From 608322a4ce719bae795e94ec97631ef77f3769e6 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sat, 30 Oct 2021 12:04:36 +0200 Subject: [PATCH 1/6] usbdev: Add dedicated stall functions This commit adds dedicated stall functions for usbdev peripherals. Two functions are added. The first function (usbdev_ep_stall) to enable and disable the stall condition on generic endpoints. The second function is a dedicated function to set the stall condition on endpoint zero in both directions. This status can only be set and should automatically be cleared by the usbdev implementation (or hardware) after a new setup request is received from the host. --- drivers/include/periph/usbdev.h | 65 +++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/drivers/include/periph/usbdev.h b/drivers/include/periph/usbdev.h index 0d947ea9f2..b10addf20b 100644 --- a/drivers/include/periph/usbdev.h +++ b/drivers/include/periph/usbdev.h @@ -75,6 +75,7 @@ #ifndef PERIPH_USBDEV_H #define PERIPH_USBDEV_H +#include #include #include @@ -330,6 +331,15 @@ typedef struct usbdev_driver { */ void (*esr)(usbdev_t *dev); + /** + * @brief Stall both OUT and IN packets on endpoint 0 until a setup packet + * is received. + * + * @note The stall condition should be cleared automatically either by + * hardware or by the usbdev implementation after receiving a setup packet. + */ + void (*ep0_stall)(usbdev_t *usbdev); + /** * @brief Initialize the USB endpoint * @@ -340,6 +350,22 @@ typedef struct usbdev_driver { */ void (*ep_init)(usbdev_ep_t *ep); + /** + * @brief Enable or disable the stall condition on the USB endpoint + * + * After clearing the stall condition on the endpoint, the usb peripheral + * must reinitialize the data toggle to DATA0. + * + * @note For enabling stall on endpoint 0 @ref usbdev_driver_t::ep0_stall + * must be used. + * + * @pre (ep->num != 0) + * + * @param[in] ep USB endpoint descriptor + * @param[in] enable True to set stall, false to disable stall + */ + void (*ep_stall)(usbdev_ep_t *ep, bool enable); + /** * @brief Get an option value from a given usb device endpoint * @@ -509,6 +535,25 @@ static inline void usbdev_esr(usbdev_t *dev) dev->driver->esr(dev); } +/** + * @brief Stall both OUT and IN packets on endpoint 0 until a setup packet + * is received. + * + * @see @ref usbdev_driver_t::ep0_stall + * + * @note The stall condition is automatically cleared after receiving a + * setup packet. + * + * @pre `(dev != NULL)` + * + * @param[in] dev USB device descriptor + */ +static inline void usbdev_ep0_stall(usbdev_t *dev) +{ + assert(dev); + dev->driver->ep0_stall(dev); +} + /** * @brief Initialize the USB endpoint * @@ -526,6 +571,26 @@ static inline void usbdev_ep_init(usbdev_ep_t *ep) ep->dev->driver->ep_init(ep); } +/** + * @brief Enable or disable the stall condition on the USB endpoint + * + * @note For enabling stall on endpoint 0 @ref usbdev_driver_t::ep0_stall + * must be used. + * + * @see @ref usbdev_driver_t::ep_stall + * + * @pre (ep->num != 0) + * + * @param[in] ep USB endpoint descriptor + * @param[in] enable True to set stall, false to disable stall + */ +static inline void usbdev_ep_stall(usbdev_ep_t *ep, bool enable) +{ + assert(ep); + assert(ep->dev); + ep->dev->driver->ep_stall(ep, enable); +} + /** * @brief Get an option value from a given usb device endpoint * From 98c31a7d589f4ca7c63bdf9f83844c61fa73a9dc Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sat, 30 Oct 2021 12:07:21 +0200 Subject: [PATCH 2/6] cpu/nrf52: Add stall functions to usbdev --- cpu/nrf52/periph/usbdev.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/cpu/nrf52/periph/usbdev.c b/cpu/nrf52/periph/usbdev.c index c639e2f50f..5e90af67f2 100644 --- a/cpu/nrf52/periph/usbdev.c +++ b/cpu/nrf52/periph/usbdev.c @@ -45,7 +45,9 @@ static int _get(usbdev_t *usbdev, usbopt_t opt, void *value, size_t max_len); static int _set(usbdev_t *usbdev, usbopt_t opt, const void *value, size_t value_len); static usbdev_ep_t *_new_ep(usbdev_t *dev, usb_ep_type_t type, usb_ep_dir_t dir, size_t len); static void _esr(usbdev_t *usbdev); +static void _ep0_stall(usbdev_t *usbdev); static void _ep_init(usbdev_ep_t *ep); +static void _ep_stall(usbdev_ep_t *ep, bool enable); static int _ep_get(usbdev_ep_t *ep, usbopt_ep_t opt, void *value, size_t max_len); static int _ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, const void *value, size_t value_len); static int _ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len); @@ -57,7 +59,9 @@ static const usbdev_driver_t _driver = { .get = _get, .set = _set, .esr = _esr, + .ep0_stall = _ep0_stall, .ep_init = _ep_init, + .ep_stall = _ep_stall, .ep_get = _ep_get, .ep_set = _ep_set, .ep_esr = _ep_esr, @@ -177,6 +181,8 @@ static void _ep_disable(usbdev_ep_t *ep) static void _ep_set_stall(usbdev_ep_t *ep, usbopt_enable_t enable) { + assert(ep->num != 0); + /* TODO: validate size */ nrfusb_t *usbdev = (nrfusb_t *)ep->dev; uint32_t val = (ep->num & USBD_EPSTALL_EP_Msk) | @@ -186,6 +192,12 @@ static void _ep_set_stall(usbdev_ep_t *ep, usbopt_enable_t enable) usbdev->device->EPSTALL = val; } +static void _ep_stall(usbdev_ep_t *ep, bool enable) +{ + /* quick wrapper */ + _ep_set_stall(ep, (usbopt_enable_t)enable); +} + static usbopt_enable_t _ep_get_stall(usbdev_ep_t *ep) { /* TODO: validate size */ @@ -390,6 +402,13 @@ static void _ep_disable_irq(usbdev_ep_t *ep) } } +static void _ep0_stall(usbdev_t *dev) +{ + nrfusb_t *usbdev = (nrfusb_t*)dev; + /* Stalls both OUT and IN */ + usbdev->device->TASKS_EP0STALL = 1; +} + static void _ep_init(usbdev_ep_t *ep) { nrfusb_t *usbdev = (nrfusb_t*)ep->dev; From 33ba2adc68a2c372040f958de671795d227835be Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sat, 30 Oct 2021 12:07:41 +0200 Subject: [PATCH 3/6] drivers/usbdev_synopsys_dwc2: add stall functions to usbdev --- .../usbdev_synopsys_dwc2.c | 61 +++++++++++++++---- 1 file changed, 49 insertions(+), 12 deletions(-) diff --git a/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c b/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c index 0d1140f3ee..faa53e8b48 100644 --- a/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c +++ b/drivers/usbdev_synopsys_dwc2/usbdev_synopsys_dwc2.c @@ -330,9 +330,10 @@ static uint32_t _ep0_size(size_t size) } /** - * @brief Disables an IN type endpoint + * @brief Disables transfers on an IN type endpoint. * - * Endpoint is only deactivated if it was activated + * Endpoint is only deactivated if it was activated. + * The endpoint will still respond to traffic, but any transfers will be aborted */ static void _ep_in_disable(const dwc2_usb_otg_fshs_config_t *conf, size_t num) { @@ -352,9 +353,10 @@ static void _ep_in_disable(const dwc2_usb_otg_fshs_config_t *conf, size_t num) } /** - * @brief Disables an OUT type endpoint + * @brief Disables transfers on an OUT type endpoint. * * Endpoint is only deactivated if it was activated + * The endpoint will still respond to traffic, but any transfers will be aborted */ static void _ep_out_disable(const dwc2_usb_otg_fshs_config_t *conf, size_t num) { @@ -1148,25 +1150,58 @@ static int _usbdev_ep_get(usbdev_ep_t *ep, usbopt_ep_t opt, return res; } +static void _usbdev_ep0_stall(usbdev_t *usbdev) +{ + dwc2_usb_otg_fshs_t *st_usbdev = (dwc2_usb_otg_fshs_t *)usbdev; + const dwc2_usb_otg_fshs_config_t *conf = st_usbdev->config; + /* Stall both directions, cleared automatically on SETUP received */ + _in_regs(conf, 0)->DIEPCTL |= USB_OTG_DIEPCTL_STALL; + _out_regs(conf, 0)->DOEPCTL |= USB_OTG_DOEPCTL_STALL; +} + static void _ep_set_stall(usbdev_ep_t *ep, bool enable) { + (void)enable; + + assert(ep->num != 0); dwc2_usb_otg_fshs_t *usbdev = (dwc2_usb_otg_fshs_t *)ep->dev; const dwc2_usb_otg_fshs_config_t *conf = usbdev->config; - (void)enable; - - if (ep->dir == USB_EP_DIR_IN) { - /* Disable first */ - _ep_in_disable(conf, ep->num); - _in_regs(conf, ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_STALL; + if (enable) { + if (ep->dir == USB_EP_DIR_IN) { + /* Disable first */ + _ep_in_disable(conf, ep->num); + _in_regs(conf, ep->num)->DIEPCTL |= USB_OTG_DIEPCTL_STALL; + } + else { + /* Disable first */ + _ep_out_disable(conf, ep->num); + _out_regs(conf, ep->num)->DOEPCTL |= USB_OTG_DOEPCTL_STALL; + } } else { - /* Disable first */ - _ep_out_disable(conf, ep->num); - _out_regs(conf, ep->num)->DOEPCTL |= USB_OTG_DOEPCTL_STALL; + if (ep->dir == USB_EP_DIR_IN) { + /* Clear stall and set to DATA0 */ + uint32_t diepctl = _in_regs(conf, ep->num)->DIEPCTL; + diepctl &= ~(USB_OTG_DIEPCTL_STALL); + diepctl |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM; + _in_regs(conf, ep->num)->DIEPCTL = diepctl; + } + else { + /* Clear stall and set to DATA0 */ + uint32_t doepctl = _out_regs(conf, ep->num)->DOEPCTL; + doepctl &= ~(USB_OTG_DIEPCTL_STALL); + doepctl |= USB_OTG_DIEPCTL_SD0PID_SEVNFRM; + _out_regs(conf, ep->num)->DOEPCTL = doepctl; + } } } +static void _usbdev_ep_stall(usbdev_ep_t *ep, bool enable) +{ + _ep_set_stall(ep, enable); +} + static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, const void *value, size_t value_len) { @@ -1492,7 +1527,9 @@ const usbdev_driver_t driver = { .get = _usbdev_get, .set = _usbdev_set, .esr = _usbdev_esr, + .ep0_stall = _usbdev_ep0_stall, .ep_init = _usbdev_ep_init, + .ep_stall = _usbdev_ep_stall, .ep_get = _usbdev_ep_get, .ep_set = _usbdev_ep_set, .ep_esr = _usbdev_ep_esr, From 10578c789567308a4bf5d49a203f686a349d5329 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sat, 30 Oct 2021 12:07:54 +0200 Subject: [PATCH 4/6] cpu/sam0_common: Add stall functions to usbdev --- cpu/sam0_common/periph/usbdev.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/cpu/sam0_common/periph/usbdev.c b/cpu/sam0_common/periph/usbdev.c index 1e814b90b8..aa21ad4986 100644 --- a/cpu/sam0_common/periph/usbdev.c +++ b/cpu/sam0_common/periph/usbdev.c @@ -584,12 +584,23 @@ static inline void _enable_ep_stall_in(UsbDeviceEndpoint *ep_reg) static inline void _disable_ep_stall_out(UsbDeviceEndpoint *ep_reg) { - ep_reg->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0; + ep_reg->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0 | + USB_DEVICE_EPSTATUSCLR_DTGLOUT; } static inline void _disable_ep_stall_in(UsbDeviceEndpoint *ep_reg) { - ep_reg->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1; + ep_reg->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1 | + USB_DEVICE_EPSTATUSCLR_DTGLIN; +} + +static void _usbdev_ep0_stall(usbdev_t *usbdev) +{ + sam0_common_usb_t *sam_usbdev = (sam0_common_usb_t *)usbdev; + UsbDeviceEndpoint *ep0_reg = &sam_usbdev->config->device->DeviceEndpoint[0]; + + ep0_reg->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1 | + USB_DEVICE_EPSTATUSSET_STALLRQ0; } static void _ep_set_stall(usbdev_ep_t *ep, usbopt_enable_t enable) @@ -625,6 +636,11 @@ usbopt_enable_t _ep_get_stall(usbdev_ep_t *ep) } +static void _usbdev_ep_stall(usbdev_ep_t *ep, bool enable) +{ + _ep_set_stall(ep, enable); +} + static void _usbdev_ep_init(usbdev_ep_t *ep) { _enable_ep_irq(ep); @@ -773,7 +789,9 @@ const usbdev_driver_t driver = { .get = _usbdev_get, .set = _usbdev_set, .esr = _usbdev_esr, + .ep0_stall = _usbdev_ep0_stall, .ep_init = _usbdev_ep_init, + .ep_stall = _usbdev_ep_stall, .ep_get = _usbdev_ep_get, .ep_set = _usbdev_ep_set, .ep_esr = _usbdev_ep_esr, From 5f43e07c0673d3947e853882e9a9381c480bcba9 Mon Sep 17 00:00:00 2001 From: Koen Zandberg Date: Sat, 30 Oct 2021 12:08:10 +0200 Subject: [PATCH 5/6] usbus: Use new usbdev ep0 stall function --- sys/usb/usbus/usbus_control.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sys/usb/usbus/usbus_control.c b/sys/usb/usbus/usbus_control.c index d86f9fae44..96290f12d1 100644 --- a/sys/usb/usbus/usbus_control.c +++ b/sys/usb/usbus/usbus_control.c @@ -277,10 +277,8 @@ static void _recv_setup(usbus_t *usbus, usbus_control_handler_t *handler) } } if (res < 0) { - /* Signal stall to indicate unsupported (USB 2.0 spec 9.6.2 */ - static const usbopt_enable_t enable = USBOPT_ENABLE; - usbdev_ep_set(handler->in, USBOPT_EP_STALL, &enable, - sizeof(usbopt_enable_t)); + /* Signal stall to indicate unsupported (USB 2.0 spec 9.6.2) */ + usbdev_ep0_stall(usbus->dev); handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY; } else if (res) { From 86808b690e1518bdc53cce05cc553a2df25aa5f1 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 9 Mar 2023 16:59:15 +0100 Subject: [PATCH 6/6] cpu/stm32: Add stall functions to usbdev_fs --- cpu/stm32/periph/usbdev_fs.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cpu/stm32/periph/usbdev_fs.c b/cpu/stm32/periph/usbdev_fs.c index 9d6478d4d3..5f94d520a1 100644 --- a/cpu/stm32/periph/usbdev_fs.c +++ b/cpu/stm32/periph/usbdev_fs.c @@ -665,6 +665,18 @@ static void _ep_set_stall(usbdev_ep_t *ep, usbopt_enable_t enable) EP_REG(ep->num) = reg; } +static void _usbdev_ep0_stall(usbdev_t *usbdev) +{ + (void)usbdev; + _ep_set_stall(&_ep_in[0], true); + _ep_set_stall(&_ep_out[0], true); +} + +static void _usbdev_ep_stall(usbdev_ep_t *ep, bool enable) +{ + _ep_set_stall(ep, enable); +} + static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, const void *value, size_t value_len) { @@ -773,7 +785,9 @@ const usbdev_driver_t driver = { .get = _usbdev_get, .set = _usbdev_set, .esr = _usbdev_esr, + .ep0_stall = _usbdev_ep0_stall, .ep_init = _usbdev_ep_init, + .ep_stall = _usbdev_ep_stall, .ep_get = _usbdev_ep_get, .ep_set = _usbdev_ep_set, .ep_esr = _usbdev_ep_esr,