Unless you are curious (or eager to make things hard on yourself) you should use libusb. There are plenty of resources for learning about that, best of which are the online API documents.
However, libusb is an abstraction and it is portable to a variety of operating systems. This is great, but at some point, a person like myself starts wondering just how libusb talks to USB host adapters.
Take a look at /proc/bus/usb. I did, and it wasn't there. I am running Fedora 34 with a 5.16.8 kernel and the ancient USB FAQ mentioned above talks about 2.5 kernels, so we really need more modern documentation. The following is more of a description of driver internals, I do find /sys/bus/usb on my system. The trick just may be to look at the libusb sources. Before we dive into that, the following provides interesting information: The last two links above are from the Docs directory for usbloger. I put them here on my web page as a handier way to view them.Also interesting is "man 5 sysfs" as well as "sysfs"
Note that /sys/bus/usb/devices holds a bunch of links to files in /sys/devices. On my system, all the USB host devices are on the PCI bus, so it is much more tricky to get at them via /sys/devices than via /sys/bus/usb/devices.
As an experiment, let's chase down what libusb_get_device_list() does. We will use ctags to help us along. This routine is in libusb/core.c It is a fairly simple routine. The work seems to be done by the routine "usbi_backend.get_device_list(). So usbi_backend is a struct with function pointers. This leads us to os/linux_usbfs.c. It appears to be able to use either sysfs_get_device_list() or usbfs_get_device_list(). It looks like it uses the latter on my system, and the former is for ancient systems.
The sysfs_get_device_list() routine is in os/linux_usbfs.c. It does an opendir() on /sys/bus/usb/devices, then loops through what is in that directory. It looks like it skips anything that begins with "usb" and any name that begins with a colon. So it likes entries like "1-1" and "3-2.6" but not "usb1" or "1-1:1.0". Then it calls sysfs_scan_device() on the entries it likes.
This routine calls linux_get_device_address() and linux_enumerate_device(). If either of these fail, it skips the device. The first extracts the "busnum" and "devaddr"
This could be looked at in more detail, but it is clear that /sys/bus/usb/devices is the game here. What about libusb_open_device_with_vid_pid() ?
This also is in libusb/core.c. They say this shouldn't be used in real applications. It is a shortcut for the lazy man. It calls libusb_get_device_list(). This returns a null terminated array that it plows through, calling libusb_get_device_descriptor() for each entry. Once it has the device descriptor, it can check the vendor and product ID for a match. Once it finds a match, it calls libusb_open(), frees the list, and returns the handle from libusb_open.
So, let's look at libusb_get_device_descriptor(). This is in libusb/descriptor.c It is just an accessor routine that returns the "device_descriptor" field from the chosen entry from the device list.
Libusb_open() is in core.c The key routine is "usbi_backend.open() which is op_open() in linux_usbfs.c It calls get_usbfs_fd() It does a good old fashioned open() call on /dev/bus/usb/%03u/%03u where the first value is the bus_number and the second is the device_address.
When I look at /dev/bus/usb on my system, I see 4 directories (001, 002, 003, and 004). In the 004 directory on my system, I see:
crw-rw-rw- 1 root usbusers 189, 384 Feb 13 16:48 001 crw-rw-rw- 1 root usbusers 189, 386 Feb 13 16:48 003 crw-rw-rw- 1 root usbusers 189, 387 Feb 13 16:48 004 crw-rw-rw- 1 root usbusers 189, 397 Feb 14 11:51 014And it is these files that ultimately get read or written.
Tom's electronics pages / tom@mmto.org