Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to disconnect a specific USB device using musb_hdrc Linux driver?

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.

like image 998
Fryz Avatar asked Jul 11 '17 12:07

Fryz


People also ask

How do I remove a device from my USB port?

Windows: Open the My Computer, Computer, This PC, or Windows Explorer utility. Then right-click the name of your USB device (listed as a removable disk) and select Eject. Mac: Drag the removable disk icon for your USB device from the desktop into the trash.

How do I access USB devices on Linux?

Double-click the folder on your desktop that says Username's Home, where Username is your username. Then in the field next to Location, type /mnt/usb , or the appropriate directory you want to access.


1 Answers

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

UPDATE

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.

like image 95
Ezequiel Garcia Avatar answered Oct 21 '22 08:10

Ezequiel Garcia