libusb: Caveats

| libusb 1.0.26 A cross-platform user library to access USB devices

Caveats

# Thread safety

libusb is designed to be completely thread-safe, but as with any API it cannot prevent a user from sabotaging themselves, either intentionally or otherwise.

Observe the following general guidelines:

- Calls to functions that release a resource (e.g. libusb_close(), libusb_free_config_descriptor()) should not be called concurrently on the same resource. This is no different than concurrently calling free() on the same allocated pointer.
- Each individual libusb_transfer should be prepared by a single thread. In other words, no two threads should ever be concurrently filling out the fields of a libusb_transfer. You can liken this to calling sprintf() with the same destination buffer from multiple threads. The results will likely not be what you want unless the input parameters are all the same, but its best to avoid this situation entirely.
- Both the libusb_transfer structure and its associated data buffer should not be accessed between the time the transfer is submitted and the time the completion callback is invoked. You can think of "ownership" of these things as being transferred to libusb while the transfer is active.
- The various "setter" functions (e.g. libusb_set_log_cb(), libusb_set_pollfd_notifiers()) should not be called concurrently on the resource. Though doing so will not lead to any undefined behavior, it will likely produce results that the application does not expect.

Rules for multiple threads and asynchronous I/O are detailed here.

# Fork considerations

libusb is not designed to work across fork() calls. Depending on the platform, there may be resources in the parent process that are not available to the child (e.g. the hotplug monitor thread on Linux). In addition, since the parent and child will share libusb's internal file descriptors, using libusb in any way from the child could cause the parent process's libusb_context to get into an inconsistent state.

On Linux, libusb's file descriptors will be marked as CLOEXEC, which means that it is safe to fork() and exec() without worrying about the child process needing to clean up state or having access to these file descriptors. Other platforms may not be so forgiving, so consider yourself warned!

# Device resets

The libusb_reset_device() function allows you to reset a device. If your program has to call such a function, it should obviously be aware that the reset will cause device state to change (e.g. register values may be reset).

The problem is that any other program could reset the device your program is working with, at any time. libusb does not offer a mechanism to inform you when this has happened, so if someone else resets your device it will not be clear to your own program why the device state has changed.

Ultimately, this is a limitation of writing drivers in user space. Separation from the USB stack in the underlying kernel makes it difficult for the operating system to deliver such notifications to your program. The Linux kernel USB stack allows such reset notifications to be delivered to in-kernel USB drivers, but it is not clear how such notifications could be delivered to second-class drivers that live in user space.

# Blocking-only functionality

The functionality listed below is only available through synchronous, blocking functions. There are no asynchronous/non-blocking alternatives, and no clear ways of implementing these.

- Configuration activation (libusb_set_configuration())
- Interface/alternate setting activation (libusb_set_interface_alt_setting())
- Releasing of interfaces (libusb_release_interface())
- Clearing of halt/stall condition (libusb_clear_halt())
- Device resets (libusb_reset_device())

# Configuration selection and handling

When libusb presents a device handle to an application, there is a chance that the corresponding device may be in unconfigured state. For devices with multiple configurations, there is also a chance that the configuration currently selected is not the one that the application wants to use.

The obvious solution is to add a call to libusb_set_configuration() early on during your device initialization routines, but there are caveats to be aware of:

1. If the device is already in the desired configuration, calling libusb_set_configuration() using the same configuration value will cause a lightweight device reset. This may not be desirable behaviour.
2. In the case where the desired configuration is already active, libusb may not even be able to perform a lightweight device reset. For example, take my USB keyboard with fingerprint reader: I'm interested in driving the fingerprint reader interface through libusb, but the kernel's USB-HID driver will almost always have claimed the keyboard interface. Because the kernel has claimed an interface, it is not even possible to perform the lightweight device reset, so libusb_set_configuration() will fail. (Luckily the device in question only has a single configuration.)
3. libusb will be unable to set a configuration if other programs or drivers have claimed interfaces. In particular, this means that kernel drivers must be detached from all the interfaces before libusb_set_configuration() may succeed.

One solution to some of the above problems is to consider the currently active configuration. If the configuration we want is already active, then we don't have to select any configuration:

cfg = -1;
libusb_get_configuration(dev, &cfg);
if (cfg != desired)
libusb_set_configuration(dev, desired);
libusb_set_configuration
int libusb_set_configuration(libusb_device_handle *dev_handle, int configuration)
Set the active configuration for a device.
Definition: core.c:1626
libusb_get_configuration
int libusb_get_configuration(libusb_device_handle *dev_handle, int *config)
Determine the bConfigurationValue of the currently active configuration.
Definition: core.c:1539

This is probably suitable for most scenarios, but is inherently racy: another application or driver may change the selected configuration after the libusb_get_configuration() call.

Even in cases where libusb_set_configuration() succeeds, consider that other applications or drivers may change configuration after your application calls libusb_set_configuration().

One possible way to lock your device into a specific configuration is as follows:

1. Set the desired configuration (or use the logic above to realise that it is already in the desired configuration)
2. Claim the interface that you wish to use
3. Check that the currently active configuration is the one that you want to use.

The above method works because once an interface is claimed, no application or driver is able to select another configuration.

# Early transfer completion

NOTE: This section is currently Linux-centric. I am not sure if any of these considerations apply to Darwin or other platforms.

When a transfer completes early (i.e. when less data is received/sent in any one packet than the transfer buffer allows for) then libusb is designed to terminate the transfer immediately, not transferring or receiving any more data unless other transfers have been queued by the user.

On legacy platforms, libusb is unable to do this in all situations. After the incomplete packet occurs, "surplus" data may be transferred. For recent versions of libusb, this information is kept (the data length of the transfer is updated) and, for device-to-host transfers, any surplus data was added to the buffer. Still, this is not a nice solution because it loses the information about the end of the short packet, and the user probably wanted that surplus data to arrive in the next logical transfer.

# Zero length packets

- libusb is able to send a packet of zero length to an endpoint simply by submitting a transfer of zero length.
- The LIBUSB_TRANSFER_ADD_ZERO_PACKET flag is currently supported on Linux, Darwin and Windows (WinUSB).