From c13c2b3b3c41b71586209bd8a9615b0c34cb296c Mon Sep 17 00:00:00 2001 From: Devan Lai Date: Sat, 17 Oct 2020 17:12:20 +0000 Subject: [PATCH] usb: Allow registration of a single non-contiguous string descriptor for WinUSB Classic WinUSB support is detected by probing for a string descriptor at index 0xEE with a special string. usbd_register_extra_string() allows registration of a string at this index without having to provide 237 other string descriptors Originally filed as https://github.com/libopencm3/libopencm3/pull/849 WCID reference: https://github.com/pbatard/libwdi/wiki/WCID-Devices --- include/libopencm3/usb/usbd.h | 3 +++ lib/usb/usb.c | 16 ++++++++++++++++ lib/usb/usb_private.h | 4 ++++ lib/usb/usb_standard.c | 16 +++++++++++++++- 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/include/libopencm3/usb/usbd.h b/include/libopencm3/usb/usbd.h index d2451010..3576d2b2 100644 --- a/include/libopencm3/usb/usbd.h +++ b/include/libopencm3/usb/usbd.h @@ -165,6 +165,9 @@ extern int usbd_register_set_config_callback(usbd_device *usbd_dev, extern void usbd_register_set_altsetting_callback(usbd_device *usbd_dev, usbd_set_altsetting_callback callback); +/** Registers a non-contiguous string descriptor */ +extern void usbd_register_extra_string(usbd_device *usbd_dev, int index, const char* string); + /* Functions to be provided by the hardware abstraction layer */ extern void usbd_poll(usbd_device *usbd_dev); diff --git a/lib/usb/usb.c b/lib/usb/usb.c index e2dd0c27..12bc431c 100644 --- a/lib/usb/usb.c +++ b/lib/usb/usb.c @@ -54,6 +54,8 @@ usbd_device *usbd_init(const usbd_driver *driver, usbd_dev->config = conf; usbd_dev->strings = strings; usbd_dev->num_strings = num_strings; + usbd_dev->extra_string_idx = 0; + usbd_dev->extra_string = NULL; usbd_dev->ctrl_buf = control_buffer; usbd_dev->ctrl_buf_len = control_buffer_size; @@ -94,6 +96,20 @@ void usbd_register_sof_callback(usbd_device *usbd_dev, void (*callback)(void)) usbd_dev->user_callback_sof = callback; } +void usbd_register_extra_string(usbd_device *usbd_dev, int index, const char* string) +{ + /* + * Note: string index 0 is reserved for LANGID requests and cannot + * be overwritten using this functionality. + */ + if (string != NULL && index > 0) { + usbd_dev->extra_string_idx = index; + usbd_dev->extra_string = string; + } else { + usbd_dev->extra_string_idx = 0; + } +} + void _usbd_reset(usbd_device *usbd_dev) { usbd_dev->current_address = 0; diff --git a/lib/usb/usb_private.h b/lib/usb/usb_private.h index 3aa3f9ee..9e5e1181 100644 --- a/lib/usb/usb_private.h +++ b/lib/usb/usb_private.h @@ -92,6 +92,10 @@ struct _usbd_device { const struct _usbd_driver *driver; + /* Extra, non-contiguous user string descriptor index and value */ + int extra_string_idx; + const char* extra_string; + /* private driver data */ uint16_t fifo_mem_top; diff --git a/lib/usb/usb_standard.c b/lib/usb/usb_standard.c index 4ce7a8b1..7057f2de 100644 --- a/lib/usb/usb_standard.c +++ b/lib/usb/usb_standard.c @@ -179,7 +179,21 @@ usb_standard_get_descriptor(usbd_device *usbd_dev, sizeof(sd->wData[0]); *len = MIN(*len, sd->bLength); - } else { + } else if (descr_idx == usbd_dev->extra_string_idx) { + /* This string is returned as UTF16, hence the + * multiplication + */ + sd->bLength = strlen(usbd_dev->extra_string) * 2 + + sizeof(sd->bLength) + + sizeof(sd->bDescriptorType); + + *len = MIN(*len, sd->bLength); + + for (i = 0; i < (*len / 2) - 1; i++) { + sd->wData[i] = + usbd_dev->extra_string[i]; + } + } else { array_idx = descr_idx - 1; if (!usbd_dev->strings) {