diff --git a/drivers/usb/udc/udc_dwc2.c b/drivers/usb/udc/udc_dwc2.c index eb7368e1178f..769030670918 100644 --- a/drivers/usb/udc/udc_dwc2.c +++ b/drivers/usb/udc/udc_dwc2.c @@ -2328,6 +2328,7 @@ static int udc_dwc2_disable(const struct device *dev) } config->irq_disable_func(dev); + cancel_hibernation_request(priv); if (priv->hibernated) { dwc2_exit_hibernation(dev, false, true); diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index d4afb34e7664..953182096580 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -287,6 +287,10 @@ struct usbd_context { const struct device *dev; /** Notification message recipient callback */ usbd_msg_cb_t msg_cb; + /** slist to keep endpoint events */ + sys_slist_t ep_events; + /** Endpoint event list spinlock */ + struct k_spinlock ep_event_lock; /** Middle layer runtime data */ struct usbd_ch9_data ch9_data; /** slist to manage descriptors like string, BOS */ diff --git a/subsys/usb/device_next/usbd_core.c b/subsys/usb/device_next/usbd_core.c index 9f24530fc2c2..a802d74028a2 100644 --- a/subsys/usb/device_next/usbd_core.c +++ b/subsys/usb/device_next/usbd_core.c @@ -34,29 +34,53 @@ K_MSGQ_DEFINE(usbd_msgq, sizeof(struct udc_event), static int usbd_event_carrier(const struct device *dev, const struct udc_event *const event) { + struct usbd_context *const uds_ctx = (void *)udc_get_event_ctx(dev); + k_spinlock_key_t key; + + if (event->type == UDC_EVT_EP_REQUEST) { + /* + * Always add completed transfer requests to the list, so they + * do not get lost. + */ + key = k_spin_lock(&uds_ctx->ep_event_lock); + sys_slist_append(&uds_ctx->ep_events, &event->buf->node); + k_spin_unlock(&uds_ctx->ep_event_lock, key); + } + return k_msgq_put(&usbd_msgq, event, K_NO_WAIT); } -static int event_handler_ep_request(struct usbd_context *const uds_ctx, - const struct udc_event *const event) +static void event_handler_ep_request(struct usbd_context *const uds_ctx) { struct udc_buf_info *bi; + k_spinlock_key_t key; + struct net_buf *buf; + sys_snode_t *node; int ret; - bi = udc_get_buf_info(event->buf); + while (!sys_slist_is_empty(&uds_ctx->ep_events)) { + key = k_spin_lock(&uds_ctx->ep_event_lock); + node = sys_slist_get(&uds_ctx->ep_events); + k_spin_unlock(&uds_ctx->ep_event_lock, key); - if (USB_EP_GET_IDX(bi->ep) == 0) { - ret = usbd_handle_ctrl_xfer(uds_ctx, event->buf, bi->err); - } else { - ret = usbd_class_handle_xfer(uds_ctx, event->buf, bi->err); - } + buf = SYS_SLIST_CONTAINER(node, buf, node); + if (buf == NULL) { + break; + } - if (ret) { - LOG_ERR("unrecoverable error %d, ep 0x%02x, buf %p", - ret, bi->ep, event->buf); - } + bi = udc_get_buf_info(buf); + if (USB_EP_GET_IDX(bi->ep) == 0) { + ret = usbd_handle_ctrl_xfer(uds_ctx, buf, bi->err); + } else { + ret = usbd_class_handle_xfer(uds_ctx, buf, bi->err); + } - return ret; + if (ret) { + LOG_ERR("Unrecoverable error %d, ep 0x%02x, buf %p", + ret, bi->ep, (void *)buf); + usbd_msg_pub_simple(uds_ctx, USBD_MSG_STACK_ERROR, ret); + } + } } static void usbd_class_bcast_event(struct usbd_context *const uds_ctx, @@ -138,6 +162,13 @@ static ALWAYS_INLINE void usbd_event_handler(struct usbd_context *const uds_ctx, { int err = 0; + /* Always check if there is a completed transfer request. */ + event_handler_ep_request(uds_ctx); + if (event->type == UDC_EVT_EP_REQUEST) { + /* It has already been handled and cannot be another event type. */ + return; + } + switch (event->type) { case UDC_EVT_VBUS_REMOVED: LOG_DBG("VBUS remove event"); @@ -167,9 +198,6 @@ static ALWAYS_INLINE void usbd_event_handler(struct usbd_context *const uds_ctx, err = event_handler_bus_reset(uds_ctx); usbd_msg_pub_simple(uds_ctx, USBD_MSG_RESET, 0); break; - case UDC_EVT_EP_REQUEST: - err = event_handler_ep_request(uds_ctx, event); - break; case UDC_EVT_ERROR: LOG_ERR("UDC error event"); usbd_msg_pub_simple(uds_ctx, USBD_MSG_UDC_ERROR, event->status);