^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) #! /bin/sh
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) # SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) # Copyright (c) 2020, Google LLC. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) # Author: Saravana Kannan <saravanak@google.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) function help() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) cat << EOF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) Usage: $(basename $0) [-c|-d|-m|-f] [filter options] <list of devices>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) This script needs to be run on the target device once it has booted to a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) shell.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) The script takes as input a list of one or more device directories under
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /sys/devices and then lists the probe dependency chain (suppliers and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) parents) of these devices. It does a breadth first search of the dependency
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) chain, so the last entry in the output is close to the root of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) dependency chain.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) By default it lists the full path to the devices under /sys/devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) It also takes an optional modifier flag as the first parameter to change
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) what information is listed in the output. If the requested information is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) not available, the device name is printed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) -c lists the compatible string of the dependencies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) -d lists the driver name of the dependencies that have probed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) -m lists the module name of the dependencies that have a module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) -f list the firmware node path of the dependencies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) -g list the dependencies as edges and nodes for graphviz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) -t list the dependencies as edges for tsort
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) The filter options provide a way to filter out some dependencies:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) --allow-no-driver By default dependencies that don't have a driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) attached are ignored. This is to avoid following
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) device links to "class" devices that are created
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) when the consumer probes (as in, not a probe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) dependency). If you want to follow these links
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) anyway, use this flag.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) --exclude-devlinks Don't follow device links when tracking probe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) dependencies.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) --exclude-parents Don't follow parent devices when tracking probe
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) dependencies.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) EOF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) function dev_to_detail() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) local i=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) while [ $i -lt ${#OUT_LIST[@]} ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) local C=${OUT_LIST[i]}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) local S=${OUT_LIST[i+1]}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) local D="'$(detail_chosen $C $S)'"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if [ ! -z "$D" ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) # This weirdness is needed to work with toybox when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) # using the -t option.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) printf '%05u\t%s\n' ${i} "$D" | tr -d \'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) i=$((i+2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) function already_seen() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) local i=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) while [ $i -lt ${#OUT_LIST[@]} ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if [ "$1" = "${OUT_LIST[$i]}" ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) # if-statement treats 0 (no-error) as true
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) i=$(($i+2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) # if-statement treats 1 (error) as false
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) # Return 0 (no-error/true) if parent was added
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) function add_parent() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) if [ ${ALLOW_PARENTS} -eq 0 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) local CON=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) # $CON could be a symlink path. So, we need to find the real path and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) # then go up one level to find the real parent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) local PARENT=$(realpath $CON/..)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) while [ ! -e ${PARENT}/driver ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if [ "$PARENT" = "/sys/devices" ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) return 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) PARENT=$(realpath $PARENT/..)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) CONSUMERS+=($PARENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) OUT_LIST+=(${CON} ${PARENT})
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) # Return 0 (no-error/true) if one or more suppliers were added
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) function add_suppliers() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) local CON=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) local RET=1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) if [ ${ALLOW_DEVLINKS} -eq 0 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) return 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) SUPPLIER_LINKS=$(ls -1d $CON/supplier:* 2>/dev/null)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) for SL in $SUPPLIER_LINKS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) SYNC_STATE=$(cat $SL/sync_state_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) # sync_state_only links are proxy dependencies.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) # They can also have cycles. So, don't follow them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if [ "$SYNC_STATE" != '0' ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) SUPPLIER=$(realpath $SL/supplier)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if [ ! -e $SUPPLIER/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) CONSUMERS+=($SUPPLIER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) OUT_LIST+=(${CON} ${SUPPLIER})
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) RET=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) return $RET
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) function detail_compat() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) f=$1/of_node/compatible
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if [ -e $f ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) echo -n $(cat $f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) echo -n $1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) function detail_module() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) f=$1/driver/module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if [ -e $f ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) echo -n $(basename $(realpath $f))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) echo -n $1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) function detail_driver() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) f=$1/driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if [ -e $f ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) echo -n $(basename $(realpath $f))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) echo -n $1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) function detail_fwnode() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) f=$1/firmware_node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if [ ! -e $f ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) f=$1/of_node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if [ -e $f ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) echo -n $(realpath $f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) echo -n $1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) function detail_graphviz() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if [ "$2" != "ROOT" ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) echo -n "\"$(basename $2)\"->\"$(basename $1)\""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) echo -n "\"$(basename $1)\""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) function detail_tsort() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) echo -n "\"$2\" \"$1\""
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) function detail_device() { echo -n $1; }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) alias detail=detail_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) ALLOW_NO_DRIVER=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) ALLOW_DEVLINKS=1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) ALLOW_PARENTS=1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) while [ $# -gt 0 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) ARG=$1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) case $ARG in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) --help)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) help
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) exit 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) -c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) alias detail=detail_compat
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) -m)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) alias detail=detail_module
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) -d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) alias detail=detail_driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) -f)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) alias detail=detail_fwnode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) -g)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) alias detail=detail_graphviz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) -t)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) alias detail=detail_tsort
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) --allow-no-driver)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) ALLOW_NO_DRIVER=1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) --exclude-devlinks)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) ALLOW_DEVLINKS=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) --exclude-parents)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) ALLOW_PARENTS=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) # Stop at the first argument that's not an option.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) break
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) ;;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) esac
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) shift
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) function detail_chosen() {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) detail $1 $2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if [ $# -eq 0 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) help
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) exit 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) CONSUMERS=($@)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) OUT_LIST=()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) # Do a breadth first, non-recursive tracking of suppliers. The parent is also
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) # considered a "supplier" as a device can't probe without its parent.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) i=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) while [ $i -lt ${#CONSUMERS[@]} ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) do
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) CONSUMER=$(realpath ${CONSUMERS[$i]})
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) i=$(($i+1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if already_seen ${CONSUMER}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) # If this is not a device with a driver, we don't care about its
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) # suppliers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if [ ! -e ${CONSUMER}/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) continue
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) ROOT=1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) # Add suppliers to CONSUMERS list and output the consumer details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) #
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) # We don't need to worry about a cycle in the dependency chain causing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) # infinite loops. That's because the kernel doesn't allow cycles in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) # device links unless it's a sync_state_only device link. And we ignore
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) # sync_state_only device links inside add_suppliers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) if add_suppliers ${CONSUMER}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) ROOT=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if add_parent ${CONSUMER}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) ROOT=0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) if [ $ROOT -eq 1 ]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) then
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) OUT_LIST+=(${CONSUMER} "ROOT")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) fi
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) done
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) # Can NOT combine sort and uniq using sort -suk2 because stable sort in toybox
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) # isn't really stable.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) dev_to_detail | sort -k2 -k1 | uniq -f 1 | sort | cut -f2-
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) exit 0