USB Core & friends

It’s been a while since I’ve last written something and I thought it’s about time I did this again. ๐Ÿ™‚

The reason I haven’t been writing recently is that I’ve been progressing very slowly. I managed to have a non-trivial patch accepted (yey!) that adds functionality for an option that was left out of USB/IP on the last major refactoring.

The second patch I’ve been working on is converting the usbip-host driver from an interface driver to a device driver. To put things into context, USB/IP architecture looks pretty much like this:

The driver in question is Stub Driver in the image. As it can be seen, the USB architecture is a layered one, going from the host controller driver (HCD), to USB Core driver and, finally, interface drivers (PDD – Per Device Driver).

At this point it is worth mentioning how a USB device is organized. Each USB device comes with some configurations (that specify the power and bandwidth requirments). Only one configuration can be active at a given time, and the USB Core driver decides which one to use when the device is plugged in.

Within each configuration there are multiple interfaces. For example, in the case of USB speakers, you may have one interface that deals with the audio data and another one that manages the buttons. And within each interface there are multiple endpoints. You can think of endpoint as sinks – it can receive or transmit data. When you write something to your USB mass storage device, you are actually sending data to an endpoint. Endpoint can be used for data transfer or control purposes. There is a special endpoint, endpoint 0, which is not part of any interface and it is used for device management.

The stub driver only managed an interface. Since USB/IP exports a whole device, and not only an interface, it would make sense that this driver be a device driver. So, the driver moves a layer down the hierarchy.ย And this is where things get tricky.

I began by implementing the callbacks required by struct usb_device_driver – nothing special here. However, binding my device to this new driver took me a bit to get working. Why? dmesg was silent, there were no errors thrown but the device still won’t bind to it.

Long story short, after quite a bit of googling and studying of the way devices and drivers interact, I found out that every USB device was bound at the core level to a driver called, inspiredly, usb. Unbinding the device from this one and binding to the stub fixed things.

After this adventure I have managed to successfully bind the device at core level and make it visible from the other host, ready for export.

In an ideal case, the patch would be ready to submit. Only that when I actually try attaching the device from another host, I get a cute stack trace on the server side. It seems that it receives a weird endpoint from the client. I am still working on tracking down the bug; perhaps the HCD should be modified as well.

And now, back to reading the USB spec and debugging. ๐Ÿ™‚