diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h index 6d697c88869f9..b72127b69838b 100644 --- a/include/zephyr/usb/usbd.h +++ b/include/zephyr/usb/usbd.h @@ -226,6 +226,8 @@ struct usbd_contex { const char *name; /** Access mutex */ struct k_mutex mutex; + /** Remote wakeup semaphore */ + struct k_sem rwup_sem; /** Pointer to UDC device */ const struct device *dev; /** Notification message recipient callback */ diff --git a/subsys/usb/device_next/class/usbd_cdc_acm.c b/subsys/usb/device_next/class/usbd_cdc_acm.c index 838550f18dd71..7b26854ce7954 100644 --- a/subsys/usb/device_next/class/usbd_cdc_acm.c +++ b/subsys/usb/device_next/class/usbd_cdc_acm.c @@ -41,12 +41,13 @@ NET_BUF_POOL_FIXED_DEFINE(cdc_acm_ep_pool, #define CDC_ACM_FS_INT_EP_INTERVAL USB_FS_INT_EP_INTERVAL(10000U) #define CDC_ACM_HS_INT_EP_INTERVAL USB_HS_INT_EP_INTERVAL(10000U) -#define CDC_ACM_CLASS_ENABLED 0 -#define CDC_ACM_CLASS_SUSPENDED 1 -#define CDC_ACM_IRQ_RX_ENABLED 2 -#define CDC_ACM_IRQ_TX_ENABLED 3 -#define CDC_ACM_RX_FIFO_BUSY 4 -#define CDC_ACM_LOCK 5 +enum { + CDC_ACM_CLASS_ENABLED, + CDC_ACM_IRQ_RX_ENABLED, + CDC_ACM_IRQ_TX_ENABLED, + CDC_ACM_RX_FIFO_BUSY, + CDC_ACM_LOCK, +}; static struct k_work_q cdc_acm_work_q; static K_KERNEL_STACK_DEFINE(cdc_acm_stack, @@ -278,25 +279,21 @@ static void usbd_cdc_acm_disable(struct usbd_class_data *const c_data) struct cdc_acm_uart_data *data = dev->data; atomic_clear_bit(&data->state, CDC_ACM_CLASS_ENABLED); - atomic_clear_bit(&data->state, CDC_ACM_CLASS_SUSPENDED); LOG_INF("Configuration disabled"); } static void usbd_cdc_acm_suspended(struct usbd_class_data *const c_data) { const struct device *dev = usbd_class_get_private(c_data); - struct cdc_acm_uart_data *data = dev->data; - /* FIXME: filter stray suspended events earlier */ - atomic_set_bit(&data->state, CDC_ACM_CLASS_SUSPENDED); + LOG_DBG("CDC ACM device %s suspended", dev->name); } static void usbd_cdc_acm_resumed(struct usbd_class_data *const c_data) { const struct device *dev = usbd_class_get_private(c_data); - struct cdc_acm_uart_data *data = dev->data; - atomic_clear_bit(&data->state, CDC_ACM_CLASS_SUSPENDED); + LOG_DBG("CDC ACM device %s resumed", dev->name); } static void *usbd_cdc_acm_get_desc(struct usbd_class_data *const c_data, @@ -485,11 +482,6 @@ static int cdc_acm_send_notification(const struct device *dev, return -EACCES; } - if (atomic_test_bit(&data->state, CDC_ACM_CLASS_SUSPENDED)) { - LOG_INF("USB support is suspended (FIXME)"); - return -EACCES; - } - ep = cdc_acm_get_int_in(c_data); buf = usbd_ep_buf_alloc(c_data, ep, sizeof(struct cdc_acm_notification)); if (buf == NULL) { @@ -498,10 +490,14 @@ static int cdc_acm_send_notification(const struct device *dev, net_buf_add_mem(buf, ¬ification, sizeof(struct cdc_acm_notification)); ret = usbd_ep_enqueue(c_data, buf); - /* FIXME: support for sync transfers */ + if (ret) { + net_buf_unref(buf); + return ret; + } + k_sem_take(&data->notif_sem, K_FOREVER); - return ret; + return 0; } /* @@ -523,11 +519,6 @@ static void cdc_acm_tx_fifo_handler(struct k_work *work) return; } - if (atomic_test_bit(&data->state, CDC_ACM_CLASS_SUSPENDED)) { - LOG_INF("USB support is suspended (FIXME: submit rwup)"); - return; - } - if (atomic_test_and_set_bit(&data->state, CDC_ACM_LOCK)) { cdc_acm_work_submit(&data->tx_fifo_work); return; @@ -558,7 +549,6 @@ static void cdc_acm_tx_fifo_handler(struct k_work *work) * - (x) RX transfer completion * - (x) the end of cdc_acm_irq_cb_handler * - (x) USBD class API enable call - * - ( ) USBD class API resumed call (TODO) */ static void cdc_acm_rx_fifo_handler(struct k_work *work) { @@ -571,9 +561,8 @@ static void cdc_acm_rx_fifo_handler(struct k_work *work) data = CONTAINER_OF(work, struct cdc_acm_uart_data, rx_fifo_work); c_data = data->c_data; - if (!atomic_test_bit(&data->state, CDC_ACM_CLASS_ENABLED) || - atomic_test_bit(&data->state, CDC_ACM_CLASS_SUSPENDED)) { - LOG_INF("USB configuration is not enabled or suspended"); + if (!atomic_test_bit(&data->state, CDC_ACM_CLASS_ENABLED)) { + LOG_INF("USB configuration is not enabled"); return; } diff --git a/subsys/usb/device_next/class/usbd_cdc_ecm.c b/subsys/usb/device_next/class/usbd_cdc_ecm.c index 7b3305bf34385..0c2368636dbdb 100644 --- a/subsys/usb/device_next/class/usbd_cdc_ecm.c +++ b/subsys/usb/device_next/class/usbd_cdc_ecm.c @@ -28,7 +28,6 @@ LOG_MODULE_REGISTER(cdc_ecm, CONFIG_USBD_CDC_ECM_LOG_LEVEL); enum { CDC_ECM_IFACE_UP, CDC_ECM_CLASS_ENABLED, - CDC_ECM_CLASS_SUSPENDED, CDC_ECM_OUT_ENGAGED, }; @@ -334,11 +333,6 @@ static int cdc_ecm_send_notification(const struct device *dev, return 0; } - if (atomic_test_bit(&data->state, CDC_ECM_CLASS_SUSPENDED)) { - LOG_INF("USB device is suspended (FIXME)"); - return 0; - } - ep = cdc_ecm_get_int_in(c_data); buf = usbd_ep_buf_alloc(c_data, ep, sizeof(struct cdc_ecm_notification)); if (buf == NULL) { @@ -401,24 +395,21 @@ static void usbd_cdc_ecm_disable(struct usbd_class_data *const c_data) net_if_carrier_off(data->iface); } - atomic_clear_bit(&data->state, CDC_ECM_CLASS_SUSPENDED); LOG_INF("Configuration disabled"); } static void usbd_cdc_ecm_suspended(struct usbd_class_data *const c_data) { const struct device *dev = usbd_class_get_private(c_data); - struct cdc_ecm_eth_data *data = dev->data; - atomic_set_bit(&data->state, CDC_ECM_CLASS_SUSPENDED); + LOG_DBG("CDC ECM device %s suspended", dev->name); } static void usbd_cdc_ecm_resumed(struct usbd_class_data *const c_data) { const struct device *dev = usbd_class_get_private(c_data); - struct cdc_ecm_eth_data *data = dev->data; - atomic_clear_bit(&data->state, CDC_ECM_CLASS_SUSPENDED); + LOG_DBG("CDC ECM device %s resumed", dev->name); } static int usbd_cdc_ecm_ctd(struct usbd_class_data *const c_data, diff --git a/subsys/usb/device_next/usbd_core.c b/subsys/usb/device_next/usbd_core.c index 40999b0f7e4fa..3717ae1480325 100644 --- a/subsys/usb/device_next/usbd_core.c +++ b/subsys/usb/device_next/usbd_core.c @@ -204,6 +204,8 @@ int usbd_device_init_core(struct usbd_contex *const uds_ctx) { int ret; + k_sem_init(&uds_ctx->rwup_sem, 0, 1); + ret = udc_init(uds_ctx->dev, usbd_event_carrier); if (ret != 0) { LOG_ERR("Failed to init device driver"); diff --git a/subsys/usb/device_next/usbd_device.c b/subsys/usb/device_next/usbd_device.c index 9057e439040b8..6b38bb41fa3e4 100644 --- a/subsys/usb/device_next/usbd_device.c +++ b/subsys/usb/device_next/usbd_device.c @@ -149,6 +149,7 @@ int usbd_device_set_code_triple(struct usbd_contex *const uds_ctx, int usbd_wakeup_request(struct usbd_contex *const uds_ctx) { struct udc_device_caps caps = udc_caps(uds_ctx->dev); + const k_timeout_t resume_timeout = K_MSEC(25); int ret = 0; usbd_device_lock(uds_ctx); @@ -165,7 +166,19 @@ int usbd_wakeup_request(struct usbd_contex *const uds_ctx) goto wakeup_request_error; } + k_sem_reset(&uds_ctx->rwup_sem); ret = udc_host_wakeup(uds_ctx->dev); + if (ret) { + LOG_ERR("Failed to signal remote wakekup, %d", ret); + goto wakeup_request_error; + } + + ret = k_sem_take(&uds_ctx->rwup_sem, resume_timeout); + if (ret) { + LOG_ERR("Remote wakeup timeout"); + } else { + LOG_DBG("Resumed after remote wakeup"); + } wakeup_request_error: usbd_device_unlock(uds_ctx); diff --git a/subsys/usb/device_next/usbd_device.h b/subsys/usb/device_next/usbd_device.h index f125345fb4e43..d91c49634094c 100644 --- a/subsys/usb/device_next/usbd_device.h +++ b/subsys/usb/device_next/usbd_device.h @@ -93,6 +93,9 @@ static inline void usbd_status_suspended(struct usbd_contex *const uds_ctx, const bool value) { uds_ctx->status.suspended = value; + if (!value) { + k_sem_give(&uds_ctx->rwup_sem); + } } /** diff --git a/subsys/usb/device_next/usbd_endpoint.c b/subsys/usb/device_next/usbd_endpoint.c index fa68313ce8db0..3fb3988981750 100644 --- a/subsys/usb/device_next/usbd_endpoint.c +++ b/subsys/usb/device_next/usbd_endpoint.c @@ -125,7 +125,12 @@ int usbd_ep_enqueue(const struct usbd_class_data *const c_data, if (USB_EP_DIR_IS_IN(bi->ep)) { if (usbd_is_suspended(uds_ctx)) { - return -EPERM; + int ret; + + ret = usbd_wakeup_request(uds_ctx); + if (ret != 0) { + return ret; + } } }