Kernel – How to Assign USB Driver to Device

driverskernelkernel-modulesudevusb

This question is two-fold:

First, how do you manually detach a driver from a USB device and attach a different one? For example, I have a device that when connected automatically uses the usb-storage driver.

usbview output

Vendor Id: xxxx
Product Id: xxxx
...
    Number of Interfaces: 2
    Interface Number: 0
        Name: usb-storage
        Number of Endpoints: 2
        ...
    Interface Number: 1
        Name: (none)
        Number of Endpoints: 2
        ...

I do not want to use the usb-storage driver, so in my application I use the libusb library to detach the usb-storage driver and then I claim the interface. I then can send data to and from the applications running on my USB device and on my host Linux system.

How do you detach a driver manually outside of an application?


Second, how do I automatically assign the driver to attach on device plugin? I currently have a udev rule setup to set the device permissions automatically:

SUBSYSTEM=="usb", ATTR{idVendor}=="xxxx", MODE="0666"

Can I use udev rules to assign drivers to specific interfaces on the USB device? For example, if I wanted the usbnet module to be used on automatically on interface 0 instead of usb-storage, is that possible in udev?

Best Answer

For the first part of the question, I've looked and couldn't find a better way to detach a USB driver than what you're already doing with libusb.

As for the second part of the question, udev can react to driver loading, but not force a specific driver to be assigned to a device.

Every driver in the Linux kernel is responsible for one or more devices. The driver itself chooses what devices it supports. It does this programmatically, i.e. by checking the device's vendor and product ID, or, if those aren't available (e.g. an old device), performing some auto-detection heuristics and sanity checks. Once the driver is confident it's found a device it supports, it attaches itself to it. In short, you often can't force a particular driver to use a particular device. Sometimes, however, a device driver is generous with what it accepts, and a device can work that it doesn't know about. Your mileage will vary! In the past, I've had to manually add weird PCI device/vendor IDs to drivers that should support them, with mixed success and a few amusing kernel crashes.

Now, in the case of modules, there's an extra step. The module loader is woken up by the kernel when a new device is detected. It's passed a ‘modalias’ string, which identifies the device and looks something like this for USB devices:

usb:v046DpC221d0170dc00dsc00dp00ic03isc00ip00

This string contains the device class (usb) and class-specific information (vendor/device/serial number, device class, etc). Each kernel driver contains a line such as:

MODULE_ALIAS("usb:...")

Which must match the usbalias (wildcards are used to match multiple devices). If the modalias matches one that the driver supports, this driver is loaded (or notified of the new device, if it's there already).

You can see the supported devices (by modalias) and their associated modules with

less /lib/modules/`uname -r`/modules.alias

If you grep for the usb-storage device driver, you'll see it has some specific devices it supports by vendor and device ID, and will also attempt to support any device with the right (storage) class, no matter the vendor/device.

You can influence this using userspace mechanisms on your OS (/etc/modprobe.d/ on Debian and friends). You can blacklist modules, or you can specify modules to be loaded by modalias, just like the modules.alias file (and using the same syntax). depmod -a will then regenerate the module loader's patterns.

However, even though you can lead this particular horse to water, but you can't make him drink. If the driver has no support for your device, it should ignore it.

This is the theory in the general case.

In practice, and in the case of USB, I see your device appears to have two interfaces, of which storage is one. The kernel will attach to the storage interface of the overall device. If the other interface has the right class, the usbnet driver could attach to it. Yes, you can have multiple drivers attached to the same physical device, because a USB device exports multiple interfaces (e.g. my Logitech G15 keyboard exports two because it has a keyboard device and an LCD screen, each of which is handled by a separate driver).

The fact that the second interface of your USB device isn't detected is indicative of lack of support in the kernel. Whatever the case, you can list the device interfaces/endpoints in excruciating detail using lsusb -v | less, then scroll down to your particular device (you can limit the output by device:vendor ID or USB path if you're so inclined).

Please note: I'm oversimplifying a bit here with respect to the logical structure of USB devices. Blame the USB consortium. :)

Related Question