Linux: Where the USB related kernel files are

This post was written by eli on May 17, 2017
Posted Under: Linux,Linux kernel,USB

A few notes on where to find USB related kernel files on a Linux system (kernel 3.12.20 in my case)

$ lsusb
[ ... ]
Bus 001 Device 059: ID 046d:c52b Logitech, Inc.

Now find the position in the tree. It should be device 59 under bus number 1:

$ lsusb -t
[ ... ]
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/6p, 480M
    |__ Port 4: Dev 4, If 0, Class=hub, Driver=hub/4p, 480M
        |__ Port 1: Dev 59, If 0, Class=HID, Driver=usbhid, 12M
        |__ Port 1: Dev 59, If 1, Class=HID, Driver=usbhid, 12M
        |__ Port 1: Dev 59, If 2, Class=HID, Driver=usbhid, 12M
        |__ Port 3: Dev 98, If 0, Class=vend., Driver=pl2303, 12M
    |__ Port 6: Dev 94, If 0, Class=vend., Driver=rt2800usb, 480M

So it’s bus 1, hub on port 4 and then port 1. Verify by checking the IDs (the paths can be much shorter, see below):

$ cat /sys/bus/usb/devices/usb1/1-4/1-4.1/idVendor
046d
$ cat /sys/bus/usb/devices/usb1/1-4/1-4.1/idProduct
c52b

or look at the individual interfaces:

$ cat /sys/bus/usb/devices/usb1/1-4/1-4.1/1-4.1\:1.2/bInterfaceClass
03

or get everything in one go, with the “uevent” file:

$ cat /sys/bus/usb/devices/usb1/1-4/1-4.1/uevent
MAJOR=189
MINOR=56
DEVNAME=bus/usb/001/059
DEVTYPE=usb_device
DRIVER=usb
PRODUCT=46d/c52b/1209
TYPE=0/0/0
BUSNUM=001
DEVNUM=059

Even though “uevent” was originally intended for generating an udev event by writing to it, reading from it provides the variables supplied to the udev mechanism. The DRIVER entry, if present, contains the driver currently assigned to the device (or interface), and is absent if no such driver is assigned (e.g. after an rmmod of the relevant module). It will usually not contain anything interesting except for when looking at directories of interfaces, because all other parts of the hierarchy are USB infrastructure, driven by drivers for such.

The device file accessed for raw userspace I/O with a USB device (with e.g libusb) is in /dev/usb/ followed by the bus number and address. For example, the Logitech device mentioned above is at bus 1, address 59 (and note DEVNAME from uevent file), hence

$ ls -l /dev/bus/usb/001/059
crw-rw-r-- 1 root root 189, 58 2017-05-17 09:57 /dev/bus/usb/001/059

Note the permissions and major/minors. The major is 189 (usb_devices on my system, according to /proc/devices). The minor is the ((bus_number-1) * 128) + address – 1.

The permissions and ownership are those in effect for who’s allowed to access this device. This is the place to check if udev rules that allow wider access to a device have done their job.

/sys/bus/usb/devices/

This was mentioned briefly above, and now let’s do the deep dive. The sysfs structure for USB devices is rather tangled, because it has many references: Through the host controller it’s connected (typically as a PCI/PCIe device on a PC), as the device itself, and as the interfaces it provides.

It helps to note that those numeric-dash-dot-colon directory names actually contain all information about the position in the USB bus hierarchy, and all of these are present directly in /sys/bus/usb/devices, as a symbolic link.

Also in /sys/bus/usb/devices, there are usbN directories, each representing a USB root hub, with N being the USB bus number. One can travel down the USB bus hierarchy starting from the usbN directories, and find the directories those symlinked directories, in a directory hierarchy that represents the bus hierarchy.

So let’s look, for example, at a directory name 1-5.1.4:1.3.

  • The “1-” part means bus number one.
  • The “5.1.4″ part describes the path through hubs until the device is reached: port number 5 of the root hub, port 1 of the hub connected to it, and port 4 of the hub connected to that one. Without any physical hubs, this part is just one digit, so one gets those short “1-4″ names.
    Note that the chain of ports is delimited by dots. It seems like there used to be dashes a long time ago, so it would read “5-1-4″ instead. But that’s probably ancient history.
  • Then we have the “:1.3″ part, which means interface number 3 on the device running in configuration number 1.

This specific directory can be found in /sys/bus/usb/devices/usb1/1-5/1-5.1/1-5.1.4/1-5.1.4:1.3/, where it appears to be a plain directory, or as /sys/bus/usb/devices/1-5.1.4:1.3, where it appears to be a symbolic link to ../../../devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.1/1-5.1.4/1-5.1.4:1.3/. But the symbolic link actually points at the former, because /sys/devices/pci0000:00/0000:00:14.0/usb1/ and /sys/bus/usb/devices/usb1/ is exactly the same. The bonus with having the symbolic link pointing at the PCI device is that we can tell which PCI/PCIe device it belongs to.

Part of the reason for this mess is that the sysfs directory tree is a representation of the references between device structures inside the Linux kernel. Since these structures point at each other in every possible direction, so does the directory structure, sometimes with symbolic links, and sometimes with identical entries.

Messy or not, this directory structure allows traveling down the USB bus tree quite easily. For example, starting from /sys/bus/usb/devices/usb1/, one can travel down all the way to 1-5.1.4:1.3, each directory providing product and vendor IDs in both numerical and string format. Except for the final leaf (with the name including a colon-suffix, e.g. :1.3) which represents an interface, so it carries different information (about endpoints, for example).

The numbers in the directories in sysfs relate to the physical topology, and should not be confused with the bus address that is assigned to each device. The only thing they have in common is the bus number, and I’m not sure that can be trusted either. But in reality, that initial “1″ and the “usb1″ part in the path actually represent the bus number of all devices in that hierarchy. Recall that all devices that are connected to a USB root port have the same bus number, even if there are hubs inbetween (unlike PCI/PCIe and switches).

Ah, and once again: “usb1″ means USB bus 1. If you were temped to interpret this as a USB protocol level, well, no.

To obtain the enumerated addresses (those that are used to talk with the device, and appear with a plain lsusb), read the “uevent” file, which even supplies the path in /dev. Or read “busnum” and “devnum” files in each directory. Now one can ask if “busnum” is redundant, since it’s supposed to be known from the directory path itself. But one could likewise ask what “devpath” is doing there, as it consists the part that comes after the dash in the directory name. Go figure.

/sys/bus/usb/drivers/

But hey, it’s not over yet. The USB devices are also divided according to their drivers. This happens in /sys/bus/usb/drivers, which is a nice place to start if you’re looking for a device doing a specific task, hence easily found by its driver.

Back to the example above, /sys/bus/usb/drivers/usb-storage has a symbolic link named 1-5.1.4:1.3, pointing at ../../../../devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.1/1-5.1.4/1-5.1.4:1.3/, which is exactly the same leaf directory as before. Not surprisingly, the driver is attached to an interface, and not to a device. So this provides the entire path to the functional part, going from the PCI entry to the USB bus, and all the way down. If we want the bus address, fetch it from the leaf directory’s parent directory, 1-5.1.4 in this case.

The dedicated usb-storage directory also has the “bind” and “unbind” files, which allow to detach and re-attach the driver to the USB device. This may be equivalent to unplugging the device and plugging it back, but not necessarily — it will result in a certain level of re-initialization, but not as full as detaching the device completely (or unbinding the USB controller from the PCI bus).

Note that a device can have multiple interfaces, which are possibly handled by different drivers. For example, a camera can function as webcam for showing a live picture, but also as a mass storage device for exposing the SD card. It’s still one USB device, with one Vendor / Product ID, and with a single pool of endpoints. So a device may appear under several directories of /sys/bus/usb/drivers/.

Try lsusb -t and lsusb -vv. And now also appreciate what this utility does…

Add a Comment

required, use real name
required, will not be published
optional, your blog address