Tiny Core Extensions > TCE Q&A Forum

how do firmware extensions work without startup script?

<< < (8/10) > >>

Rich:
Hi GNUser
OK, I'm back.

Here's the new cut:

--- Code: ---#!/bin/sh
# Script to reset a USB device written by Richard A. Rost September 4,2024
# This script attempts to replicate the behavior of unplugging/replugging
# a USB device by unbinding/binding the devices driver.


# *************************************************************************** #
#
# Default behavior for Debug and Reset can be changed here.
# -d command line switch turns on debugging messages.
Debug="test"
# Uncomment the next line to turn on debugging messages.
#Debug="echo"

# -r command line switch requests resetting the device.
Reset="No"
# Uncomment the next line to request resetting the device.
#Reset="Yes"

# *************************************************************************** #

# --------------------------------- Aliases --------------------------------- #
alias cp='busybox cp'
alias cut='busybox cut'
alias mkdir='busybox mkdir -p'
alias rm='busybox rm -rf'
alias tr='busybox tr'


# ------------------------------- End Aliases ------------------------------- #


# -------------------------------- Constants -------------------------------- #
# Current version.
VERSION="Version 0.1"
# Maximum number of command line parameters we accept.
MAXPARAMS=2
# Number of command line parameters passed in.
PARAMCOUNT=$#
# List of parameters passed in.
PARAMLIST=$@
# Needed for embedding a newline character in some commands.
NL="
"
# These are the properties we'll be searching for in WalkTheSysPath().
SEARCHTERMS="SUBSYSTEM= DRIVER="

# ------------------------------ End Constants ------------------------------ #


# -------------------------------- Variables -------------------------------- #
# Set if user passes in /dev/, such as  /dev/sdg , /dev/sdg1 , or  /dev/ttyUSB0.
DEV=""
# Set if user passes in VID:PID. VID and PID must each be 4 digits separated by
# a colon. VID and PID are hex and may contain letters. Both uppercase and
# lowercase are acceptable.
VIDPID=""
# VID and PID separated with colon removed.
VID=""
PID=""
# Variable used for temporary lists.
TMPLIST=""
# The path we traverse from end to beginning in search for its driver.
DEVPATH=""
# Working copy of DEVPATH used by WalkTheSysPath().
SEARCHPATH=""
# The text after the last slash in DEVPATH. Echoed into unbind/bind to
# identify which USB device to effect.
ENDPATH=""
# These are the properties we are scanning for. We want to find:
# [ SUBSYSTEM == "usb" ] && [ DRIVER != "" ]
SUBSYSTEM=""
DRIVER=""
# Driver directory.
BINDPATH=""
# That directory should contain the unbind and bind files.
BINDFILE=""
UNBINDFILE=""

# ------------------------------ End Variables ------------------------------ #


# -------------------------------- Functions -------------------------------- #

# --------------------------------------------------------------------------- #
ParseCommand()
{
# [ $PARAMCOUNT -gt $MAXPARAMS ] && Usage "To many parameters entered."

for ITEM in $PARAMLIST
do
case $ITEM in
-h) Usage ;;
-help) Usage ;;
--help) Usage ;;

-d) # Throw away -d to avoid  Invalid option  error. It's handled in Main.
;;

-r) # Request device reset.
Reset="Yes"
;;

"/dev/"?*)
# Skip if DEV already defined.
[ -n "$DEV" ] && continue
# Skip if VIDPID already defined.
[ -n "$VIDPID" ] && continue
DEV="$ITEM"
# The results are saved along with string lengths for sorting later.
for DEVPATH in $(udevadm trigger -v -n -t devices -p DEVNAME="$DEV")
do
TMPLIST=$TMPLIST$(printf "%04d %s\n" ${#DEVPATH} "$DEVPATH")$NL
done
"$Debug" "TMPLIST=$TMPLIST"
;;

[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])
# Skip if DEV already defined.
[ -n "$DEV" ] && continue
# Skip if VIDPID already defined.
[ -n "$VIDPID" ] && continue
# Covert uppercase characters to lowercase.
VIDPID="$(echo "$ITEM" | busybox tr '[A-Z]' '[a-z]')"
# Separate VID from PID and remove colon.
VID="$(echo "$VIDPID" | cut -c 1-4)"
PID="$(echo "$VIDPID" | cut -c 6-9)"
"$Debug" "VID=$VID    PID=$PID"

# This won't work because it searches for "ID_VENDOR_ID=0644 OR ID_MODEL_ID=0200"
# udevadm trigger -v -n -t devices -p ID_VENDOR_ID=0644 -p ID_MODEL_ID=0200
udevadm trigger -v -n -t devices -p ID_VENDOR_ID="$VID" | sort > VIDs.txt
udevadm trigger -v -n -t devices -p ID_MODEL_ID="$PID" | sort > PIDs.txt

# Since we had to search for VID and PID separately, we check which
# results are common to both lists for an exact match. The results
# are saved along with string lengths for sorting later.
for DEVPATH in $(comm -12 VIDs.txt PIDs.txt)
do
TMPLIST=$TMPLIST$(printf "%04d %s\n" ${#DEVPATH} "$DEVPATH")$NL
done

# Clean up the files we created.
rm VIDs.txt PIDs.txt

"$Debug" "TMPLIST=$TMPLIST"
;;

*)
echo "Invalid option."
exit 1
;;

esac
done

}
# --------------------------------------------------------------------------- #


# --------------------------------------------------------------------------- #
ParseList()
{
# Parse list of DEVPATHs returned by udevadm and save the longest line.

# Sort our list, longest lines first, remove string length, and
# save the first entry (longest string).
DEVPATH="$(echo "$TMPLIST" | sort -r | cut -c 6- | head -n 1)"
"$Debug" "DEVPATH=$DEVPATH"
TMPLIST=""

# Make sure we got result.
[ -z "$DEVPATH" ] && echo "No DEVPATH found" && exit 1
# Make sure it's USB device.
[ ! $(echo "$DEVPATH" | grep -E '/usb[0-9]') ] && echo "Not a USB device" && exit 1

}
# --------------------------------------------------------------------------- #


# --------------------------------------------------------------------------- #
SetupBindPaths()
{
# Find the drivers directory.
BINDPATH="$(find /sys/bus/usb/drivers/ -type d -name "$DRIVER")"
[ -z "$BINDPATH" ] && echo "No BINDPATH found" && exit 1
# That directory should contain the unbind and bind files.
BINDFILE="$BINDPATH""/bind"
UNBINDFILE="$BINDPATH""/unbind"
"$Debug" "BINDPATH=$BINDPATH"
"$Debug" "BINDFILE=$BINDFILE"
"$Debug" "UNBINDFILE=$UNBINDFILE"

# Make sure BINDPATH contains correct ENDPATH link.
[ "$(realpath "$BINDPATH/$ENDPATH")" != "$SEARCHPATH" ] && echo "Bad BINDPATH" && exit 1

}
# --------------------------------------------------------------------------- #


# --------------------------------------------------------------------------- #
Usage()
{
[ "$1" != "" ] && echo "$1" && echo

echo "
$0 $VERSION

This script attempts to reset a USB device without an unplug/replug
sequence using a supplied  /dev/device  OR  VID:PID. The device will
only be reset if the  -r  switch is included.

Usage:
$0 /dev/device | VID:PID [ -d -r ]

/dev/device Must point to a connected USB device.

VID:PID Two 4 digit IDs separated by a colon.
Since IDs are hex, they may contain
letters. Upper and/or lower case are OK.

-d Turn on debugging messages.

-r Request device reset.

Command line switches must be given separately, ie -d -r, not -dr.

"

exit
}
# --------------------------------------------------------------------------- #


# --------------------------------------------------------------------------- #
WalkTheSysPath()
{
# This walks up the DEVPATH by shortening it one entry at a time in an
# effort to located its driver.

"$Debug" "$NL""WalkTheSysPath(): Searching for SUBSYSTEM and DRIVER."

# SEARCHPATH is our working copy of DEVPATH.
SEARCHPATH="$DEVPATH"
# Copy the text after the last slash in SEARCHPATH.
ENDPATH="${SEARCHPATH##*/}"

# When ENDPATH begins with  usbN*  where N is a digit, we've hit the USB border.
while [ ! $(echo "$ENDPATH" | grep -E '^usb[0-9]') ]
do
"$Debug" "$NL""SEARCHPATH=$SEARCHPATH"
INFO="$(udevadm info -q property -p "$SEARCHPATH" 2> /dev/null)"
for ST in $SEARCHTERMS
do
# Search for our search term (i.e. SUBSYSTEM=).
T="$(echo "$INFO" | grep -E "^$ST")"
# Remove our search term (i.e. SUBSYSTEM=) from the result.
T="${T/$ST/}"
case $ST in
"SUBSYSTEM=")
# If the result matched our search term, save it.
SUBSYSTEM="$T"
"$Debug" "$ST$T"
;;

"DRIVER=")
DRIVER="$T"
"$Debug" "$ST$T"
;;

esac
done

if [ "$SUBSYSTEM" == "usb" ] && [ "$DRIVER" != "" ]
then
# We found what we were searching for.
"$Debug" "$NL""WalkTheSysPath(): Search complete."
"$Debug" "SEARCHPATH=$SEARCHPATH"
"$Debug" "ENDPATH=$ENDPATH    SUBSYSTEM=$SUBSYSTEM    DRIVER=$DRIVER"
return
fi

# Clear the properties for the next pass.
SUBSYSTEM=""
DRIVER=""

# Shorten the path and update ENDPATH for the next pass
SEARCHPATH="${SEARCHPATH%/*}"
ENDPATH="${SEARCHPATH##*/}"
done

"$Debug" "$NL""WalkTheSysPath(): Search failed."
}
# --------------------------------------------------------------------------- #


# ------------------------------ End Functions ------------------------------ #


# ---------------------------------- Main ----------------------------------- #
# Program starts here.

[ $PARAMCOUNT -eq 0 ] && Usage

for ITEM in $PARAMLIST
do
# We want this to happen before any debug messages are encountered.
# Turn on debugging messages if option  -d  is specified.
[ "$ITEM" == "-d" ] && Debug="echo" && break
done

ParseCommand

ParseList

WalkTheSysPath

SetupBindPaths

# See if device reset (-r) was requested.
if [ "$Reset" == "Yes" ]
then

if [ -e "$UNBINDFILE" ]
then
# Remove device.
echo "$ENDPATH" | sudo tee "$UNBINDFILE" 1> /dev/null
fi

"$Debug" "Sleep ..."
sleep 3
"$Debug" "... Wake up"


if [ -e "$BINDFILE" ]
then
# Add device back.
echo "$ENDPATH" | sudo tee "$BINDFILE" 1> /dev/null
fi

fi

exit
--- End code ---

Help is included:

--- Code: ---tc@E310:~$ ./Scripting/USB_Reset/USBreset.sh -h

./Scripting/USB_Reset/USBreset.sh Version 0.1

This script attempts to reset a USB device without an unplug/replug
sequence using a supplied  /dev/device  OR  VID:PID. The device will
only be reset if the  -r  switch is included.

Usage:
        ./Scripting/USB_Reset/USBreset.sh /dev/device | VID:PID [ -d -r ]

        /dev/device     Must point to a connected USB device.

        VID:PID         Two 4 digit IDs separated by a colon.
                        Since IDs are hex, they may contain
                        letters. Upper and/or lower case are OK.

        -d              Turn on debugging messages.

        -r              Request device reset.

Command line switches must be given separately, ie -d -r, not -dr.
--- End code ---

The default behavior is  debugging messages  and  device reset  are off.
Use -d and -r to turn them on. There are settings at the beginning of the
script if you want to have them default to on. There are no - switches to
turn them off.

This is what it looks like resetting a thumb drive with debugging messages on:

--- Code: ---tc@E310:~$ ./Scripting/USB_Reset/USBreset.sh 8644:8003 -d -r > USBtest.txt
VID=8644    PID=8003
TMPLIST=0045 /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5
0089 /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/host7/target7:0:0/7:0:0:0/block/sdg
0094 /sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/host7/target7:0:0/7:0:0:0/block/sdg/sdg1

DEVPATH=/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/host7/target7:0:0/7:0:0:0/block/sdg/sdg1

WalkTheSysPath(): Searching for SUBSYSTEM and DRIVER.

SEARCHPATH=/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/host7/target7:0:0/7:0:0:0/block/sdg/sdg1
SUBSYSTEM=block
DRIVER=

SEARCHPATH=/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/host7/target7:0:0/7:0:0:0/block/sdg
SUBSYSTEM=block
DRIVER=

SEARCHPATH=/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/host7/target7:0:0/7:0:0:0/block
SUBSYSTEM=
DRIVER=

SEARCHPATH=/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/host7/target7:0:0/7:0:0:0
SUBSYSTEM=scsi
DRIVER=sd

SEARCHPATH=/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/host7/target7:0:0
SUBSYSTEM=scsi
DRIVER=

SEARCHPATH=/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0/host7
SUBSYSTEM=scsi
DRIVER=

SEARCHPATH=/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0
SUBSYSTEM=usb
DRIVER=usb-storage

WalkTheSysPath(): Search complete.
SEARCHPATH=/sys/devices/pci0000:00/0000:00:1d.7/usb1/1-5/1-5:1.0
ENDPATH=1-5:1.0    SUBSYSTEM=usb    DRIVER=usb-storage
BINDPATH=/sys/bus/usb/drivers/usb-storage
BINDFILE=/sys/bus/usb/drivers/usb-storage/bind
UNBINDFILE=/sys/bus/usb/drivers/usb-storage/unbind
Sleep ...
... Wake up
--- End code ---
TMPLIST  shows the results udevadm returned for the VID:PID which I
prefixed with their string lengths so I could grab the longest one.

DEVPATH contains the chosen string.

WalkTheSysPath() asks udevadm for the properties of SEARCHPATH.
It's looking for a match on SUBSYSTEM == "usb" && DRIVER != ""
If it doesn't match, go up one level on SEARCHPATH and try again
This continues until a match is found, or fails if it reaches .../usb[0-9]

Once found, the bind path, bind files, and what to echo into them
are determined.

The new (and hopefully working) version is attached.

GNUser:
You're back and you mean business!

It works like a charm now:


--- Code: ---$ ifconfig -a wlan1
ifconfig: wlan1: error fetching interface information: Device not found

$ tce-load -i firmware-atheros
firmware-atheros.tcz: OK

$ ./USBReset.sh 040d:3801 -d -r
VID=040d    PID=3801
TMPLIST=0051 /sys/devices/pci0000:00/0000:00:1a.0/usb2/2-1/2-1.2

DEVPATH=/sys/devices/pci0000:00/0000:00:1a.0/usb2/2-1/2-1.2

WalkTheSysPath(): Searching for SUBSYSTEM and DRIVER.

SEARCHPATH=/sys/devices/pci0000:00/0000:00:1a.0/usb2/2-1/2-1.2
SUBSYSTEM=usb
DRIVER=

SEARCHPATH=/sys/devices/pci0000:00/0000:00:1a.0/usb2/2-1
SUBSYSTEM=usb
DRIVER=usb

WalkTheSysPath(): Search complete.
SEARCHPATH=/sys/devices/pci0000:00/0000:00:1a.0/usb2/2-1
ENDPATH=2-1    SUBSYSTEM=usb    DRIVER=usb
BINDPATH=/sys/bus/usb/drivers/usb
BINDFILE=/sys/bus/usb/drivers/usb/bind
UNBINDFILE=/sys/bus/usb/drivers/usb/unbind
Sleep ...
... Wake up

$ ifconfig -a wlan1
wlan1     Link encap:Ethernet  HWaddr 00:12:7B:20:6B:A0 
          BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

--- End code ---

Wow, you are definitely not one to settle for superficial/accidental solutions. This is impressively thorough.

I manage several machines from a distance, so I expect that over time I will find several applications for this script.

Many thanks, Rich.

Rich:
Hi GNUser

--- Quote from: GNUser on September 05, 2024, 04:22:25 PM ---You're back and you mean business! ...
--- End quote ---
Some of us are stubborn and too dumb to know when to quit. :)


--- Quote --- ... It works like a charm now: ...
--- End quote ---
How about that, sometimes being persistent does pay off.


--- Quote --- ... Wow, you are definitely not one to settle for superficial/accidental solutions. This is impressively thorough. ...
--- End quote ---
I did my best to cover all the bases. I added the option of using /dev/device for a
system with multiple USB devices with the same VID:PID on the off chance they
show up under /dev/.


--- Quote --- ... Many thanks, Rich.
--- End quote ---
You are quite welcome. Thank you for your patience. If you have
any problems or questions, let me know.

Rich:
Hi GNUser
I had another idea I'd like to investigate.

Could you please post the result of this command using your MAC address:

--- Code: ---tc@E310:~$ udevadm trigger -v -n -t devices -a address=00:13:20:c4:4a:20
/sys/devices/pci0000:00/0000:00:1e.0/0000:03:08.0/net/eth0
tc@E310:~$
--- End code ---

GNUser:

--- Quote from: Rich on September 05, 2024, 05:13:32 PM ---Some of us are stubborn and too dumb to know when to quit. :)

--- End quote ---
Ha! I know how that goes. Sometimes I just want a quick fix to get a problem out of the way. But sometimes I want to throw an atom bomb on the problem so that I never have to rehash a quick fix again.


--- Quote from: Rich on September 05, 2024, 05:29:19 PM ---Could you please post the result of this command using your MAC address:

--- End quote ---

--- Code: ---$ sudo udevadm trigger -v -n -t devices -a address=00:12:7b:20:6b:a0
/sys/devices/pci0000:00/0000:00:1a.0/usb2/2-1/2-1.2/2-1.2:1.0/net/wlan1
--- End code ---

Navigation

[0] Message Index

[#] Next page

[*] Previous page

Go to full version