diff --git a/examples/stm32/f1/other/usb_dfu/usbdfu.c b/examples/stm32/f1/other/usb_dfu/usbdfu.c index 0211a47e..f30783f3 100644 --- a/examples/stm32/f1/other/usb_dfu/usbdfu.c +++ b/examples/stm32/f1/other/usb_dfu/usbdfu.c @@ -244,6 +244,8 @@ int main(void) AFIO_MAPR |= AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON; gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 0, GPIO15); + rcc_peripheral_enable_clock(&RCC_AHBENR, RCC_AHBENR_OTGFSEN); + usbd_init(&stm32f107_usb_driver, &dev, &config, usb_strings); usbd_set_control_buffer_size(sizeof(usbd_control_buffer)); usbd_register_control_callback( diff --git a/include/libopencm3/stm32/f1/desig.h b/include/libopencm3/stm32/f1/desig.h index 74cfb353..6ceb6658 100644 --- a/include/libopencm3/stm32/f1/desig.h +++ b/include/libopencm3/stm32/f1/desig.h @@ -51,6 +51,15 @@ u16 desig_get_flash_size(void); */ void desig_get_unique_id(u32 result[]); +/** + * Read the full 96 bit unique identifier and return it as a + * zero-terminated string + * @param string memory region to write the result to + 8 @param string_len the size of string in bytes + */ +void desig_get_unique_id_as_string(char *string, + unsigned int string_len); + END_DECLS #endif diff --git a/include/libopencm3/usb/usbd.h b/include/libopencm3/usb/usbd.h index e4b35785..8f685557 100644 --- a/include/libopencm3/usb/usbd.h +++ b/include/libopencm3/usb/usbd.h @@ -24,6 +24,13 @@ BEGIN_DECLS + +enum usbd_request_return_codes { + USBD_REQ_NOTSUPP = 0, + USBD_REQ_HANDLED = 1, + USBD_REQ_NEXT_CALLBACK = 2, +}; + typedef struct _usbd_driver usbd_driver; extern const usbd_driver stm32f103_usb_driver; extern const usbd_driver stm32f107_usb_driver; @@ -38,7 +45,7 @@ extern u8 usbd_control_buffer[]; extern int usbd_init(const usbd_driver *driver, const struct usb_device_descriptor *dev, const struct usb_config_descriptor *conf, - const char **strings); + const char **strings, int num_strings); extern void usbd_set_control_buffer_size(u16 size); extern void usbd_register_reset_callback(void (*callback)(void)); diff --git a/include/libopencm3/usb/usbstd.h b/include/libopencm3/usb/usbstd.h index 8610fdbc..01fc7e3c 100644 --- a/include/libopencm3/usb/usbstd.h +++ b/include/libopencm3/usb/usbstd.h @@ -220,4 +220,7 @@ struct usb_iface_assoc_descriptor { #define USB_DT_INTERFACE_ASSOCIATION_SIZE \ sizeof(struct usb_iface_assoc_descriptor) +enum usb_language_id { + USB_LANGID_ENGLISH_US = 0x409, +}; #endif diff --git a/lib/stm32/f1/desig.c b/lib/stm32/f1/desig.c index 7ae968e1..7f213fab 100644 --- a/lib/stm32/f1/desig.c +++ b/lib/stm32/f1/desig.c @@ -35,3 +35,25 @@ void desig_get_unique_id(u32 result[]) result[1] = bits63_32; result[2] = bits31_16 << 16 | bits15_0; } + +void desig_get_unique_id_as_string(char *string, + unsigned int string_len) +{ + int i, len; + u8 device_id[12]; + static const char chars[] = "0123456789ABCDEF"; + + desig_get_unique_id((u32 *)device_id); + + /* Each byte produces two characters */ + len = (2 * sizeof(device_id) < string_len) ? + 2 * sizeof(device_id) : string_len - 1; + + for (i = 0; i < len; i += 2) { + string[i] = chars[(device_id[i / 2] >> 0) & 0x0F]; + string[i + 1] = chars[(device_id[i / 2] >> 4) & 0x0F]; + } + + string[len] = '\0'; +} + diff --git a/lib/usb/usb.c b/lib/usb/usb.c index 1ebb6ec5..d5ec9800 100644 --- a/lib/usb/usb.c +++ b/lib/usb/usb.c @@ -45,12 +45,14 @@ u8 usbd_control_buffer[128] __attribute__((weak)); */ int usbd_init(const usbd_driver *driver, const struct usb_device_descriptor *dev, - const struct usb_config_descriptor *conf, const char **strings) + const struct usb_config_descriptor *conf, + const char **strings, int num_strings) { _usbd_device.driver = driver; _usbd_device.desc = dev; _usbd_device.config = conf; _usbd_device.strings = strings; + _usbd_device.num_strings = num_strings; _usbd_device.ctrl_buf = usbd_control_buffer; _usbd_device.ctrl_buf_len = sizeof(usbd_control_buffer); diff --git a/lib/usb/usb_control.c b/lib/usb/usb_control.c index 3dd08578..b4ac57e9 100644 --- a/lib/usb/usb_control.c +++ b/lib/usb/usb_control.c @@ -102,7 +102,8 @@ static int usb_control_request_dispatch(struct usb_setup_data *req) result = cb[i].cb(req, &control_state.ctrl_buf, &control_state.ctrl_len, &control_state.complete); - if (result) + if (result == USBD_REQ_HANDLED || + result == USBD_REQ_NOTSUPP) return result; } } diff --git a/lib/usb/usb_private.h b/lib/usb/usb_private.h index a1e5e4c8..238f14f3 100644 --- a/lib/usb/usb_private.h +++ b/lib/usb/usb_private.h @@ -29,6 +29,7 @@ extern struct _usbd_device { const struct usb_device_descriptor *desc; const struct usb_config_descriptor *config; const char **strings; + int num_strings; u8 *ctrl_buf; /**< Internal buffer used for control transfers */ u16 ctrl_buf_len; diff --git a/lib/usb/usb_standard.c b/lib/usb/usb_standard.c index 2d7c619e..08923d85 100644 --- a/lib/usb/usb_standard.c +++ b/lib/usb/usb_standard.c @@ -87,50 +87,74 @@ static u16 build_config_descriptor(u8 index, u8 *buf, u16 len) return total; } +static int usb_descriptor_type(u16 wValue) +{ + return wValue >> 8; +} + +static int usb_descriptor_index(u16 wValue) +{ + return wValue & 0xFF; +} + static int usb_standard_get_descriptor(struct usb_setup_data *req, u8 **buf, u16 *len) { - int i; + int i, array_idx, descr_idx; struct usb_string_descriptor *sd; - switch (req->wValue >> 8) { + descr_idx = usb_descriptor_index(req->wValue); + + switch (usb_descriptor_type(req->wValue)) { case USB_DT_DEVICE: *buf = (u8 *) _usbd_device.desc; *len = MIN(*len, _usbd_device.desc->bLength); - return 1; + return USBD_REQ_HANDLED; case USB_DT_CONFIGURATION: *buf = _usbd_device.ctrl_buf; - *len = build_config_descriptor(req->wValue & 0xff, *buf, *len); - return 1; + *len = build_config_descriptor(descr_idx, *buf, *len); + return USBD_REQ_HANDLED; case USB_DT_STRING: sd = (struct usb_string_descriptor *)_usbd_device.ctrl_buf; - if (!_usbd_device.strings) - return 0; /* Device doesn't support strings. */ + if (descr_idx == 0) { + /* Send sane Language ID descriptor... */ + sd->wData[0] = USB_LANGID_ENGLISH_US; + sd->bLength = sizeof(sd->bLength) + sizeof(sd->bDescriptorType) + + sizeof(sd->wData[0]); - /* Check that string index is in range. */ - for (i = 0; i <= (req->wValue & 0xff); i++) - if (_usbd_device.strings[i] == NULL) - return 0; + *len = MIN(*len, sd->bLength); + } else { + array_idx = descr_idx - 1; + + if (!_usbd_device.strings) + return USBD_REQ_NOTSUPP; /* Device doesn't support strings. */ + /* Check that string index is in range. */ + if (array_idx >= _usbd_device.num_strings) + return USBD_REQ_NOTSUPP; + + /* Strings with Language ID differnet from + * USB_LANGID_ENGLISH_US are not supported */ + if (req->wIndex != USB_LANGID_ENGLISH_US) + return USBD_REQ_NOTSUPP; + + /* Ths string is returned as UTF16, hence the multiplication */ + sd->bLength = strlen(_usbd_device.strings[array_idx]) * 2 + + sizeof(sd->bLength) + sizeof(sd->bDescriptorType); + + *len = MIN(*len, sd->bLength); + + for (i = 0; i < (*len / 2) - 1; i++) + sd->wData[i] = + _usbd_device.strings[array_idx][i]; + } - sd->bLength = strlen(_usbd_device.strings[req->wValue & 0xff]) - * 2 + 2; sd->bDescriptorType = USB_DT_STRING; - *buf = (u8 *)sd; - *len = MIN(*len, sd->bLength); - for (i = 0; i < (*len / 2) - 1; i++) - sd->wData[i] = - _usbd_device.strings[req->wValue & 0xff][i]; - - /* Send sane Language ID descriptor... */ - if ((req->wValue & 0xff) == 0) - sd->wData[0] = 0x409; - - return 1; + return USBD_REQ_HANDLED; } - return 0; + return USBD_REQ_NOTSUPP; } static int usb_standard_set_address(struct usb_setup_data *req, u8 **buf,