diff --git a/subsys/usb/device_next/usbd_ch9.c b/subsys/usb/device_next/usbd_ch9.c index 755950cc651..da80e778533 100644 --- a/subsys/usb/device_next/usbd_ch9.c +++ b/subsys/usb/device_next/usbd_ch9.c @@ -523,41 +523,85 @@ static int sreq_get_desc_cfg(struct usbd_contex *const uds_ctx, return 0; } -static int sreq_get_desc(struct usbd_contex *const uds_ctx, - struct net_buf *const buf, - const uint8_t type, const uint8_t idx) +/* Copy and convert ASCII-7 string descriptor to UTF16-LE */ +static void string_ascii7_to_utf16le(struct usbd_desc_node *const dn, + struct net_buf *const buf, const uint16_t wLength) +{ + struct usb_string_descriptor *desc = dn->desc; + uint8_t *ascii7_str = (uint8_t *)&desc->bString; + size_t len; + + LOG_DBG("wLength %u, bLength %u, tailroom %u", + wLength, desc->bLength, net_buf_tailroom(buf)); + + len = MIN(net_buf_tailroom(buf), MIN(desc->bLength, wLength)); + + /* Add bLength and bDescriptorType */ + net_buf_add_mem(buf, desc, MIN(len, 2U)); + len -= MIN(len, 2U); + + for (size_t i = 0; i < len; i++) { + __ASSERT(ascii7_str[i] > 0x1F && ascii7_str[i] < 0x7F, + "Only printable ascii-7 characters are allowed in USB " + "string descriptors"); + net_buf_add_le16(buf, ascii7_str[i]); + } +} + +static int sreq_get_desc_dev(struct usbd_contex *const uds_ctx, + struct net_buf *const buf) { struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); struct usb_desc_header *head; size_t len; - if (type == USB_DESC_DEVICE) { - switch (usbd_bus_speed(uds_ctx)) { - case USBD_SPEED_FS: - head = uds_ctx->fs_desc; - break; - case USBD_SPEED_HS: - head = uds_ctx->hs_desc; - break; - default: - errno = -ENOTSUP; - return 0; - } - } else { - head = usbd_get_descriptor(uds_ctx, type, idx); - } + len = MIN(setup->wLength, net_buf_tailroom(buf)); - if (head == NULL) { + switch (usbd_bus_speed(uds_ctx)) { + case USBD_SPEED_FS: + head = uds_ctx->fs_desc; + break; + case USBD_SPEED_HS: + head = uds_ctx->hs_desc; + break; + default: errno = -ENOTSUP; return 0; } - len = MIN(setup->wLength, net_buf_tailroom(buf)); net_buf_add_mem(buf, head, MIN(len, head->bLength)); return 0; } +static int sreq_get_desc_str(struct usbd_contex *const uds_ctx, + struct net_buf *const buf, const uint8_t idx) +{ + struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + struct usb_desc_header *head; + struct usbd_desc_node *d_nd; + size_t len; + + /* Get string descriptor */ + d_nd = usbd_get_descriptor(uds_ctx, USB_DESC_STRING, idx); + if (d_nd == NULL) { + errno = -ENOTSUP; + return 0; + } + + if (d_nd->idx == 0U) { + /* Language ID string descriptor */ + head = d_nd->desc; + len = MIN(setup->wLength, net_buf_tailroom(buf)); + net_buf_add_mem(buf, head, MIN(len, head->bLength)); + } else { + /* String descriptors in ASCII7 format */ + string_ascii7_to_utf16le(d_nd, buf, setup->wLength); + } + + return 0; +} + static int sreq_get_dev_qualifier(struct usbd_contex *const uds_ctx, struct net_buf *const buf) { @@ -617,13 +661,13 @@ static int sreq_get_descriptor(struct usbd_contex *const uds_ctx, switch (desc_type) { case USB_DESC_DEVICE: - return sreq_get_desc(uds_ctx, buf, USB_DESC_DEVICE, 0); + return sreq_get_desc_dev(uds_ctx, buf); case USB_DESC_CONFIGURATION: return sreq_get_desc_cfg(uds_ctx, buf, desc_idx, false); case USB_DESC_OTHER_SPEED: return sreq_get_desc_cfg(uds_ctx, buf, desc_idx, true); case USB_DESC_STRING: - return sreq_get_desc(uds_ctx, buf, USB_DESC_STRING, desc_idx); + return sreq_get_desc_str(uds_ctx, buf, desc_idx); case USB_DESC_DEVICE_QUALIFIER: return sreq_get_dev_qualifier(uds_ctx, buf); case USB_DESC_INTERFACE: diff --git a/subsys/usb/device_next/usbd_desc.c b/subsys/usb/device_next/usbd_desc.c index 1d91c188d42..70cfdec2456 100644 --- a/subsys/usb/device_next/usbd_desc.c +++ b/subsys/usb/device_next/usbd_desc.c @@ -17,54 +17,6 @@ #include LOG_MODULE_REGISTER(usbd_desc, CONFIG_USBD_LOG_LEVEL); -/* - * The last index of the initializer_string without null character is: - * ascii_idx_max = bLength / 2 - 2 - * Use this macro to determine the last index of ASCII7 string. - */ -#define USB_BSTRING_ASCII_IDX_MAX(n) (n / 2 - 2) - -/* - * The last index of the bString is: - * utf16le_idx_max = sizeof(initializer_string) * 2 - 2 - 1 - * utf16le_idx_max = bLength - 2 - 1 - * Use this macro to determine the last index of UTF16LE string. - */ -#define USB_BSTRING_UTF16LE_IDX_MAX(n) (n - 3) - -/** - * @brief Transform ASCII-7 string descriptor to UTF16-LE - * - * This function transforms ASCII-7 string descriptor - * into a UTF16-LE. - * - * @param[in] dn Pointer to descriptor node - */ -static void usbd_ascii7_to_utf16le(struct usbd_desc_node *const dn) -{ - struct usb_string_descriptor *desc = dn->desc; - int idx_max = USB_BSTRING_UTF16LE_IDX_MAX(desc->bLength); - int ascii_idx_max = USB_BSTRING_ASCII_IDX_MAX(desc->bLength); - uint8_t *buf = (uint8_t *)&desc->bString; - - LOG_DBG("idx_max %d, ascii_idx_max %d, buf %p", - idx_max, ascii_idx_max, buf); - - for (int i = idx_max; i >= 0; i -= 2) { - LOG_DBG("char %c : %x, idx %d -> %d", - buf[ascii_idx_max], - buf[ascii_idx_max], - ascii_idx_max, i); - __ASSERT(buf[ascii_idx_max] > 0x1F && buf[ascii_idx_max] < 0x7F, - "Only printable ascii-7 characters are allowed in USB " - "string descriptors"); - buf[i] = 0U; - buf[i - 1] = buf[ascii_idx_max--]; - } - - dn->utf16le = true; -} - /** * @brief Get common USB descriptor * @@ -171,8 +123,8 @@ static int desc_add_and_update_idx(struct usbd_contex *const uds_ctx, return 0; } -void *usbd_get_descriptor(struct usbd_contex *const uds_ctx, - const uint8_t type, const uint8_t idx) +struct usbd_desc_node *usbd_get_descriptor(struct usbd_contex *const uds_ctx, + const uint8_t type, const uint8_t idx) { struct usbd_desc_node *tmp; struct usb_desc_header *dh; @@ -180,7 +132,7 @@ void *usbd_get_descriptor(struct usbd_contex *const uds_ctx, SYS_DLIST_FOR_EACH_CONTAINER(&uds_ctx->descriptors, tmp, node) { dh = tmp->desc; if (tmp->idx == idx && dh->bDescriptorType == type) { - return tmp->desc; + return tmp; } } @@ -258,10 +210,6 @@ int usbd_add_descriptor(struct usbd_contex *const uds_ctx, default: break; } - - if (desc_nd->idx && !desc_nd->utf16le) { - usbd_ascii7_to_utf16le(desc_nd); - } } add_descriptor_error: diff --git a/subsys/usb/device_next/usbd_desc.h b/subsys/usb/device_next/usbd_desc.h index 0b3702206d2..623e92e90c4 100644 --- a/subsys/usb/device_next/usbd_desc.h +++ b/subsys/usb/device_next/usbd_desc.h @@ -10,18 +10,18 @@ #include /** - * @brief Get common USB descriptor + * @brief Get USB descriptor node * - * Get descriptor from internal descriptor list. + * Get descriptor node from internal descriptor list. * * @param[in] ctx Pointer to USB device support context * @param[in] type Descriptor type (bDescriptorType) * @param[in] idx Descriptor index * - * @return pointer to descriptor or NULL if not found. + * @return pointer to descriptor node or NULL if not found. */ -void *usbd_get_descriptor(struct usbd_contex *uds_ctx, - const uint8_t type, const uint8_t idx); +struct usbd_desc_node *usbd_get_descriptor(struct usbd_contex *const uds_ctx, + const uint8_t type, const uint8_t idx); /** * @brief Remove all descriptors from an USB device context