diff --git a/drivers/usb/udc/udc_common.c b/drivers/usb/udc/udc_common.c index 009fb085a5d..c152d4a71b0 100644 --- a/drivers/usb/udc/udc_common.c +++ b/drivers/usb/udc/udc_common.c @@ -770,13 +770,14 @@ udc_disable_error: return ret; } -int udc_init(const struct device *dev, udc_event_cb_t event_cb) +int udc_init(const struct device *dev, + udc_event_cb_t event_cb, const void *const event_ctx) { const struct udc_api *api = dev->api; struct udc_data *data = dev->data; int ret; - if (event_cb == NULL) { + if (event_cb == NULL || event_ctx == NULL) { return -EINVAL; } @@ -788,6 +789,7 @@ int udc_init(const struct device *dev, udc_event_cb_t event_cb) } data->event_cb = event_cb; + data->event_ctx = event_ctx; ret = api->init(dev); if (ret == 0) { diff --git a/include/zephyr/drivers/usb/udc.h b/include/zephyr/drivers/usb/udc.h index 7d7c8ee07c5..15f70a729a4 100644 --- a/include/zephyr/drivers/usb/udc.h +++ b/include/zephyr/drivers/usb/udc.h @@ -277,8 +277,10 @@ struct udc_data { struct udc_device_caps caps; /** Driver access mutex */ struct k_mutex mutex; - /** Callback to submit an UDC event to upper layer */ + /** Callback to submit an UDC event to higher layer */ udc_event_cb_t event_cb; + /** Opaque pointer to store higher layer context */ + const void *event_ctx; /** USB device controller status */ atomic_t status; /** Internal used Control Sequence Stage */ @@ -345,14 +347,16 @@ static inline bool udc_is_suspended(const struct device *dev) * After initialization controller driver should be able to detect * power state of the bus and signal power state changes. * - * @param[in] dev Pointer to device struct of the driver instance - * @param[in] event_cb Event callback from the higher layer (USB device stack) + * @param[in] dev Pointer to device struct of the driver instance + * @param[in] event_cb Event callback from the higher layer (USB device stack) + * @param[in] event_ctx Opaque pointer to higher layer context * * @return 0 on success, all other values should be treated as error. * @retval -EINVAL on parameter error (no callback is passed) * @retval -EALREADY already initialized */ -int udc_init(const struct device *dev, udc_event_cb_t event_cb); +int udc_init(const struct device *dev, + udc_event_cb_t event_cb, const void *const event_ctx); /** * @brief Enable USB device controller @@ -702,6 +706,24 @@ static inline struct udc_buf_info *udc_get_buf_info(const struct net_buf *const return (struct udc_buf_info *)net_buf_user_data(buf); } + +/** + * @brief Get pointer to higher layer context + * + * The address of the context is passed as an argument to the udc_init() + * function and is stored in the UDC data. + * + * @param[in] dev Pointer to device struct of the driver instance + * + * @return Opaque pointer to higher layer context + */ +static inline const void *udc_get_event_ctx(const struct device *dev) +{ + struct udc_data *data = dev->data; + + return data->event_ctx; +} + /** * @} */ diff --git a/subsys/usb/device_next/usbd_core.c b/subsys/usb/device_next/usbd_core.c index 4bdebd6fc68..e6f1cf1faee 100644 --- a/subsys/usb/device_next/usbd_core.c +++ b/subsys/usb/device_next/usbd_core.c @@ -187,16 +187,16 @@ static void usbd_thread(void *p1, void *p2, void *p3) ARG_UNUSED(p2); ARG_UNUSED(p3); + struct usbd_context *uds_ctx; struct udc_event event; while (true) { k_msgq_get(&usbd_msgq, &event, K_FOREVER); - STRUCT_SECTION_FOREACH(usbd_context, uds_ctx) { - if (uds_ctx->dev == event.dev) { - usbd_event_handler(uds_ctx, &event); - } - } + uds_ctx = (void *)udc_get_event_ctx(event.dev); + __ASSERT(uds_ctx != NULL && usbd_is_initialized(uds_ctx), + "USB device is not initialized"); + usbd_event_handler(uds_ctx, &event); } } @@ -204,7 +204,7 @@ int usbd_device_init_core(struct usbd_context *const uds_ctx) { int ret; - ret = udc_init(uds_ctx->dev, usbd_event_carrier); + ret = udc_init(uds_ctx->dev, usbd_event_carrier, uds_ctx); if (ret != 0) { LOG_ERR("Failed to init device driver"); return ret; diff --git a/tests/drivers/udc/src/main.c b/tests/drivers/udc/src/main.c index 97abbbd7448..64298b1508c 100644 --- a/tests/drivers/udc/src/main.c +++ b/tests/drivers/udc/src/main.c @@ -24,6 +24,7 @@ static K_KERNEL_STACK_DEFINE(test_udc_stack, 512); static struct k_thread test_udc_thread_data; static K_SEM_DEFINE(ep_queue_sem, 0, 1); static uint8_t last_used_ep; +static uint8_t test_event_ctx; static int test_udc_event_handler(const struct device *dev, const struct udc_event *const event) @@ -57,6 +58,9 @@ static void test_udc_thread(void *p1, void *p2, void *p3) while (true) { k_msgq_get(&test_msgq, &event, K_FOREVER); + zassert_equal(udc_get_event_ctx(event.dev), &test_event_ctx, + "Wrong pointer to higher layer context"); + switch (event.type) { case UDC_EVT_VBUS_REMOVED: LOG_DBG("VBUS remove event"); @@ -368,7 +372,7 @@ static void test_udc_ep_mps(uint8_t type) dev = DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)); zassert_true(device_is_ready(dev), "UDC device not ready"); - err = udc_init(dev, test_udc_event_handler); + err = udc_init(dev, test_udc_event_handler, &test_event_ctx); zassert_ok(err, "Failed to initialize UDC driver"); err = udc_enable(dev); @@ -476,7 +480,7 @@ ZTEST(udc_driver_test, test_udc_not_initialized) dev = DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)); zassert_true(device_is_ready(dev), "UDC device not ready"); - err = udc_init(dev, NULL); + err = udc_init(dev, NULL, NULL); zassert_equal(err, -EINVAL, "Not failed to initialize UDC"); err = udc_shutdown(dev); @@ -515,7 +519,7 @@ ZTEST(udc_driver_test, test_udc_initialized) dev = DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)); zassert_true(device_is_ready(dev), "UDC device not ready"); - err = udc_init(dev, test_udc_event_handler); + err = udc_init(dev, test_udc_event_handler, &test_event_ctx); zassert_ok(err, "Failed to initialize UDC driver"); test_udc_set_address(dev, 0); @@ -548,7 +552,7 @@ ZTEST(udc_driver_test, test_udc_enabled) dev = DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)); zassert_true(device_is_ready(dev), "UDC device not ready"); - err = udc_init(dev, test_udc_event_handler); + err = udc_init(dev, test_udc_event_handler, &test_event_ctx); zassert_ok(err, "Failed to initialize UDC driver"); err = udc_enable(dev);