mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge #17086
17086: usbdev: Add dedicated stall functions r=benpicco a=bergzand ### Contribution description This PR 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. ### Testing procedure - examples/usbus_minimal should still enumerate correctly on the host side. - #17085 can be used to demonstrate the ep0_stall function with the `tests/usbus_cdc_acm_stdio/` test ### Issues/PRs references None Co-authored-by: Koen Zandberg <koen@bergzand.net> Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
This commit is contained in:
commit
513676f6e0
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -75,6 +75,7 @@
|
||||
#ifndef PERIPH_USBDEV_H
|
||||
#define PERIPH_USBDEV_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user