0001
0002
0003
0004
0005
0006 function help() {
0007 cat << EOF
0008 Usage: $(basename $0) [-c|-d|-m|-f] [filter options] <list of devices>
0009
0010 This script needs to be run on the target device once it has booted to a
0011 shell.
0012
0013 The script takes as input a list of one or more device directories under
0014 /sys/devices and then lists the probe dependency chain (suppliers and
0015 parents) of these devices. It does a breadth first search of the dependency
0016 chain, so the last entry in the output is close to the root of the
0017 dependency chain.
0018
0019 By default it lists the full path to the devices under /sys/devices.
0020
0021 It also takes an optional modifier flag as the first parameter to change
0022 what information is listed in the output. If the requested information is
0023 not available, the device name is printed.
0024
0025 -c lists the compatible string of the dependencies
0026 -d lists the driver name of the dependencies that have probed
0027 -m lists the module name of the dependencies that have a module
0028 -f list the firmware node path of the dependencies
0029 -g list the dependencies as edges and nodes for graphviz
0030 -t list the dependencies as edges for tsort
0031
0032 The filter options provide a way to filter out some dependencies:
0033 --allow-no-driver By default dependencies that don't have a driver
0034 attached are ignored. This is to avoid following
0035 device links to "class" devices that are created
0036 when the consumer probes (as in, not a probe
0037 dependency). If you want to follow these links
0038 anyway, use this flag.
0039
0040 --exclude-devlinks Don't follow device links when tracking probe
0041 dependencies.
0042
0043 --exclude-parents Don't follow parent devices when tracking probe
0044 dependencies.
0045
0046 EOF
0047 }
0048
0049 function dev_to_detail() {
0050 local i=0
0051 while [ $i -lt ${#OUT_LIST[@]} ]
0052 do
0053 local C=${OUT_LIST[i]}
0054 local S=${OUT_LIST[i+1]}
0055 local D="'$(detail_chosen $C $S)'"
0056 if [ ! -z "$D" ]
0057 then
0058 # This weirdness is needed to work with toybox when
0059 # using the -t option.
0060 printf '%05u\t%s\n' ${i} "$D" | tr -d \'
0061 fi
0062 i=$((i+2))
0063 done
0064 }
0065
0066 function already_seen() {
0067 local i=0
0068 while [ $i -lt ${#OUT_LIST[@]} ]
0069 do
0070 if [ "$1" = "${OUT_LIST[$i]}" ]
0071 then
0072 # if-statement treats 0 (no-error) as true
0073 return 0
0074 fi
0075 i=$(($i+2))
0076 done
0077
0078 # if-statement treats 1 (error) as false
0079 return 1
0080 }
0081
0082 # Return 0 (no-error/true) if parent was added
0083 function add_parent() {
0084
0085 if [ ${ALLOW_PARENTS} -eq 0 ]
0086 then
0087 return 1
0088 fi
0089
0090 local CON=$1
0091 # $CON could be a symlink path. So, we need to find the real path and
0092 # then go up one level to find the real parent.
0093 local PARENT=$(realpath $CON/..)
0094
0095 while [ ! -e ${PARENT}/driver ]
0096 do
0097 if [ "$PARENT" = "/sys/devices" ]
0098 then
0099 return 1
0100 fi
0101 PARENT=$(realpath $PARENT/..)
0102 done
0103
0104 CONSUMERS+=($PARENT)
0105 OUT_LIST+=(${CON} ${PARENT})
0106 return 0
0107 }
0108
0109 # Return 0 (no-error/true) if one or more suppliers were added
0110 function add_suppliers() {
0111 local CON=$1
0112 local RET=1
0113
0114 if [ ${ALLOW_DEVLINKS} -eq 0 ]
0115 then
0116 return 1
0117 fi
0118
0119 SUPPLIER_LINKS=$(ls -1d $CON/supplier:* 2>/dev/null)
0120 for SL in $SUPPLIER_LINKS;
0121 do
0122 SYNC_STATE=$(cat $SL/sync_state_only)
0123
0124 # sync_state_only links are proxy dependencies.
0125 # They can also have cycles. So, don't follow them.
0126 if [ "$SYNC_STATE" != '0' ]
0127 then
0128 continue
0129 fi
0130
0131 SUPPLIER=$(realpath $SL/supplier)
0132
0133 if [ ! -e $SUPPLIER/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
0134 then
0135 continue
0136 fi
0137
0138 CONSUMERS+=($SUPPLIER)
0139 OUT_LIST+=(${CON} ${SUPPLIER})
0140 RET=0
0141 done
0142
0143 return $RET
0144 }
0145
0146 function detail_compat() {
0147 f=$1/of_node/compatible
0148 if [ -e $f ]
0149 then
0150 echo -n $(cat $f)
0151 else
0152 echo -n $1
0153 fi
0154 }
0155
0156 function detail_module() {
0157 f=$1/driver/module
0158 if [ -e $f ]
0159 then
0160 echo -n $(basename $(realpath $f))
0161 else
0162 echo -n $1
0163 fi
0164 }
0165
0166 function detail_driver() {
0167 f=$1/driver
0168 if [ -e $f ]
0169 then
0170 echo -n $(basename $(realpath $f))
0171 else
0172 echo -n $1
0173 fi
0174 }
0175
0176 function detail_fwnode() {
0177 f=$1/firmware_node
0178 if [ ! -e $f ]
0179 then
0180 f=$1/of_node
0181 fi
0182
0183 if [ -e $f ]
0184 then
0185 echo -n $(realpath $f)
0186 else
0187 echo -n $1
0188 fi
0189 }
0190
0191 function detail_graphviz() {
0192 if [ "$2" != "ROOT" ]
0193 then
0194 echo -n "\"$(basename $2)\"->\"$(basename $1)\""
0195 else
0196 echo -n "\"$(basename $1)\""
0197 fi
0198 }
0199
0200 function detail_tsort() {
0201 echo -n "\"$2\" \"$1\""
0202 }
0203
0204 function detail_device() { echo -n $1; }
0205
0206 alias detail=detail_device
0207 ALLOW_NO_DRIVER=0
0208 ALLOW_DEVLINKS=1
0209 ALLOW_PARENTS=1
0210
0211 while [ $
0212 do
0213 ARG=$1
0214 case $ARG in
0215 --help)
0216 help
0217 exit 0
0218 ;;
0219 -c)
0220 alias detail=detail_compat
0221 ;;
0222 -m)
0223 alias detail=detail_module
0224 ;;
0225 -d)
0226 alias detail=detail_driver
0227 ;;
0228 -f)
0229 alias detail=detail_fwnode
0230 ;;
0231 -g)
0232 alias detail=detail_graphviz
0233 ;;
0234 -t)
0235 alias detail=detail_tsort
0236 ;;
0237 --allow-no-driver)
0238 ALLOW_NO_DRIVER=1
0239 ;;
0240 --exclude-devlinks)
0241 ALLOW_DEVLINKS=0
0242 ;;
0243 --exclude-parents)
0244 ALLOW_PARENTS=0
0245 ;;
0246 *)
0247
0248 break
0249 ;;
0250 esac
0251 shift
0252 done
0253
0254 function detail_chosen() {
0255 detail $1 $2
0256 }
0257
0258 if [ $
0259 then
0260 help
0261 exit 1
0262 fi
0263
0264 CONSUMERS=($@)
0265 OUT_LIST=()
0266
0267
0268
0269 i=0
0270 while [ $i -lt ${
0271 do
0272 CONSUMER=$(realpath ${CONSUMERS[$i]})
0273 i=$(($i+1))
0274
0275 if already_seen ${CONSUMER}
0276 then
0277 continue
0278 fi
0279
0280
0281
0282 if [ ! -e ${CONSUMER}/driver -a ${ALLOW_NO_DRIVER} -eq 0 ]
0283 then
0284 continue
0285 fi
0286
0287 ROOT=1
0288
0289
0290
0291
0292
0293
0294
0295 if add_suppliers ${CONSUMER}
0296 then
0297 ROOT=0
0298 fi
0299
0300 if add_parent ${CONSUMER}
0301 then
0302 ROOT=0
0303 fi
0304
0305 if [ $ROOT -eq 1 ]
0306 then
0307 OUT_LIST+=(${CONSUMER} "ROOT")
0308 fi
0309 done
0310
0311
0312
0313 dev_to_detail | sort -k2 -k1 | uniq -f 1 | sort | cut -f2-
0314
0315 exit 0