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:
committed by
Fabio Baltieri
parent
29003ff264
commit
b0d7d70834
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user