I'm trying to reconnect a usb device once after system boots. I need it for some glitch in my Creative Sound Blaster X4 usb sound card Linux drivers, when under some conditions the mic doesn't work after boot. I wasn't able to find the reason for this bug, but I discovered that if I reconnect it physically, mic works fine. I also am now able to do that with a script, based on hub-ctrl:
#!/bin/bash
ID=$1
ID_REGEXP='[0-9a-f]{4}:[0-9a-f]{4}'
ROOT_HUB_REGEXP="^Bus [0-9]{3} Device [0-9]{3}: ID $ID_REGEXP Linux Foundation [0-9]+\.[0-9]+ root hub"
if ! echo "$ID" | grep -Exq "$ID_REGEXP"; then
echo "Usage $0 ID" >&2
exit 1
fi
VENDOR_ID=`echo $ID | cut -d: -f1`
PRODUCT_ID=`echo $ID | cut -d: -f2`
PRODUCT="`echo $VENDOR_ID | sed 's/^0*//'`/`echo $PRODUCT_ID | sed 's/^0*//'`"
DEVICES="`lsusb`"
args=""
BUSES=`echo "$DEVICES" | grep -E "Bus [0-9]{3} Device [0-9]{3}: ID $ID" | cut -d' ' -f2 | sort -u`
for bus in $BUSES; do
hub_device=`echo "$DEVICES" | grep -E "^Bus $bus Device [0-9]{3}: ID" | grep -E "$ROOT_HUB_REGEXP" | cut -d' ' -f4 | sed -e 's/^0*//' -e 's/:$//'`
bus_consice=`echo $bus | sed 's/^0*//'`
for dev in `ls /sys/bus/usb/devices/usb${bus_consice}/${bus_consice}-*/dev | sed 's~/dev$~~'`; do
if grep -Eq "^PRODUCT=${PRODUCT}/" ${dev}/uevent; then
port=`echo $dev | sed "s|^.*/${bus_consice}-\(.*\)\$|\1|"`
args="$args ${bus_consice},${hub_device},${port}"
fi
done
done
for arg in $args; do
read bus_consice hub_device port < <(echo $arg | sed 's/,/ /g')
sudo hub-ctrl -B $bus_consice -D $hub_device -P $port -p 0
done
sleep 0.1
for arg in $args; do
read bus_consice hub_device port < <(echo $arg | sed 's/,/ /g')
sudo hub-ctrl -B $bus_consice -D $hub_device -P $port -p 1
done
And now I want it to be executed once when device is connected. I can't do this too early, since the sound card is connected to a thunderbolt 3 hub, otherwise a systemd oneshot service would be perfect. So I thought that a udev rule would do the trick: to run script when the device is connected. The problem is that this falls into endless reconnect cycle, if I add an ACTION=="add" rule.
I tried using an environment variable as a state variable, but looks like it doesn't work the way I hoped it would:
ATTR{idVendor}=="041e", ATTR{idProduct}=="3278", ACTION=="add", ENV{DEV_041e_3278_RELOADED}!="1, RUN+="/.../restart_by_id.sh '041e:3278'", ENV{DEV_041e_3278_RELOADED}="1"
It still goes into the endless reconnect cycle. What am I doing wrong? Or maybe it is better to achieve this without udev? I know I could create a temporary file on a ram disk to indicate that the script has been run, but it would be great to find a more elegant solution
Thank you!