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