From b0d7d70834ab13e0ae9115436ead908545b2b410 Mon Sep 17 00:00:00 2001 From: Johann Fischer Date: Tue, 30 Apr 2024 18:24:40 +0200 Subject: [PATCH] usb: device_next: add initial BOS support Use the same scheme as for string descriptors. Descriptors can be added or removed using the existend interface. Signed-off-by: Johann Fischer --- include/zephyr/usb/usbd.h | 39 +++++++++++++++++++-- subsys/usb/device_next/usbd_ch9.c | 56 ++++++++++++++++++++++++++++++ subsys/usb/device_next/usbd_desc.c | 29 ++++++++++++---- 3 files changed, 114 insertions(+), 10 deletions(-) diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index 9c272cdeadd..6d697c88869 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -15,6 +15,7 @@ #define ZEPHYR_INCLUDE_USBD_H_ #include +#include #include #include #include @@ -69,6 +70,9 @@ enum usbd_str_desc_utype { USBD_DUT_STRING_INTERFACE, }; +enum usbd_bos_desc_utype { + USBD_DUT_BOS_NONE, +}; /** @endcond */ /** @@ -85,17 +89,26 @@ struct usbd_str_desc_data { unsigned int use_hwinfo : 1; }; +/** + * USBD BOS Device Capability descriptor data + */ +struct usbd_bos_desc_data { + /** Descriptor usage type (not bDescriptorType) */ + enum usbd_bos_desc_utype utype : 8; +}; + /** * Descriptor node * * Descriptor node is used to manage descriptors that are not - * directly part of a structure, such as string or bos descriptors. + * directly part of a structure, such as string or BOS capability descriptors. */ struct usbd_desc_node { /** slist node struct */ sys_dnode_t node; union { struct usbd_str_desc_data str; + struct usbd_bos_desc_data bos; }; /** Opaque pointer to a descriptor payload */ const void *const ptr; @@ -219,7 +232,7 @@ struct usbd_contex { usbd_msg_cb_t msg_cb; /** Middle layer runtime data */ struct usbd_ch9_data ch9_data; - /** slist to manage descriptors like string, bos */ + /** slist to manage descriptors like string, BOS */ sys_dlist_t descriptors; /** slist to manage Full-Speed device configurations */ sys_slist_t fs_configs; @@ -530,6 +543,26 @@ static inline void *usbd_class_get_private(const struct usbd_class_data *const c .bDescriptorType = USB_DESC_STRING, \ } +/** + * @brief Define BOS Device Capability descriptor node + * + * The application defines a BOS capability descriptor node for descriptors + * such as USB 2.0 Extension Descriptor. + * + * @param name Descriptor node identifier + * @param len Device Capability descriptor length + * @param subset Pointer to a Device Capability descriptor + */ +#define USBD_DESC_BOS_DEFINE(name, len, subset) \ + static struct usbd_desc_node name = { \ + .bos = { \ + .utype = USBD_DUT_BOS_NONE, \ + }, \ + .ptr = subset, \ + .bLength = len, \ + .bDescriptorType = USB_DESC_BOS, \ + } + #define USBD_DEFINE_CLASS(class_name, class_api, class_priv, class_v_reqs) \ static struct usbd_class_data class_name = { \ .name = STRINGIFY(class_name), \ @@ -569,7 +602,7 @@ static inline void *usbd_class_get_private(const struct usbd_class_data *const c /** * @brief Add common USB descriptor * - * Add common descriptor like string or bos. + * Add common descriptor like string or BOS Device Capability. * * @param[in] uds_ctx Pointer to USB device support context * @param[in] dn Pointer to USB descriptor node diff --git a/subsys/usb/device_next/usbd_ch9.c b/subsys/usb/device_next/usbd_ch9.c index aa6e3851312..8e7db0b756e 100644 --- a/subsys/usb/device_next/usbd_ch9.c +++ b/subsys/usb/device_next/usbd_ch9.c @@ -691,6 +691,60 @@ static int sreq_get_dev_qualifier(struct usbd_contex *const uds_ctx, return 0; } +static void desc_fill_bos_root(struct usbd_contex *const uds_ctx, + struct usb_bos_descriptor *const root) +{ + struct usbd_desc_node *desc_nd; + + root->bLength = sizeof(struct usb_bos_descriptor); + root->bDescriptorType = USB_DESC_BOS; + root->wTotalLength = root->bLength; + + SYS_DLIST_FOR_EACH_CONTAINER(&uds_ctx->descriptors, desc_nd, node) { + if (desc_nd->bDescriptorType == USB_DESC_BOS) { + root->wTotalLength += desc_nd->bLength; + root->bNumDeviceCaps += desc_nd->bLength; + } + } +} + +static int sreq_get_desc_bos(struct usbd_contex *const uds_ctx, + struct net_buf *const buf) +{ + struct usb_setup_packet *setup = usbd_get_setup_pkt(uds_ctx); + struct usb_bos_descriptor bos; + struct usbd_desc_node *desc_nd; + size_t len; + + desc_fill_bos_root(uds_ctx, &bos); + len = MIN(net_buf_tailroom(buf), MIN(setup->wLength, bos.wTotalLength)); + + LOG_DBG("wLength %u, bLength %u, wTotalLength %u, tailroom %u", + setup->wLength, bos.bLength, bos.wTotalLength, net_buf_tailroom(buf)); + + net_buf_add_mem(buf, &bos, MIN(len, bos.bLength)); + + len -= MIN(len, sizeof(bos)); + if (len == 0) { + return 0; + } + + SYS_DLIST_FOR_EACH_CONTAINER(&uds_ctx->descriptors, desc_nd, node) { + if (desc_nd->bDescriptorType == USB_DESC_BOS) { + LOG_DBG("bLength %u, len %u, tailroom %u", + desc_nd->bLength, len, net_buf_tailroom(buf)); + net_buf_add_mem(buf, desc_nd->ptr, MIN(len, desc_nd->bLength)); + + len -= MIN(len, desc_nd->bLength); + if (len == 0) { + break; + } + } + } + + return 0; +} + static int sreq_get_descriptor(struct usbd_contex *const uds_ctx, struct net_buf *const buf) { @@ -722,6 +776,8 @@ static int sreq_get_descriptor(struct usbd_contex *const uds_ctx, 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_BOS: + return sreq_get_desc_bos(uds_ctx, buf); case USB_DESC_INTERFACE: case USB_DESC_ENDPOINT: default: diff --git a/subsys/usb/device_next/usbd_desc.c b/subsys/usb/device_next/usbd_desc.c index efc9c217dbe..ecc8e57259a 100644 --- a/subsys/usb/device_next/usbd_desc.c +++ b/subsys/usb/device_next/usbd_desc.c @@ -86,8 +86,16 @@ struct usbd_desc_node *usbd_get_descriptor(struct usbd_contex *const uds_ctx, struct usbd_desc_node *desc_nd; SYS_DLIST_FOR_EACH_CONTAINER(&uds_ctx->descriptors, desc_nd, node) { - if (desc_nd->str.idx == idx && desc_nd->bDescriptorType == type) { - return desc_nd; + if (desc_nd->bDescriptorType == type) { + if (desc_nd->bDescriptorType == USB_DESC_STRING) { + if (desc_nd->str.idx == idx) { + return desc_nd; + } + } + + if (desc_nd->bDescriptorType == USB_DESC_BOS) { + return desc_nd; + } } } @@ -133,13 +141,17 @@ int usbd_add_descriptor(struct usbd_contex *const uds_ctx, goto add_descriptor_error; } - ret = desc_add_and_update_idx(uds_ctx, desc_nd); - if (ret) { - ret = -EINVAL; - goto add_descriptor_error; + if (desc_nd->bDescriptorType == USB_DESC_BOS) { + sys_dlist_append(&uds_ctx->descriptors, &desc_nd->node); } if (desc_nd->bDescriptorType == USB_DESC_STRING) { + ret = desc_add_and_update_idx(uds_ctx, desc_nd); + if (ret) { + ret = -EINVAL; + goto add_descriptor_error; + } + switch (desc_nd->str.utype) { case USBD_DUT_STRING_LANG: break; @@ -178,6 +190,9 @@ void usbd_remove_descriptor(struct usbd_desc_node *const desc_nd) { if (sys_dnode_is_linked(&desc_nd->node)) { sys_dlist_remove(&desc_nd->node); - desc_nd->str.idx = 0; + + if (desc_nd->bDescriptorType == USB_DESC_STRING) { + desc_nd->str.idx = 0U; + } } }