usb: device_next: convert ASCII7 strings to UTF16LE on the fly
This is slower but should have no real effect. In the future we can support more than ASCII7 format and store it in other memory areas. Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
committed by
Fabio Baltieri
parent
f110766072
commit
2f31ee63b5
@@ -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:
|
||||
|
||||
@@ -17,54 +17,6 @@
|
||||
#include <zephyr/logging/log.h>
|
||||
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:
|
||||
|
||||
@@ -10,18 +10,18 @@
|
||||
#include <zephyr/usb/usbd.h>
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
||||
Reference in New Issue
Block a user