Tiny Core Extensions > TCE Q&A Forum
how do firmware extensions work without startup script?
Rich:
Hi GNUser
--- Quote from: GNUser on September 06, 2024, 09:32:44 AM --- ...
--- 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 ---
--- End quote ---
Excellent. When I have a chance later tonight or tomorrow, I will
add MAC address as another choice. That will guarantee a way
to distinguish between multiple devices with identical VID:PID
identifiers.
GNUser:
Note that when I first tried this command, I got no output. I had copied and pasted the MAC address that ifconfig outputted, which uses capital letters. It seems the address= option to udevadm requires letters in the MAC address to be lowercase.
Rich:
Hi GNUser
Thanks for the heads up, but I'm afraid I already dealt
with that. If you look at where VIDPID gets processed
in ParseCommand() , you'll find:
--- Code: ---# Covert uppercase characters to lowercase.
VIDPID="$(echo "$ITEM" | busybox tr '[A-Z]' '[a-z]')"
--- End code ---
In fact, it's even mentioned in the usage message:
--- Quote ---/home/tc/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:
/home/tc/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 quote ---
I planned on giving the MAC address the same treatment.
Now that you got me thinking about it, I'm going to make
a ToLower() function since I'm using it twice. :)
Rich:
Hi GNUser
Version 0.2 is ready for testing:
--- 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.
#
# Special thanks to GNUser for his patience and help in testing and debugging.
#
# ------------------------------- Change Log -------------------------------- #
# Version 0.1 Sep 5,2024
# First working release.
#
# Version 0.2 Sep 6,2024
# In addition to /dev/device Or VID:PID, A third choice of MAC address is now
# available.
# Upper to lower case conversion was turned into function ToLower().
#
# ----------------------------- End Change Log ------------------------------ #
# *************************************************************************** #
#
# 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.2"
# 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=""
# Set if user passes in a MAC address.
MACADDR=""
# 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()
{
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
# Skip if MACADDR already defined.
[ -n "$MACADDR" ] && 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
# Skip if MACADDR already defined.
[ -n "$MACADDR" ] && continue
# Covert uppercase characters to lowercase.
VIDPID="$(ToLower "$ITEM")"
# 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"
;;
[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]:[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
# Skip if MACADDR already defined.
[ -n "$MACADDR" ] && continue
# Covert uppercase characters to lowercase.
MACADDR="$(ToLower "$ITEM")"
"$Debug" "MACADDR=$MACADDR"
# The results are saved along with string lengths for sorting later.
for DEVPATH in $(udevadm trigger -v -n -t devices -a address="$MACADDR")
do
TMPLIST=$TMPLIST$(printf "%04d %s\n" ${#DEVPATH} "$DEVPATH")$NL
done
"$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
}
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
ToLower()
{
# Converts any uppercase characters in a string to lowercase.
# Usage:
# Dest="$(ToLower Src)"
echo "$(echo "$1" | tr '[A-Z]' '[a-z]')"
}
# --------------------------------------------------------------------------- #
# --------------------------------------------------------------------------- #
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 OR MAC address.
The device will only be reset if the -r switch is included.
Usage:
${0##*/} /dev/device | VID:PID | XX:XX:XX:XX:XX:XX [ -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.
XX:XX:XX:XX:XX:XX Six 2 digit numbers separated by colons
that make up the MAC address of a network
interface device. Since these numbers 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 ---
MAC address has been added as choice for specifying a device.
The help message has been updated to reflect that addition.
While the script found my network device from the (uppercase) MAC
address, it's not USB based so it quits after identifying DEVPATH :
--- Code: ---tc@E310:~/ReplaceMe$ ~/Scripting/USB_Reset/USBreset.sh -d 00:13:20:C4:4A:20
MACADDR=00:13:20:c4:4a:20
TMPLIST=0058 /sys/devices/pci0000:00/0000:00:1e.0/0000:03:08.0/net/eth0
DEVPATH=/sys/devices/pci0000:00/0000:00:1e.0/0000:03:08.0/net/eth0
Not a USB device
tc@E310:~/ReplaceMe$
--- End code ---
Tag, you're it. ;D
GNUser:
Hi Rich. I wanted to get back to you sooner, but sometimes real life interferes with my linux addiction ;D
Version 0.2 does exactly what it says on the tin. At this point I can't think of any way of making this script better.
You remain a distinguished member of the wizards' guild.
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version