I first heard about libusb back in 2011 when I was working on USRP1. At the time, USRP had a really good C++ abstraction library called UHD, which did the heavy lifting talking to libusb. Hopefully, it takes me less than a decade to do a second example.
What is libusb? Link to heading
libusb website says it all
libusb is a C library that provides generic access to USB devices. It is intended to be used by developers to facilitate the production of applications that communicate with USB hardware.
It is portable: Using a single cross-platform API, it provides access to USB devices on Linux, macOS, Windows, etc.
It is user-mode: No special privilege or elevation is required for the application to communicate with a device.
It is version-agnostic: All versions of the USB protocol, from 1.0 to 3.1 (latest), are supported.
Hello world Link to heading
This first example is from [libstdevs.c])2
int main(void)
{
libusb_device **devs;
int r;
ssize_t cnt;
r = libusb_init(NULL);
if (r < 0)
return r;
cnt = libusb_get_device_list(NULL, &devs);
if (cnt < 0){
libusb_exit(NULL);
return (int) cnt;
}
print_devs(devs);
libusb_free_device_list(devs, 1);
libusb_exit(NULL);
return 0;
}
Here is a rundown of APIs used in above snippet
libusb_init Link to heading
From API docs
int libusb_init ( libusb_context ** context )
Initialize libusb. This function must be called before calling any other libusb function.
libusb_get_device_list Link to heading
From API docs
ssize_t libusb_get_device_list ( libusb_context * ctx, libusb_device *** list )
Returns a list of USB devices currently attached to the system. This is your entry point into finding a USB device to operate.
USB descriptors Link to heading
The next part in listdev.c is looping over the device list and print device descriptor and device-specific info.
static void print_devs(libusb_device **devs)
{
libusb_device *dev;
int i = 0, j = 0;
uint8_t path[8];
while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc;
int r = libusb_get_device_descriptor(dev, &desc);
if (r < 0) {
fprintf(stderr, "failed to get device descriptor");
return;
}
printf("%04x:%04x (bus %d, device %d)",
desc.idVendor, desc.idProduct,
libusb_get_bus_number(dev), libusb_get_device_address(dev));
r = libusb_get_port_numbers(dev, path, sizeof(path));
if (r > 0) {
printf(" path: %d", path[0]);
for (j = 1; j < r; j++)
printf(".%d", path[j]);
}
printf("\n");
}
}
Device descriptor libusb_get_device_descriptor Link to heading
libusb_device_descriptor
defined in API doc is returned by libusb_get_device_descriptor
.
Device descriptor fields are defined in USB2 specs section 9.6.1. We can also see the fields by doing lsusb -v
. For example,
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 3.00
bDeviceClass 9 Hub
bDeviceSubClass 0
bDeviceProtocol 3
bMaxPacketSize0 9
idVendor
idProduct
bcdDevice 5.04
iManufacturer 3
iProduct 2
iSerial 1
bNumConfigurations 1
Device information API Link to heading
There are also APIs to get info about device like libusb_get_bus_number
. bus number or port number depends on the implementation and OS running on the host.
I traced libusb_get_bus_number
in libusb repo to libusb/os/linux_usbfs.c
where it reads the bus number assigned from /dev/bus/
.
if (!strncmp(dev_node, "/dev/bus/usb", 12))
sscanf(dev_node, "/dev/bus/usb/%hhu/%hhu", busnum, devaddr);