-
Sylvain Fasel authored
libusb_get_device_string() exposes only the device-descriptor strings (manufacturer, product, serial number). Applications also need the configuration (iConfiguration) and interface (iInterface) strings, e.g. to present a human-readable interface name during device selection (#1855). Add two public APIs that mirror libusb_get_device_string() but for these descriptor-scoped strings, retrievable without opening the device: int libusb_get_config_string(libusb_device *dev, uint8_t config_value, char *data, int length); int libusb_get_interface_string(libusb_device *dev, uint8_t config_value, uint8_t interface_number, uint8_t alt_setting, char *data, int length); config_value is the bConfigurationValue, or 0 to select the currently active configuration (0 is never a valid bConfigurationValue). As in libusb_get_device_string(), data may be NULL (with a non-zero length) to query the required buffer size, and the returned string length includes the NUL terminator. LIBUSB_API_VERSION is bumped to 0x0100010D; the functions first appear in 1.0.31. USB string descriptors are device-global and addressed by index, so the fetch is identical to the device strings; only resolving iConfiguration / iInterface from the cached configuration descriptor is new. That resolution is shared in usbi_get_config_string_index() / usbi_get_interface_string_index(), and every backend resolves the index first, so a nonexistent configuration/interface/alternate setting or a missing string (index 0) fails identically everywhere (LIBUSB_ERROR_NOT_FOUND) before any platform limit applies (LIBUSB_ERROR_NOT_SUPPORTED). The public wrappers fetch into an internal scratch buffer and reuse usbi_utf8_copy() for UTF-8-boundary-safe truncation, matching libusb_get_device_string() minus its persistent cache, which cannot index the unbounded config/interface/alt-setting space; results are therefore not cached, as documented. Because the core always passes that valid scratch buffer, backends assert data/length rather than validate them. Backends: - windows (winusb): the parent-hub IOCTL fetch is extracted from winusb_get_device_string() into winusb_fetch_string_descriptor() (defined after the getters, so the original function and its explanatory comment stay in place) and shared by all three string getters. - darwin: a GET_DESCRIPTOR control request; IOKit does not cache interface/configuration strings as IORegistry properties. The device lock is held across the whole open/request/close sequence so that the open_count check stays stable, a concurrent libusb_open() / libusb_close() cannot interleave with the temporary open (plain USBDeviceOpen(), never Seize), and the device interface cannot be swapped by a re-enumeration. The primary language ID is cached in the cached device, as the winusb backend does. - linux: reads the named sysfs attributes (configuration, <dev>:<config>.<interface>/interface), sharing the read/strip helper with op_get_device_string() (which as a side effect now returns the length including the NUL terminator; its only caller checks the result solely for error). Only the active configuration and the currently selected alternate setting are available without opening the device; other requests return LIBUSB_ERROR_NOT_SUPPORTED, as spelled out in the per-platform documentation notes. - backends without an implementation return LIBUSB_ERROR_NOT_SUPPORTED. The listdevs example prints the configuration and per-interface strings in --verbose mode. Assisted-by: claude-code:claude-opus-4-8ce43856aSylvain Fasel authoredlibusb_get_device_string() exposes only the device-descriptor strings (manufacturer, product, serial number). Applications also need the configuration (iConfiguration) and interface (iInterface) strings, e.g. to present a human-readable interface name during device selection (#1855). Add two public APIs that mirror libusb_get_device_string() but for these descriptor-scoped strings, retrievable without opening the device: int libusb_get_config_string(libusb_device *dev, uint8_t config_value, char *data, int length); int libusb_get_interface_string(libusb_device *dev, uint8_t config_value, uint8_t interface_number, uint8_t alt_setting, char *data, int length); config_value is the bConfigurationValue, or 0 to select the currently active configuration (0 is never a valid bConfigurationValue). As in libusb_get_device_string(), data may be NULL (with a non-zero length) to query the required buffer size, and the returned string length includes the NUL terminator. LIBUSB_API_VERSION is bumped to 0x0100010D; the functions first appear in 1.0.31. USB string descriptors are device-global and addressed by index, so the fetch is identical to the device strings; only resolving iConfiguration / iInterface from the cached configuration descriptor is new. That resolution is shared in usbi_get_config_string_index() / usbi_get_interface_string_index(), and every backend resolves the index first, so a nonexistent configuration/interface/alternate setting or a missing string (index 0) fails identically everywhere (LIBUSB_ERROR_NOT_FOUND) before any platform limit applies (LIBUSB_ERROR_NOT_SUPPORTED). The public wrappers fetch into an internal scratch buffer and reuse usbi_utf8_copy() for UTF-8-boundary-safe truncation, matching libusb_get_device_string() minus its persistent cache, which cannot index the unbounded config/interface/alt-setting space; results are therefore not cached, as documented. Because the core always passes that valid scratch buffer, backends assert data/length rather than validate them. Backends: - windows (winusb): the parent-hub IOCTL fetch is extracted from winusb_get_device_string() into winusb_fetch_string_descriptor() (defined after the getters, so the original function and its explanatory comment stay in place) and shared by all three string getters. - darwin: a GET_DESCRIPTOR control request; IOKit does not cache interface/configuration strings as IORegistry properties. The device lock is held across the whole open/request/close sequence so that the open_count check stays stable, a concurrent libusb_open() / libusb_close() cannot interleave with the temporary open (plain USBDeviceOpen(), never Seize), and the device interface cannot be swapped by a re-enumeration. The primary language ID is cached in the cached device, as the winusb backend does. - linux: reads the named sysfs attributes (configuration, <dev>:<config>.<interface>/interface), sharing the read/strip helper with op_get_device_string() (which as a side effect now returns the length including the NUL terminator; its only caller checks the result solely for error). Only the active configuration and the currently selected alternate setting are available without opening the device; other requests return LIBUSB_ERROR_NOT_SUPPORTED, as spelled out in the per-platform documentation notes. - backends without an implementation return LIBUSB_ERROR_NOT_SUPPORTED. The listdevs example prints the configuration and per-interface strings in --verbose mode. Assisted-by: claude-code:claude-opus-4-8
To find the state of this project's repository at the time of any of these versions, check out the tags.
Loading