diff --git a/drivers/usb/udc/udc_common.c b/drivers/usb/udc/udc_common.c index b3b4db1719d..53ae5a3f407 100644 --- a/drivers/usb/udc/udc_common.c +++ b/drivers/usb/udc/udc_common.c @@ -262,7 +262,7 @@ static bool ep_check_config(const struct device *dev, return false; } - if (mps > cfg->caps.mps) { + if (USB_MPS_EP_SIZE(mps) > USB_MPS_EP_SIZE(cfg->caps.mps)) { return false; } @@ -273,12 +273,16 @@ static bool ep_check_config(const struct device *dev, } break; case USB_EP_TYPE_INTERRUPT: - if (!cfg->caps.interrupt) { + if (!cfg->caps.interrupt || + (USB_MPS_ADDITIONAL_TRANSACTIONS(mps) && + !cfg->caps.high_bandwidth)) { return false; } break; case USB_EP_TYPE_ISO: - if (!cfg->caps.iso) { + if (!cfg->caps.iso || + (USB_MPS_ADDITIONAL_TRANSACTIONS(mps) && + !cfg->caps.high_bandwidth)) { return false; } break; diff --git a/include/zephyr/drivers/usb/udc.h b/include/zephyr/drivers/usb/udc.h index 15f70a729a4..625d962c1bd 100644 --- a/include/zephyr/drivers/usb/udc.h +++ b/include/zephyr/drivers/usb/udc.h @@ -76,6 +76,8 @@ struct udc_ep_caps { uint32_t bulk : 1; /** ISO transfer capable endpoint */ uint32_t iso : 1; + /** High-Bandwidth (interrupt or iso) capable endpoint */ + uint32_t high_bandwidth : 1; /** IN transfer capable endpoint */ uint32_t in : 1; /** OUT transfer capable endpoint */ diff --git a/include/zephyr/usb/usb_ch9.h b/include/zephyr/usb/usb_ch9.h index dccc7445daa..ecd9705e88b 100644 --- a/include/zephyr/usb/usb_ch9.h +++ b/include/zephyr/usb/usb_ch9.h @@ -348,6 +348,29 @@ struct usb_association_descriptor { /** 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) +/** 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 } #endif diff --git a/subsys/usb/device_next/class/usbd_hid.c b/subsys/usb/device_next/class/usbd_hid.c index e11c7f1c1be..fe67f7e7850 100644 --- a/subsys/usb/device_next/class/usbd_hid.c +++ b/subsys/usb/device_next/class/usbd_hid.c @@ -742,6 +742,8 @@ static const struct hid_device_driver_api hid_device_api = { (USBD_HID_INTERFACE_ALTERNATE_DEFINE(n))) #define USBD_HID_INSTANCE_DEFINE(n) \ + HID_VERIFY_REPORT_SIZES(n); \ + \ NET_BUF_POOL_DEFINE(hid_buf_pool_in_##n, \ CONFIG_USBD_HID_IN_BUF_COUNT, 0, \ sizeof(struct udc_buf_info), NULL); \ diff --git a/subsys/usb/device_next/class/usbd_hid_macros.h b/subsys/usb/device_next/class/usbd_hid_macros.h index b0af92237bb..ac9dbdeb90b 100644 --- a/subsys/usb/device_next/class/usbd_hid_macros.h +++ b/subsys/usb/device_next/class/usbd_hid_macros.h @@ -153,7 +153,7 @@ */ #define HID_OUT_EP_MPS(n, 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)))) /* @@ -162,7 +162,7 @@ */ #define HID_IN_EP_MPS(n, 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)))) #define HID_OUT_EP_DEFINE(n, hs, alt) \ @@ -206,4 +206,10 @@ COND_CODE_1(DT_INST_NODE_HAS_PROP(n, out_report_size), \ (&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_ */ diff --git a/tests/drivers/udc/src/main.c b/tests/drivers/udc/src/main.c index d2babb427ec..66bf469cd79 100644 --- a/tests/drivers/udc/src/main.c +++ b/tests/drivers/udc/src/main.c @@ -197,7 +197,7 @@ static struct net_buf *test_udc_ep_buf_alloc(const struct device *dev, struct net_buf *buf; 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"); @@ -338,7 +338,7 @@ static void test_udc_ep_api(const struct device *dev, /* It needs a little reserve for memory management overhead. */ for (int n = 0; n < (CONFIG_UDC_BUF_COUNT - 4); n++) { 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 (%d) for 0x%02x", n, ed->bEndpointAddress);