After working for 2 months (whoa, 2 months already!?) at USB/IP, I can say I’ve become familiar with the way USB devices are seen be an operating system. Well, this belief was shattered today.
A problem of USB/IP at this point is that both the client and the server can use the shared device at the same time. If, for example, you share a USB mass storage device, and both involved parties mount it and read data from it, there’s shouldn’t be an issue. But what if they both decide to write to the device?
Obviously, concurrent access without any supervising entity is not desirable. In order to avoid this, the server would have to be unable to use the shared device (since the client intends to use the device in the first place).
Thanks to Sarah Sharp and Alan Stern, I found out about a mechanism called port claiming. While a port is claimed, whenever you plug in a USB device or change the configuration of an existing one, usbcore will prevent kernel drivers to bind to the device’s interfaces. No interface drivers, no usability – sounds good enough.
This mechanism is intended to be used from userspace, from various applications that want custom configurations for a device. So a ioctl() call is used, having as arguments the usbfs file corresponding to the USB hub the device will be connected at and the port. Sounds simple enough, right? Wrong. (at least for me)
After some research on how to enable this usbfs, I found out it was depracated and the files it contained were put in sysfs and /dev. What I knew was that I was looking for *some* file that would somehow correspond to a hub. sysfs didn’t help much, I couldn’t find something like that. On the other hand, in /dev/bus/usb there was a folder that contained char devices. The structure resembled the tree USB architecture. (I read the files in usbfs look like /proc/bus/usb/BBB/DDD – where BBB and DDD are numbers – and, indeed, /dev/bus/usb looked the same. however, my brain was helpful enough to make this connection a long time after)
Alan confirmed that this was, indeed, the file I was looking for. The plan is to claim the port from the driver (hence, from kernel space) but I wanted to see how this worked from a userspace program that called the above mentioned ioctl(). And this is where the fun begin.
I should mention that my laptop has 2 physical ports: one has another 4-port USB hub attached (with keyboard, mouse and headphones), the other has a small mass storage device. The plan was to claim the port the storage device was using.
lsusb provided the following output (the first physical port is omitted):
Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 021: ID 058f:6387 Alcor Micro Corp. Flash Drive
Bus 001 Device 003: ID 5986:0364 Acer, Inc
My first thought was the hub is the device 001:001. Now I had to determine what port the storage device was connected to. Could it be that 021? Removing and plugging the device back incremented that number, so it can’t be. This is the first identity: how it’s seen on the logical USB bus. It doesn’t matter which physical port it is plugged to.
Then I thought about the bus IDs in /sys/bus/usb/devices. My device had bus ID 1-1.2, so port 2 must be the port I’m looking for. However, after claiming port 2 from hub /dev/bus/usb/001/001, drivers would still bind to my device just fine. Something was not quite right.
A more graphical display of the devices associated with the physical port in question:
Hm, there are 2 hubs. Oh wait, the first one must be the virtual one created by the USB subsystem. So the “real” hub I’m looking for must be 001:002. Et voila, the port is indeed claimed.
This is the second identity of a USB device, and is the same when plugging the device in the same port. It is a string of hub ports.
Now that I think about it, things seem obvious. However, the documentation on this is really not newbie-friendly. Maybe that’s why everytime I figure something out I feel like I’ve accomplished something. :)