Skip to content

Commit

Permalink
windows: Implement get_serial_string_descriptor
Browse files Browse the repository at this point in the history
  • Loading branch information
hjmallon committed Feb 15, 2021
1 parent 4396d64 commit d0f9fd4
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 1 deletion.
9 changes: 8 additions & 1 deletion libusb/os/windows_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,13 @@ static void windows_close(struct libusb_device_handle *dev_handle)
priv->backend->close(dev_handle);
}

static int windows_get_serial_string_descriptor(struct libusb_device *dev,
unsigned char *data, int length)
{
struct windows_context_priv *priv = usbi_get_context_priv(DEVICE_CTX(dev));
return priv->backend->get_serial_string_descriptor(dev, data, length);
}

static int windows_get_active_config_descriptor(struct libusb_device *dev,
void *buffer, size_t len)
{
Expand Down Expand Up @@ -898,7 +905,7 @@ const struct usbi_os_backend usbi_backend = {
NULL, /* wrap_sys_device */
windows_open,
windows_close,
NULL, /* get_serial_string_descriptor */
windows_get_serial_string_descriptor,
windows_get_active_config_descriptor,
windows_get_config_descriptor,
windows_get_config_descriptor_by_value,
Expand Down
9 changes: 9 additions & 0 deletions libusb/os/windows_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ typedef struct USB_CONFIGURATION_DESCRIPTOR {
UCHAR MaxPower;
} USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;

typedef struct USB_STRING_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
WCHAR bString[1];
} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;

#include <poppack.h>

#define MAX_DEVICE_ID_LEN 200
Expand Down Expand Up @@ -259,6 +265,7 @@ struct winusb_device_priv {
} usb_interface[USB_MAXINTERFACES];
struct hid_device_priv *hid;
PUSB_CONFIGURATION_DESCRIPTOR *config_descriptor; // list of pointers to the cached config descriptors
PUSB_STRING_DESCRIPTOR serial_string_descriptor;
};

struct usbdk_device_handle_priv {
Expand Down Expand Up @@ -305,6 +312,8 @@ struct windows_backend {
struct discovered_devs **discdevs);
int (*open)(struct libusb_device_handle *dev_handle);
void (*close)(struct libusb_device_handle *dev_handle);
int (*get_serial_string_descriptor)(struct libusb_device *device,
unsigned char *data, int length);
int (*get_active_config_descriptor)(struct libusb_device *device,
void *buffer, size_t len);
int (*get_config_descriptor)(struct libusb_device *device,
Expand Down
7 changes: 7 additions & 0 deletions libusb/os/windows_usbdk.c
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,12 @@ static int usbdk_get_device_list(struct libusb_context *ctx, struct discovered_d
return r;
}

static int usbdk_get_serial_string_descriptor(struct libusb_device *device,
unsigned char *data, int length)
{
return LIBUSB_ERROR_NOT_SUPPORTED;
}

static int usbdk_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
{
struct usbdk_device_priv *priv = usbi_get_device_priv(dev);
Expand Down Expand Up @@ -706,6 +712,7 @@ const struct windows_backend usbdk_backend = {
usbdk_get_device_list,
usbdk_open,
usbdk_close,
usbdk_get_serial_string_descriptor,
usbdk_get_active_config_descriptor,
usbdk_get_config_descriptor,
usbdk_get_config_descriptor_by_value,
Expand Down
109 changes: 109 additions & 0 deletions libusb/os/windows_winusb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,6 +1038,98 @@ static int init_root_hub(struct libusb_device *dev)
return r;
}

/*
* Cache the serial number string descriptor
*/
static void cache_serial_string_descriptor(struct libusb_device *dev, HANDLE hub_handle)
{
struct libusb_context *ctx = DEVICE_CTX(dev);
struct winusb_device_priv *priv = _device_priv(dev);
DWORD size, ret_size;

USB_STRING_DESCRIPTOR_SHORT sd_buf_short; // dummy request
PUSB_DESCRIPTOR_REQUEST sd_buf_actual = NULL; // actual request
PUSB_STRING_DESCRIPTOR sd_data;

if (priv->dev_descriptor.iSerialNumber == 0)
return;

size = sizeof(sd_buf_short);
memset(&sd_buf_short, 0, size);

sd_buf_short.req.ConnectionIndex = (ULONG)dev->port_number;
sd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
sd_buf_short.req.SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
sd_buf_short.req.SetupPacket.wValue = (LIBUSB_DT_STRING << 8) | priv->dev_descriptor.iSerialNumber;
sd_buf_short.req.SetupPacket.wIndex = 0;
sd_buf_short.req.SetupPacket.wLength = (USHORT)sizeof(USB_STRING_DESCRIPTOR);

// Dummy call to get the required data size. Initial failures are reported as info rather
// than error as they can occur for non-penalizing situations, such as with some hubs.
// coverity[tainted_data_argument]
if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &sd_buf_short, size,
&sd_buf_short, size, &ret_size, NULL)) {
usbi_info(ctx, "could not access string descriptor %u (dummy) for '%s': %s", priv->dev_descriptor.iSerialNumber,
priv->dev_id, windows_error_str(0));
return;
}

if ((ret_size != size) || (sd_buf_short.desc.bLength < sizeof(USB_STRING_DESCRIPTOR))) {
usbi_info(ctx, "unexpected string descriptor %u size (dummy) for '%s'", priv->dev_descriptor.iSerialNumber, priv->dev_id);
return;
}

size = sizeof(USB_DESCRIPTOR_REQUEST) + sd_buf_short.desc.bLength;
sd_buf_actual = malloc(size);
if (sd_buf_actual == NULL) {
usbi_err(ctx, "could not allocate string descriptor %u buffer for '%s'", priv->dev_descriptor.iSerialNumber, priv->dev_id);
return;
}

// Actual call
sd_buf_actual->ConnectionIndex = (ULONG)dev->port_number;
sd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
sd_buf_actual->SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
sd_buf_actual->SetupPacket.wValue = (LIBUSB_DT_STRING << 8) | priv->dev_descriptor.iSerialNumber;
sd_buf_actual->SetupPacket.wIndex = 0;
sd_buf_actual->SetupPacket.wLength = sd_buf_short.desc.bLength;

if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, sd_buf_actual, size,
sd_buf_actual, size, &ret_size, NULL)) {
usbi_err(ctx, "could not access string descriptor %u for '%s': %s", priv->dev_descriptor.iSerialNumber,
priv->dev_id, windows_error_str(0));
safe_free(sd_buf_actual);
return;
}

sd_data = (PUSB_STRING_DESCRIPTOR)((UCHAR *)sd_buf_actual + sizeof(USB_DESCRIPTOR_REQUEST));

if ((size != ret_size) || (sd_data->bLength != sd_buf_short.desc.bLength)) {
usbi_err(ctx, "unexpected string descriptor %u size (actual) for '%s'", priv->dev_descriptor.iSerialNumber, priv->dev_id);
safe_free(sd_buf_actual);
return;
}

if (sd_data->bDescriptorType != LIBUSB_DT_STRING) {
usbi_err(ctx, "descriptor %u not a string descriptor for '%s'", priv->dev_descriptor.iSerialNumber, priv->dev_id);
safe_free(sd_buf_actual);
return;
}

usbi_dbg("cached string descriptor %u (%u bytes)",
priv->dev_descriptor.iSerialNumber, sd_data->bLength);

// Cache the descriptor
priv->serial_string_descriptor = malloc(sd_data->bLength);
if (priv->serial_string_descriptor != NULL) {
memcpy(priv->serial_string_descriptor, sd_data, sd_data->bLength);
} else {
usbi_err(ctx, "could not allocate string descriptor %u buffer for '%s'", priv->dev_descriptor.iSerialNumber, priv->dev_id);
}

safe_free(sd_buf_actual);
}

/*
* Populate a libusb device structure
*/
Expand Down Expand Up @@ -1172,6 +1264,9 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d
// Cache as many config descriptors as we can
cache_config_descriptors(dev, hub_handle);

// Cache serial string descriptor
cache_serial_string_descriptor(dev, hub_handle);

// In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8
if (windows_version >= WINDOWS_8) {
conn_info_v2.ConnectionIndex = (ULONG)port_number;
Expand Down Expand Up @@ -1814,6 +1909,20 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
return r;
}

static int winusb_get_serial_string_descriptor(struct libusb_device *dev,
unsigned char *buffer, int len)
{
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
int size;

if (priv->serial_string_descriptor == NULL)
return LIBUSB_ERROR_NOT_FOUND;

size = MIN(priv->serial_string_descriptor->bLength, len);
memcpy(buffer, priv->serial_string_descriptor, size);
return size;
}

static int winusb_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
{
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
Expand Down
6 changes: 6 additions & 0 deletions libusb/os/windows_winusb.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ static inline void winusb_device_priv_release(struct libusb_device *dev)
}
}
free(priv->config_descriptor);
free(priv->serial_string_descriptor);
free(priv->hid);
for (i = 0; i < USB_MAXINTERFACES; i++) {
free(priv->usb_interface[i].path);
Expand Down Expand Up @@ -353,6 +354,11 @@ typedef struct _USB_CONFIGURATION_DESCRIPTOR_SHORT {
USB_CONFIGURATION_DESCRIPTOR desc;
} USB_CONFIGURATION_DESCRIPTOR_SHORT;

typedef struct _USB_STRING_DESCRIPTOR_SHORT {
USB_DESCRIPTOR_REQUEST req;
USB_STRING_DESCRIPTOR desc;
} USB_STRING_DESCRIPTOR_SHORT;

typedef struct USB_INTERFACE_DESCRIPTOR {
UCHAR bLength;
UCHAR bDescriptorType;
Expand Down

0 comments on commit d0f9fd4

Please sign in to comment.