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 <johann.fischer@nordicsemi.no>
This commit is contained in:
Johann Fischer
2024-04-30 18:24:40 +02:00
committed by Fabio Baltieri
parent 29003ff264
commit b0d7d70834
3 changed files with 114 additions and 10 deletions

View File

@@ -15,6 +15,7 @@
#define ZEPHYR_INCLUDE_USBD_H_
#include <zephyr/device.h>
#include <zephyr/usb/bos.h>
#include <zephyr/usb/usb_ch9.h>
#include <zephyr/usb/usbd_msg.h>
#include <zephyr/net/buf.h>
@@ -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

View File

@@ -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:

View File

@@ -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;
}
}
}