usb: device_next: Make stack High-Bandwidth aware

Add macros for converting between Max Packet Size and total payload
length. Allow drivers specify whether endpoint supports high-bandwidth
interrupt and high-bandwidth isochronous transfers.

Signed-off-by: Tomasz Moń <tomasz.mon@nordicsemi.no>
This commit is contained in:
Tomasz Moń 2024-07-19 08:33:08 +02:00 committed by Fabio Baltieri
commit b7664f27c8
6 changed files with 44 additions and 7 deletions

View file

@ -262,7 +262,7 @@ static bool ep_check_config(const struct device *dev,
return false; return false;
} }
if (mps > cfg->caps.mps) { if (USB_MPS_EP_SIZE(mps) > USB_MPS_EP_SIZE(cfg->caps.mps)) {
return false; return false;
} }
@ -273,12 +273,16 @@ static bool ep_check_config(const struct device *dev,
} }
break; break;
case USB_EP_TYPE_INTERRUPT: case USB_EP_TYPE_INTERRUPT:
if (!cfg->caps.interrupt) { if (!cfg->caps.interrupt ||
(USB_MPS_ADDITIONAL_TRANSACTIONS(mps) &&
!cfg->caps.high_bandwidth)) {
return false; return false;
} }
break; break;
case USB_EP_TYPE_ISO: case USB_EP_TYPE_ISO:
if (!cfg->caps.iso) { if (!cfg->caps.iso ||
(USB_MPS_ADDITIONAL_TRANSACTIONS(mps) &&
!cfg->caps.high_bandwidth)) {
return false; return false;
} }
break; break;

View file

@ -76,6 +76,8 @@ struct udc_ep_caps {
uint32_t bulk : 1; uint32_t bulk : 1;
/** ISO transfer capable endpoint */ /** ISO transfer capable endpoint */
uint32_t iso : 1; uint32_t iso : 1;
/** High-Bandwidth (interrupt or iso) capable endpoint */
uint32_t high_bandwidth : 1;
/** IN transfer capable endpoint */ /** IN transfer capable endpoint */
uint32_t in : 1; uint32_t in : 1;
/** OUT transfer capable endpoint */ /** OUT transfer capable endpoint */

View file

@ -348,6 +348,29 @@ struct usb_association_descriptor {
/** Calculate high speed isochronous endpoint bInterval from a value in microseconds */ /** Calculate high speed isochronous endpoint bInterval from a value in microseconds */
#define USB_HS_ISO_EP_INTERVAL(us) CLAMP((ilog2((us) / 125U) + 1U), 1U, 16U) #define USB_HS_ISO_EP_INTERVAL(us) CLAMP((ilog2((us) / 125U) + 1U), 1U, 16U)
/** Get endpoint size field from Max Packet Size value */
#define USB_MPS_EP_SIZE(mps) ((mps) & BIT_MASK(11))
/** Get number of additional transactions per microframe from Max Packet Size value */
#define USB_MPS_ADDITIONAL_TRANSACTIONS(mps) (((mps) & 0x1800) >> 11)
/** Calculate total payload length from Max Packet Size value */
#define USB_MPS_TO_TPL(mps) \
((1 + USB_MPS_ADDITIONAL_TRANSACTIONS(mps)) * USB_MPS_EP_SIZE(mps))
/** Calculate Max Packet Size value from total payload length */
#define USB_TPL_TO_MPS(tpl) \
(((tpl) > 2048) ? ((2 << 11) | ((tpl) / 3)) : \
((tpl) > 1024) ? ((1 << 11) | ((tpl) / 2)) : \
(tpl))
/** Determine whether total payload length value is valid according to USB 2.0 */
#define USB_TPL_IS_VALID(tpl) \
(((tpl) > 3072) ? false : \
((tpl) > 2048) ? ((tpl) % 3 == 0) : \
((tpl) > 1024) ? ((tpl) % 2 == 0) : \
((tpl) >= 0))
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -742,6 +742,8 @@ static const struct hid_device_driver_api hid_device_api = {
(USBD_HID_INTERFACE_ALTERNATE_DEFINE(n))) (USBD_HID_INTERFACE_ALTERNATE_DEFINE(n)))
#define USBD_HID_INSTANCE_DEFINE(n) \ #define USBD_HID_INSTANCE_DEFINE(n) \
HID_VERIFY_REPORT_SIZES(n); \
\
NET_BUF_POOL_DEFINE(hid_buf_pool_in_##n, \ NET_BUF_POOL_DEFINE(hid_buf_pool_in_##n, \
CONFIG_USBD_HID_IN_BUF_COUNT, 0, \ CONFIG_USBD_HID_IN_BUF_COUNT, 0, \
sizeof(struct udc_buf_info), NULL); \ sizeof(struct udc_buf_info), NULL); \

View file

@ -153,7 +153,7 @@
*/ */
#define HID_OUT_EP_MPS(n, alt) \ #define HID_OUT_EP_MPS(n, alt) \
COND_CODE_1(alt, \ COND_CODE_1(alt, \
(sys_cpu_to_le16(DT_INST_PROP(n, out_report_size))), \ (sys_cpu_to_le16(USB_TPL_TO_MPS(DT_INST_PROP(n, out_report_size)))), \
(sys_cpu_to_le16(MIN(DT_INST_PROP(n, out_report_size), 64U)))) (sys_cpu_to_le16(MIN(DT_INST_PROP(n, out_report_size), 64U))))
/* /*
@ -162,7 +162,7 @@
*/ */
#define HID_IN_EP_MPS(n, alt) \ #define HID_IN_EP_MPS(n, alt) \
COND_CODE_1(alt, \ COND_CODE_1(alt, \
(sys_cpu_to_le16(DT_INST_PROP(n, in_report_size))), \ (sys_cpu_to_le16(USB_TPL_TO_MPS(DT_INST_PROP(n, in_report_size)))), \
(sys_cpu_to_le16(MIN(DT_INST_PROP(n, in_report_size), 64U)))) (sys_cpu_to_le16(MIN(DT_INST_PROP(n, in_report_size), 64U))))
#define HID_OUT_EP_DEFINE(n, hs, alt) \ #define HID_OUT_EP_DEFINE(n, hs, alt) \
@ -206,4 +206,10 @@
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), \ COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), \
(&hid_buf_pool_out_##n), (NULL)) (&hid_buf_pool_out_##n), (NULL))
#define HID_VERIFY_REPORT_SIZES(n) \
BUILD_ASSERT(USB_TPL_IS_VALID(DT_INST_PROP_OR(n, out_report_size, 0)), \
"out-report-size must be valid Total Packet Length"); \
BUILD_ASSERT(USB_TPL_IS_VALID(DT_INST_PROP_OR(n, in_report_size, 0)), \
"in-report-size must be valid Total Packet Length");
#endif /* ZEPHYR_USB_DEVICE_CLASS_HID_MACROS_H_ */ #endif /* ZEPHYR_USB_DEVICE_CLASS_HID_MACROS_H_ */

View file

@ -197,7 +197,7 @@ static struct net_buf *test_udc_ep_buf_alloc(const struct device *dev,
struct net_buf *buf; struct net_buf *buf;
buf = udc_ep_buf_alloc(dev, ed->bEndpointAddress, buf = udc_ep_buf_alloc(dev, ed->bEndpointAddress,
sys_le16_to_cpu(ed->wMaxPacketSize)); USB_MPS_TO_TPL(sys_le16_to_cpu(ed->wMaxPacketSize)));
zassert_not_null(buf, "Failed to allocate request"); zassert_not_null(buf, "Failed to allocate request");
@ -338,7 +338,7 @@ static void test_udc_ep_api(const struct device *dev,
/* It needs a little reserve for memory management overhead. */ /* It needs a little reserve for memory management overhead. */
for (int n = 0; n < (CONFIG_UDC_BUF_COUNT - 4); n++) { for (int n = 0; n < (CONFIG_UDC_BUF_COUNT - 4); n++) {
buf = udc_ep_buf_alloc(dev, ed->bEndpointAddress, buf = udc_ep_buf_alloc(dev, ed->bEndpointAddress,
sys_le16_to_cpu(ed->wMaxPacketSize)); USB_MPS_TO_TPL(sys_le16_to_cpu(ed->wMaxPacketSize)));
zassert_not_null(buf, zassert_not_null(buf,
"Failed to allocate request (%d) for 0x%02x", "Failed to allocate request (%d) for 0x%02x",
n, ed->bEndpointAddress); n, ed->bEndpointAddress);