Reputation: 2211
First, i am new to the Linux USB stack and i am trying to understand it a little bit more in order to achieve the following result : i need to reconnect/disconnect a specific USB device because sometimes, tough not often, this device does not respond anymore and the only solution is to physically disconnect/reconnect the USB cable from the device.
On my board (AM33x Sitara), there are 2 usb controllers with musb-hdrc drivers bind to them :
# pwd /sys/bus/platform/drivers/musb-hdrc
# ls -lrth
total 0
--w------- 1 root root 4.0K Jul 11 10:11 uevent
--w------- 1 root root 4.0K Jul 11 10:13 unbind
lrwxrwxrwx 1 root root 0 Jul 11 10:13 musb-hdrc.1.auto -> ../../../../devices/ocp.2/47400000.usb/47401c00.usb/musb-hdrc.1.auto
lrwxrwxrwx 1 root root 0 Jul 11 10:13 musb-hdrc.0.auto -> ../../../../devices/ocp.2/47400000.usb/47401400.usb/musb-hdrc.0.auto
lrwxrwxrwx 1 root root 0 Jul 11 10:13 module -> ../../../../module/musb_hdrc
--w------- 1 root root 4.0K Jul 11 10:13 bind
From dmesg, i can see that my device is using driver musb-hdrc :
usb 2-1.4: new full-speed USB device number 17 using musb-hdrc
But looking at the device node, i cannot find this driver :
# ls -lrth /sys/bus/usb/devices/2-1.4:1.0/
total 0
-rw-r--r-- 1 root root 4.0K Jul 11 12:03 uevent
-r--r--r-- 1 root root 4.0K Jul 11 12:05 supports_autosuspend
lrwxrwxrwx 1 root root 0 Jul 11 12:05 subsystem -> ../../../../../../../../../bus/usb
drwxr-xr-x 2 root root 0 Jul 11 12:05 power
...
...
-r--r--r-- 1 root root 4.0K Jul 11 12:05 bAlternateSetting
lrwxrwxrwx 1 root root 0 Jul 11 12:07 driver -> ../../../../../../../../../bus/usb/drivers/usbfs
According to https://www.kernel.org/doc/Documentation/usb/power-management.txt, it is possible to suspend usb devices by doing :
echo "auto" > /sys/bus/usb/devices/2-1.4/power/control
and echo 0 > /sys/bus/usb/devices/2-1.4/power/autosuspend_delay_ms
, plus unbinding the driver with echo "2-1.4:1.0" > /sys/bus/usb/devices/2-1.4:1.0/driver/unbind
I can see in dmesg that the device is disconnected, but for some reason the device is automatically bind just after that.
However, when i do the same procedure using musb-hdrc driver on musb-hdrc.1.auto and musb-hdrc.0.auto devices, it works well except that all my usb devices are turned off/on...and i would like to be more specific about the 2-1.4:1.0 usb devices interface.
An idea is to use the musb-hdrc driver to unbind the 2-1.4:1.0 usb device interface but it says that there is no such device...
I am a bit confused about that because i can see that the device is inside the device tree of musb-hdrc.1.auto :
# ls -lrth /sys/devices/ocp.2/47400000.usb/47401c00.usb/musb-hdrc.1.auto/usb2/2-1/2-1.4/
total 0
-rw-r--r-- 1 root root 4.0K Jul 11 12:03 uevent
-r--r--r-- 1 root root 4.0K Jul 11 12:03 speed
...
...
drwxr-xr-x 6 root root 0 Jul 11 12:03 2-1.4:1.0
...
Why the unbind command say that the device does not exist then ? Maybe there is a way to indicate, a kind of path inside the device tree to indicate to the driver that i want to unbind to this specific device interface 2-1.4:1.0 ?
Thanks for your help.
Upvotes: 7
Views: 12452
Reputation: 1057
Hm, intriguing question :-)
First of all, keep in mind that there is a difference between a (logical) Device and a Device Driver. When a hardware device is physically connected, Linux creates a (logical) device instance and then tries to bind the device to a matching device driver instance.
Therefore, binding and unbinding is one process, while disconnecting (or removing) the logical device is another process. These two are different and I'm not too sure which would solve your problem.
Sometimes, when you need to reset a buggy driver, you can get away with an unbind/bind cycle. However, if the hardware is nuts maybe this won't work.
Unbinding and re-binding is fairly easy. You need to first find the driver your device is binded to, and then use the unbind
and bind
interfaces. Let me show you this using my USB headset.
# dmesg
[ 2073.908792] usb 2-1.2: new full-speed USB device number 8 using ehci-pci
# lsusb -t
/: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M
|__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/6p, 480M
|__ Port 2: Dev 10, If 0, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 10, If 1, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 10, If 2, Class=Audio, Driver=snd-usb-audio, 12M
|__ Port 2: Dev 10, If 3, Class=Human Interface Device, Driver=usbhid, 12M
So my USB headset is usb 2-1.2
. It says it's using ehci-pci driver, but the device will be binded to a hub instead. You can find it:
# find /sys/bus/usb -name "2-1.2"
/sys/bus/usb/devices/2-1.2
/sys/bus/usb/drivers/usb/2-1.2
See above, the name of the driver is usb
. Or you can just follow the driver link:
# cd /sys/bus/usb/devices/2-1.2/driver
# ls -la
lrwxrwxrwx 1 root root 0 Jul 12 12:03 2-1.2 -> ../../../../devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2
--w------- 1 root root 4096 Jul 12 11:57 bind
--w------- 1 root root 4096 Jul 12 11:57 unbind
Now, we can cycle it:
# echo 2-1.2 > unbind
# echo 2-1.2 > bind
So far, we've talked about the device driver <-> device
binding. Now, producing a disconnect and then re-connecting the device is apparently harder. You can remove it:
# echo 1 > /sys/bus/usb/devices/2-1.2/remove
But I could not find how to insert it again!
After some research, I found a USBDEVFS_RESET ioctl, but there is a warning that suggests to avoid it. In any case, other people have found it useful. The post mentions the authorized interface as a way to re-configure the device, through an auth cycle:
# echo 0 > /sys/bus/usb/devices/2-1.2/authorized
# echo 1 > /sys/bus/usb/devices/2-1.2/authorized
Connecting my cellphone to a USB port, I can see that neither the unbinding nor the de-auth manages to turn VBUS off. The remove
certainly does it, but then you can't insert it back.
Given the USB is idle in my particular case, changing power/control
from on
to auto
apparently turns off VBUS.
# echo auto > /sys/bus/usb/devices/2-1.2/power/control
Maybe you can play with the power interface?
If this doesn't work for you, the alternative is to get down to the musb driver and hack your way adding your own kludge. This kind of trick is not unusual either.
Upvotes: 6