diff --git a/cpu/nrf52/include/nrfusb.h b/cpu/nrf52/include/nrfusb.h index d69967ff4b..07239fc021 100644 --- a/cpu/nrf52/include/nrfusb.h +++ b/cpu/nrf52/include/nrfusb.h @@ -36,11 +36,6 @@ extern "C" { */ #define NRF_USB_NUM_PERIPH 1 -/** - * USB endpoint buffer space - */ -#define NRF_USB_BUF_SPACE USBDEV_EP_BUF_SPACE - /** * Number of USB IN and OUT endpoints */ @@ -65,9 +60,6 @@ typedef struct { usbdev_ep_t ep_ins[NRF_USB_NUM_EP]; /**< IN type endpoints */ usbdev_ep_t ep_outs[ NRF_USB_NUM_EP]; /**< OUT type endpoints */ NRF_USBD_Type *device; /**< Ptr to the device registers */ - size_t used; /**< Number of bytes from the - buffer that are used */ - uint8_t buffer[NRF_USB_BUF_SPACE]; /**< Buffer space for endpoint data */ nrfusb_setup_state_t sstate; /**< Setup request state machine */ } nrfusb_t; diff --git a/cpu/nrf52/include/periph_cpu.h b/cpu/nrf52/include/periph_cpu.h index 25283d6b18..7f3bef6051 100644 --- a/cpu/nrf52/include/periph_cpu.h +++ b/cpu/nrf52/include/periph_cpu.h @@ -263,6 +263,17 @@ void spi_twi_irq_register_spi(NRF_SPIM_Type *bus, */ void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, spi_twi_irq_cb_t cb, void *arg); + +/** + * @brief USBDEV buffers must be word aligned because of DMA restrictions + */ +#define USBDEV_CPU_DMA_ALIGNMENT (4) + +/** + * @brief USBDEV buffer instantiation requirement + */ +#define USBDEV_CPU_DMA_REQUIREMENTS __attribute__((aligned(USBDEV_CPU_DMA_ALIGNMENT))) + #ifdef __cplusplus } #endif diff --git a/cpu/nrf52/periph/usbdev.c b/cpu/nrf52/periph/usbdev.c index 26d8ef4ff8..c639e2f50f 100644 --- a/cpu/nrf52/periph/usbdev.c +++ b/cpu/nrf52/periph/usbdev.c @@ -27,6 +27,7 @@ #include #include +#include "architecture.h" #include "cpu.h" #include "nrfusb.h" #include "periph/usbdev.h" @@ -42,12 +43,12 @@ static nrfusb_t _usbdevs[NRF_USB_NUM_PERIPH]; static void _init(usbdev_t *usbdev); 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 buf_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 _ep_init(usbdev_ep_t *ep); 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_ready(usbdev_ep_t *ep, size_t len); +static int _ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len); static void _ep_esr(usbdev_ep_t *ep); static const usbdev_driver_t _driver = { @@ -60,7 +61,7 @@ static const usbdev_driver_t _driver = { .ep_get = _ep_get, .ep_set = _ep_set, .ep_esr = _ep_esr, - .ready = _ep_ready, + .xmit = _ep_xmit, }; static inline usbdev_ep_t *_get_ep_in(nrfusb_t *usbdev, unsigned num) @@ -129,22 +130,10 @@ static void usb_detach(nrfusb_t *usbdev) usbdev->device->USBPULLUP = 0x00; } -static void _ep_set_address(usbdev_ep_t *ep) -{ - nrfusb_t *usbdev = (nrfusb_t *)ep->dev; - - if (ep->dir == USB_EP_DIR_OUT) { - usbdev->device->EPOUT[ep->num].PTR = (uint32_t)ep->buf; - } - else { - usbdev->device->EPIN[ep->num].PTR = (uint32_t)ep->buf; - } -} - static void _copy_setup(usbdev_ep_t *ep) { - nrfusb_t *usbdev = (nrfusb_t *)ep->dev; - usb_setup_t *setup = (usb_setup_t *)ep->buf; + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; + usb_setup_t *setup = (usb_setup_t*)(intptr_t)usbdev->device->EPOUT[0].PTR; setup->type = usbdev->device->BMREQUESTTYPE; setup->request = usbdev->device->BREQUEST; @@ -159,17 +148,6 @@ static void _copy_setup(usbdev_ep_t *ep) } } -static int _ep_set_size(usbdev_ep_t *ep) -{ - /* TODO: validate size */ - nrfusb_t *usbdev = (nrfusb_t *)ep->dev; - - if (ep->dir == USB_EP_DIR_OUT) { - usbdev->device->EPOUT[ep->num].MAXCNT = (uint32_t)ep->len; - } - return 1; -} - static void _ep_enable(usbdev_ep_t *ep) { DEBUG("Enabling endpoint %u dir %s\n", ep->num, ep->dir == USB_EP_DIR_OUT ? "OUT" : "IN"); @@ -287,7 +265,6 @@ static void _init(usbdev_t *dev) nrfusb_t *usbdev = (nrfusb_t *)dev; poweron(usbdev); - usbdev->used = 0; usbdev->sstate = NRFUSB_SETUP_READY; /* Enable a set of interrupts */ @@ -350,9 +327,9 @@ static int _set(usbdev_t *dev, usbopt_t opt, static usbdev_ep_t *_new_ep(usbdev_t *dev, usb_ep_type_t type, usb_ep_dir_t dir, - size_t buf_len) + size_t len) { - nrfusb_t *usbdev = (nrfusb_t *)dev; + nrfusb_t *usbdev = (nrfusb_t*)dev; /* The IP supports all types for all endpoints */ usbdev_ep_t *res = NULL; @@ -374,23 +351,9 @@ static usbdev_ep_t *_new_ep(usbdev_t *dev, if (res) { res->dev = dev; res->dir = dir; - DEBUG("nrfusb: Allocated new ep (%d %s)\n", - res->num, - res->dir == USB_EP_DIR_OUT ? "OUT" : "IN"); - if (usbdev->used + buf_len < NRF_USB_BUF_SPACE) { - res->buf = usbdev->buffer + usbdev->used; - res->len = buf_len; - if (_ep_set_size(res) < 0) { - return NULL; - } - usbdev->used += buf_len; - _ep_set_address(res); - res->type = type; - res->dev = dev; - } - else { - DEBUG("nrfusb: error allocating buffer space\n"); - } + res->type = type; + res->len = len; + DEBUG("nrfusb: Allocated new ep (%d %s)\n", res->num, res->dir == USB_EP_DIR_OUT ? "OUT" : "IN"); } return res; } @@ -429,10 +392,8 @@ static void _ep_disable_irq(usbdev_ep_t *ep) static void _ep_init(usbdev_ep_t *ep) { - nrfusb_t *usbdev = (nrfusb_t *)ep->dev; + nrfusb_t *usbdev = (nrfusb_t*)ep->dev; - _ep_set_size(ep); - _ep_set_address(ep); if (ep->num == 0) { usbdev->device->EVENTS_EP0SETUP = 0; } @@ -493,13 +454,6 @@ static int _ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, _ep_set_stall(ep, *(usbopt_enable_t *)value); res = sizeof(usbopt_enable_t); break; - case USBOPT_EP_READY: - assert(value_len == sizeof(usbopt_enable_t)); - if (*((usbopt_enable_t *)value)) { - _ep_ready(ep, 0); - res = sizeof(usbopt_enable_t); - } - break; default: DEBUG("Unhandled set call: 0x%x\n", opt); break; @@ -507,9 +461,11 @@ static int _ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, return res; } -static int _ep0_ready(usbdev_ep_t *ep, size_t len) +static int _ep0_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) { nrfusb_t *usbdev = (nrfusb_t *)ep->dev; + /* Assert the alignment required for the buffers */ + assert(HAS_ALIGNMENT_OF(buf, USBDEV_CPU_DMA_ALIGNMENT)); if (ep->dir == USB_EP_DIR_IN) { if (len == 0 && usbdev->sstate == NRFUSB_SETUP_WRITE) { @@ -518,12 +474,14 @@ static int _ep0_ready(usbdev_ep_t *ep, size_t len) usbdev->sstate = NRFUSB_SETUP_ACKIN; } else { - usbdev->device->EPIN[0].PTR = (uint32_t)ep->buf; + usbdev->device->EPIN[0].PTR = (uint32_t)(intptr_t)buf; usbdev->device->EPIN[0].MAXCNT = (uint32_t)len; usbdev->device->TASKS_STARTEPIN[0] = 1; } } else { + usbdev->device->EPOUT[0].PTR = (uint32_t)(intptr_t)buf; + usbdev->device->EPOUT[0].MAXCNT = (uint32_t)len; /* USB_EP_DIR_OUT */ if (usbdev->sstate == NRFUSB_SETUP_READ) { usbdev->device->TASKS_EP0STATUS = 1; @@ -537,20 +495,23 @@ static int _ep0_ready(usbdev_ep_t *ep, size_t len) return len; } -static int _ep_ready(usbdev_ep_t *ep, size_t len) +static int _ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) { nrfusb_t *usbdev = (nrfusb_t *)ep->dev; if (ep->num == 0) { /* Endpoint 0 requires special handling as per datasheet sec 6.35.9 */ - return _ep0_ready(ep, len); + return _ep0_xmit(ep, buf, len); } if (ep->dir == USB_EP_DIR_IN) { - usbdev->device->EPIN[ep->num].PTR = (uint32_t)ep->buf; + usbdev->device->EPIN[ep->num].PTR = (uint32_t)(intptr_t)buf; usbdev->device->EPIN[ep->num].MAXCNT = (uint32_t)len; _ep_dma_in(ep); } else { + /* Pre-Setup the EasyDMA settings */ + usbdev->device->EPOUT[ep->num].PTR = (uint32_t)(intptr_t)buf; + usbdev->device->EPOUT[ep->num].MAXCNT = (uint32_t)(intptr_t)len; /* Write nonzero value to EPOUT to indicate ready */ usbdev->device->SIZE.EPOUT[ep->num] = 1; } diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index eb10d8c63b..6138e18002 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -813,6 +813,16 @@ typedef struct { } sam0_common_gmac_config_t; #endif +/** + * @brief USBDEV buffers must be word aligned because of DMA restrictions + */ +#define USBDEV_CPU_DMA_ALIGNMENT (4) + +/** + * @brief USBDEV buffer instantiation requirement + */ +#define USBDEV_CPU_DMA_REQUIREMENTS __attribute__((aligned(USBDEV_CPU_DMA_ALIGNMENT))) + /** * @brief USB peripheral parameters */ diff --git a/cpu/sam0_common/include/sam_usb.h b/cpu/sam0_common/include/sam_usb.h index 9b6800b349..f11d9f9075 100644 --- a/cpu/sam0_common/include/sam_usb.h +++ b/cpu/sam0_common/include/sam_usb.h @@ -31,11 +31,6 @@ extern "C" { #endif -/** - * USB endpoint buffer space - */ -#define SAM_USB_BUF_SPACE USBDEV_EP_BUF_SPACE - /** * Number of USB IN and OUT endpoints */ @@ -49,11 +44,6 @@ typedef struct { const sam0_common_usb_config_t *config; /**< USB peripheral config */ UsbDeviceDescBank banks[2 * SAM_USB_NUM_EP]; /**< Device descriptor banks */ usbdev_ep_t endpoints[2 * SAM_USB_NUM_EP]; /**< Endpoints */ - size_t used; /**< Number of bytes from the - buffer that are used */ - __attribute__ ((aligned(4))) - uint8_t buffer[SAM_USB_BUF_SPACE]; /**< Buffer space, must be - 32-bit aligned */ bool suspended; /**< Suspend active */ } sam0_common_usb_t; diff --git a/cpu/sam0_common/periph/usbdev.c b/cpu/sam0_common/periph/usbdev.c index f392640e4d..4a54511846 100644 --- a/cpu/sam0_common/periph/usbdev.c +++ b/cpu/sam0_common/periph/usbdev.c @@ -22,6 +22,7 @@ #include #include #include +#include "architecture.h" #include "cpu.h" #include "cpu_conf.h" #include "periph/gpio.h" @@ -46,12 +47,11 @@ static sam0_common_usb_t _usbdevs[USB_INST_NUM]; const usbdev_driver_t driver; static void _usbdev_ep_init(usbdev_ep_t *ep); -static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len); +static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len); static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, - usb_ep_dir_t dir, size_t buf_len); + usb_ep_dir_t dir, size_t len); static int _bank_set_size(usbdev_ep_t *ep); -static int _ep_unready(usbdev_ep_t *ep); static inline unsigned _ep_num(unsigned num, usb_ep_dir_t dir) { @@ -144,13 +144,6 @@ static void _disable_ep_irq_in(UsbDeviceEndpoint *ep_reg) USB_DEVICE_EPINTENCLR_STALL1; } -static void _bank_set_address(usbdev_ep_t *ep) -{ - UsbDeviceDescBank *bank = _bank_from_ep(ep); - - bank->ADDR.reg = (uint32_t)ep->buf; -} - static int _bank_set_size(usbdev_ep_t *ep) { UsbDeviceDescBank *bank = _bank_from_ep(ep); @@ -255,7 +248,7 @@ static inline void _poweron(sam0_common_usb_t *dev) } static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, - usb_ep_dir_t dir, size_t buf_len) + usb_ep_dir_t dir, size_t size) { sam0_common_usb_t *usbdev = (sam0_common_usb_t *)dev; /* The IP supports all types for all endpoints */ @@ -279,17 +272,9 @@ static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, if (res) { res->dev = dev; res->dir = dir; - if (usbdev->used + buf_len < SAM_USB_BUF_SPACE) { - res->buf = usbdev->buffer + usbdev->used; - res->len = buf_len; - if (_bank_set_size(res) < 0) { - return NULL; - } - usbdev->used += buf_len; - _bank_set_address(res); - res->type = type; - res->dev = dev; - } + res->type = type; + res->len = size; + _bank_set_size(res); } return res; } @@ -334,7 +319,6 @@ static void _usbdev_init(usbdev_t *dev) /* Only one usb device on this board */ sam0_common_usb_t *usbdev = (sam0_common_usb_t *)dev; - usbdev->used = 0; /* Set GPIO */ gpio_init(usbdev->config->dp, GPIO_IN); gpio_init(usbdev->config->dm, GPIO_IN); @@ -688,16 +672,6 @@ static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, _ep_set_stall(ep, *(usbopt_enable_t *)value); res = sizeof(usbopt_enable_t); break; - case USBOPT_EP_READY: - assert(value_len == sizeof(usbopt_enable_t)); - if (*((usbopt_enable_t *)value)) { - _ep_unready(ep); - } - else { - _usbdev_ep_ready(ep, 0); - } - res = sizeof(usbopt_enable_t); - break; default: DEBUG("sam_usb: Unhandled set call: 0x%x\n", opt); break; @@ -705,23 +679,13 @@ static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, return res; } -static int _ep_unready(usbdev_ep_t *ep) -{ - UsbDeviceEndpoint *ep_reg = _ep_reg_from_ep(ep); - - if (ep->dir == USB_EP_DIR_IN) { - ep_reg->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_BK1RDY; - } - else { - ep_reg->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_BK0RDY; - } - return 0; -} - -static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len) +static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) { UsbDeviceEndpoint *ep_reg = _ep_reg_from_ep(ep); + /* Assert the alignment required for the buffers */ + assert(HAS_ALIGNMENT_OF(buf, USBDEV_CPU_DMA_ALIGNMENT)); + _bank_from_ep(ep)->ADDR.reg = (uint32_t)(intptr_t)buf; if (ep->dir == USB_EP_DIR_IN) { _disable_ep_stall_in(ep_reg); _bank_from_ep(ep)->PCKSIZE.bit.BYTE_COUNT = len; @@ -803,5 +767,5 @@ const usbdev_driver_t driver = { .ep_get = _usbdev_ep_get, .ep_set = _usbdev_ep_set, .ep_esr = _usbdev_ep_esr, - .ready = _usbdev_ep_ready, + .xmit = _usbdev_ep_xmit, }; diff --git a/cpu/stm32/include/periph_cpu.h b/cpu/stm32/include/periph_cpu.h index f84be15b77..c73e045d11 100644 --- a/cpu/stm32/include/periph_cpu.h +++ b/cpu/stm32/include/periph_cpu.h @@ -782,6 +782,16 @@ typedef struct { } i2c_timing_param_t; #endif +/** + * @brief USBDEV buffers must be word aligned because of DMA restrictions + */ +#define USBDEV_CPU_DMA_ALIGNMENT (4) + +/** + * @brief USBDEV buffer instantiation requirement + */ +#define USBDEV_CPU_DMA_REQUIREMENTS __attribute__((aligned(USBDEV_CPU_DMA_ALIGNMENT))) + /** * @brief USB OTG peripheral type. * diff --git a/cpu/stm32/include/usbdev_stm32.h b/cpu/stm32/include/usbdev_stm32.h index 6f60c3be34..337692f165 100644 --- a/cpu/stm32/include/usbdev_stm32.h +++ b/cpu/stm32/include/usbdev_stm32.h @@ -56,17 +56,6 @@ extern "C" { #error Unknown USB peripheral version #endif -/** - * @brief Buffer space available for endpoint TX/RX data - */ -#ifndef STM32_USB_OTG_BUF_SPACE -#define STM32_USB_OTG_BUF_SPACE USBDEV_EP_BUF_SPACE -#endif - -#if (STM32_USB_OTG_BUF_SPACE % 4) != 0 -#error "STM32_USB_OTG_BUF_SPACE needs to be a multiple of 4" -#endif - /** * @brief Number of endpoints available with the OTG FS peripheral * including the control endpoint @@ -121,17 +110,23 @@ extern "C" { #endif #endif +/** + * @brief stm32 USB OTG peripheral device out endpoint struct + */ +typedef struct { + usbdev_ep_t ep; /**< Inherited usbdev endpoint struct */ + uint8_t *out_buf; /**< Requested data output buffer */ +} stm32_usb_otg_fshs_out_ep_t; + /** * @brief stm32 USB OTG peripheral device context */ typedef struct { usbdev_t usbdev; /**< Inherited usbdev struct */ const stm32_usb_otg_fshs_config_t *config; /**< USB peripheral config */ - uint8_t buffer[STM32_USB_OTG_BUF_SPACE]; /**< Buffer space for endpoints */ - size_t occupied; /**< Buffer space occupied */ size_t fifo_pos; /**< FIFO space occupied */ usbdev_ep_t *in; /**< In endpoints */ - usbdev_ep_t *out; /**< Out endpoints */ + stm32_usb_otg_fshs_out_ep_t *out; /**< Out endpoints */ bool suspend; /**< Suspend status */ } stm32_usb_otg_fshs_t; diff --git a/cpu/stm32/periph/usbdev.c b/cpu/stm32/periph/usbdev.c index dae27c1902..740413ae4b 100644 --- a/cpu/stm32/periph/usbdev.c +++ b/cpu/stm32/periph/usbdev.c @@ -23,6 +23,7 @@ #include #include +#include "architecture.h" #include "bitarithm.h" #include "ztimer.h" #include "cpu.h" @@ -101,7 +102,7 @@ /* List of instantiated USB peripherals */ static stm32_usb_otg_fshs_t _usbdevs[USBDEV_NUMOF] = { 0 }; -static usbdev_ep_t _out[_TOTAL_NUM_ENDPOINTS]; +static stm32_usb_otg_fshs_out_ep_t _out[_TOTAL_NUM_ENDPOINTS]; static usbdev_ep_t _in[_TOTAL_NUM_ENDPOINTS]; /* Forward declaration for the usb device driver */ @@ -418,7 +419,7 @@ static usbdev_ep_t *_get_ep(stm32_usb_otg_fshs_t *usbdev, unsigned num, if (num >= STM32_USB_OTG_FS_NUM_EP) { return NULL; } - return dir == USB_EP_DIR_IN ? &usbdev->in[num] : &usbdev->out[num]; + return dir == USB_EP_DIR_IN ? &usbdev->in[num] : &usbdev->out[num].ep; } #if defined(DEVELHELP) && !defined(NDEBUG) @@ -479,18 +480,8 @@ static void _configure_fifo(stm32_usb_otg_fshs_t *usbdev) usbdev->fifo_pos = (rx_size + STM32_USB_OTG_FIFO_MIN_WORD_SIZE); } -size_t _round_up_to_multiple_of_four(size_t unaligned) -{ - size_t misalignment = unaligned & 0x03; - if (misalignment) { - unaligned += 4 - misalignment; - } - - return unaligned; -} - static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, - usb_ep_dir_t dir, size_t buf_len) + usb_ep_dir_t dir, size_t len) { stm32_usb_otg_fshs_t *usbdev = (stm32_usb_otg_fshs_t *)dev; usbdev_ep_t *ep = NULL; @@ -500,7 +491,7 @@ static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, ep = &usbdev->in[0]; } else { - ep = &usbdev->out[0]; + ep = &usbdev->out[0].ep; } ep->num = 0; } @@ -516,17 +507,12 @@ static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, } if (ep && ep->type == USB_EP_TYPE_NONE) { - if (usbdev->occupied + buf_len < STM32_USB_OTG_BUF_SPACE) { - ep->buf = usbdev->buffer + usbdev->occupied; - ep->dir = dir; - ep->type = type; - ep->dev = dev; - ep->len = buf_len; - usbdev->occupied += buf_len; - usbdev->occupied = _round_up_to_multiple_of_four(usbdev->occupied); - if (ep->dir == USB_EP_DIR_IN && ep->num != 0) { - _configure_tx_fifo(usbdev, ep->num, ep->len); - } + ep->dir = dir; + ep->type = type; + ep->dev = dev; + ep->len = len; + if (ep->dir == USB_EP_DIR_IN && ep->num != 0) { + _configure_tx_fifo(usbdev, ep->num, ep->len); } } return ep; @@ -922,10 +908,12 @@ static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt, return res; } -static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len) +static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) { stm32_usb_otg_fshs_t *usbdev = (stm32_usb_otg_fshs_t *)ep->dev; const stm32_usb_otg_fshs_config_t *conf = usbdev->config; + /* Assert the alignment required for the buffers */ + assert(HAS_ALIGNMENT_OF(buf, USBDEV_CPU_DMA_ALIGNMENT)); if (ep->dir == USB_EP_DIR_IN) { /* Abort when the endpoint is not active, prevents hangs, @@ -935,7 +923,7 @@ static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len) } if (_uses_dma(conf)) { - _in_regs(conf, ep->num)->DIEPDMA = (uint32_t)ep->buf; + _in_regs(conf, ep->num)->DIEPDMA = (uint32_t)(intptr_t)buf; } /* The order here is crucial (AFAIK), it is required to first set the @@ -966,9 +954,10 @@ static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len) if (len > 0 && !_uses_dma(conf)) { /* The FIFO requires 32 bit word reads/writes */ size_t words = (len + 3) / 4; - /* buffer is gets aligned in _usbdev_new_ep(). Use intermediate + + /* buffer alignment is asserted above. Use intermediate * cast to uintptr_t to silence -Wcast-align*/ - uint32_t *ep_buf = (uint32_t *)(uintptr_t)ep->buf; + uint32_t *ep_buf = (uint32_t *)(uintptr_t)buf; __O uint32_t *fifo = _tx_fifo(conf, ep->num); for (size_t i = 0; i < words; i++) { fifo[i] = ep_buf[i]; @@ -983,7 +972,10 @@ static int _usbdev_ep_ready(usbdev_ep_t *ep, size_t len) } if (_uses_dma(conf)) { - _out_regs(conf, ep->num)->DOEPDMA = (uint32_t)ep->buf; + _out_regs(conf, ep->num)->DOEPDMA = (uint32_t)(intptr_t)buf; + } + else { + container_of(ep, stm32_usb_otg_fshs_out_ep_t, ep)->out_buf = buf; } /* Configure to receive one packet with ep->len as max length */ @@ -1012,9 +1004,9 @@ static void _copy_rxfifo(stm32_usb_otg_fshs_t *usbdev, uint8_t *buf, size_t len) } } -static void _read_packet(usbdev_ep_t *ep) +static void _read_packet(stm32_usb_otg_fshs_out_ep_t *st_ep) { - stm32_usb_otg_fshs_t *usbdev = (stm32_usb_otg_fshs_t *)ep->dev; + stm32_usb_otg_fshs_t *usbdev = (stm32_usb_otg_fshs_t *)st_ep->ep.dev; const stm32_usb_otg_fshs_config_t *conf = usbdev->config; /* Pop status from the receive fifo status register */ uint32_t status = _global_regs(conf)->GRXSTSP; @@ -1029,13 +1021,12 @@ static void _read_packet(usbdev_ep_t *ep) * complete status*/ if (pkt_status == STM32_PKTSTS_DATA_UPDT || pkt_status == STM32_PKTSTS_SETUP_UPDT) { - _copy_rxfifo(usbdev, ep->buf, len); + _copy_rxfifo(usbdev, st_ep->out_buf, len); #ifdef STM32_USB_OTG_CID_2x /* CID 2x doesn't signal SETUP_COMP on non-zero length packets, signal * the TR_COMPLETE event immediately */ - if (ep->num == 0 && len) { - usbdev->usbdev.epcb(&usbdev->out[ep->num], - USBDEV_EVENT_TR_COMPLETE); + if (st_ep->ep.num == 0 && len) { + usbdev->usbdev.epcb(&st_ep->ep, USBDEV_EVENT_TR_COMPLETE); } #endif /* STM32_USB_OTG_CID_2x */ } @@ -1043,7 +1034,7 @@ static void _read_packet(usbdev_ep_t *ep) * status is skipped */ else if (pkt_status == STM32_PKTSTS_XFER_COMP || pkt_status == STM32_PKTSTS_SETUP_COMP) { - usbdev->usbdev.epcb(&usbdev->out[ep->num], USBDEV_EVENT_TR_COMPLETE); + usbdev->usbdev.epcb(&st_ep->ep, USBDEV_EVENT_TR_COMPLETE); } } @@ -1078,7 +1069,7 @@ static void _usbdev_ep_esr(usbdev_ep_t *ep) if ((_global_regs(conf)->GINTSTS & USB_OTG_GINTSTS_RXFLVL) && (_global_regs(conf)->GRXSTSR & USB_OTG_GRXSTSP_EPNUM_Msk) == ep->num && !_uses_dma(conf)) { - _read_packet(ep); + _read_packet(container_of(ep, stm32_usb_otg_fshs_out_ep_t, ep)); } /* Transfer complete seems only reliable when used with DMA */ else if (_out_regs(conf, ep->num)->DOEPINT & USB_OTG_DOEPINT_XFRC) { @@ -1102,7 +1093,7 @@ static void _isr_ep(stm32_usb_otg_fshs_t *usbdev) if (active_ep) { unsigned epnum = bitarithm_lsb(active_ep); if (epnum >= STM32_USB_OTG_REG_EP_OUT_OFFSET) { - usbdev->usbdev.epcb(&usbdev->out[epnum - STM32_USB_OTG_REG_EP_OUT_OFFSET], + usbdev->usbdev.epcb(&usbdev->out[epnum - STM32_USB_OTG_REG_EP_OUT_OFFSET].ep, USBDEV_EVENT_ESR); } else { @@ -1121,7 +1112,7 @@ void _isr_common(stm32_usb_otg_fshs_t *usbdev) if (status & USB_OTG_GINTSTS_RXFLVL) { unsigned epnum = _global_regs(conf)->GRXSTSR & USB_OTG_GRXSTSP_EPNUM_Msk; - usbdev->usbdev.epcb(&usbdev->out[epnum], USBDEV_EVENT_ESR); + usbdev->usbdev.epcb(&usbdev->out[epnum].ep, USBDEV_EVENT_ESR); } else if (_global_regs(conf)->GINTSTS & (USB_OTG_GINTSTS_OEPINT | USB_OTG_GINTSTS_IEPINT)) { @@ -1166,5 +1157,5 @@ const usbdev_driver_t driver = { .ep_get = _usbdev_ep_get, .ep_set = _usbdev_ep_set, .ep_esr = _usbdev_ep_esr, - .ready = _usbdev_ep_ready, + .xmit = _usbdev_ep_xmit, }; diff --git a/drivers/include/periph/usbdev.h b/drivers/include/periph/usbdev.h index 1845b5e69a..0d947ea9f2 100644 --- a/drivers/include/periph/usbdev.h +++ b/drivers/include/periph/usbdev.h @@ -37,22 +37,26 @@ * it's endpoint number. It can simply request an available endpoint from the * usb device with the @ref usbdev_new_ep function. * - * Data transmission is done by requesting the endpoint with a max packet size. - * Memory for this buffer is allocated from dedicated memory of the MCU USB - * peripheral or from a buffer allocated by the peripheral specific usbdev - * struct. Received data from the host ends up at this buffer automatically - * by the low level drivers. Signalling that the data at the specified address - * is ready to be reused is done with the @ref usbdev_ep_ready function by - * supplying a size of 0 for the @p len argument. + * Each interface handler can request multiple endpoints from the usbdev device. + * It must supply the expected maximum endpoint transfer size and other + * properties of the endpoint. A pointer to an usbdev endpoint is returned if + * an endpoint fitting the requirements is available. + * + * Data transmission is done via the @ref usbdev_ep_xmit function. A buffer and + * length must be supplied. Received data from the host ends up at this buffer + * automatically by the low level drivers after reception. For reception the + * maximum expected transfer length must be supplied, equal to the maximum + * endpoint transfer size. The data received can be less than this. * * For transmitting data back to the host, a similar approach is used. The data - * to be transmitted is written to the specified address and the - * @ref usbdev_ep_ready function is called with the size of the data as @p len - * argument. + * to be transmitted is supplied as buffer and the @ref usbdev_ep_xmit function + * is called with the buffer and the size of the data. * - * This approach of setting the address and only indicating new data available - * is done to allow the low level USB peripheral to use DMA to transfer the data - * from and to the MCU memory. + * To ensure that the data buffers adhere to the restrictions of the low level + * USB peripheral memory interface, the specific @ref usbdev_ep_buf_t data type + * must be used. It behaves as a regular `uint8_t` byte buffer, but is + * instantiated with the attributes to ensure that the low level DMA interface + * can use it. * * A callback function is required for signalling events from the driver. The * @ref USBDEV_EVENT_ESR is special in that it indicates that the USB peripheral @@ -75,6 +79,7 @@ #include #include "assert.h" +#include "periph_cpu.h" #include "usb.h" #include "usb/usbopt.h" @@ -93,16 +98,32 @@ typedef struct usbdev usbdev_t; typedef struct usbdev_ep usbdev_ep_t; /** - * @brief Statically allocated buffer space for endpoints. + * @brief USBDEV endpoint buffer CPU-specific requirements * - * When the device doesn't have dedicated memory for endpoint buffers, a - * buffer of this size is allocated to contain the endpoint buffers. Only - * needs to be as big as the total buffer space required by all endpoints + * Can be overridden by periph_cpu if needed by the USB peripheral DMA. */ -#ifndef USBDEV_EP_BUF_SPACE -#define USBDEV_EP_BUF_SPACE 1024 +#ifndef USBDEV_CPU_DMA_REQUIREMENTS +#define USBDEV_CPU_DMA_REQUIREMENTS #endif +/** + * @brief Instantiation type for usbdev endpoint buffers + * + * Functions passing around pointers to these buffers can still use `uint8_t` + * for the argument type. + * + * Example usage: + * + * ``` + * usbdev_ep_buf_t buffer[64]; + * ``` + * + * @note This is a define and not a typedef so that the above works. With a + * typedef it would instantiate an array of aligned uint8_t and not an aligned + * array of uint8_t (assuming the requirement is alignment). + */ +#define usbdev_ep_buf_t USBDEV_CPU_DMA_REQUIREMENTS uint8_t + /** * @brief Number of USB IN and OUT endpoints allocated * @@ -232,8 +253,7 @@ struct usbdev { */ struct usbdev_ep { usbdev_t *dev; /**< USB device this endpoint belongs to */ - uint8_t *buf; /**< Ptr to the data buffer */ - size_t len; /**< Size of the data buffer in bytes */ + size_t len; /**< Endpoint configured max transfer size in bytes */ usb_ep_dir_t dir; /**< Endpoint direction */ usb_ep_type_t type; /**< Endpoint type */ uint8_t num; /**< Endpoint number */ @@ -265,12 +285,12 @@ typedef struct usbdev_driver { * @param[in] dev USB device descriptor * @param[in] type USB endpoint type * @param[in] dir USB endpoint direction - * @param[in] buf_len optimal USB endpoint buffer size + * @param[in] size USB endpoint buffer size * * @return ptr to the new USB endpoint descriptor * @return NULL on error */ - usbdev_ep_t *(*new_ep)(usbdev_t *dev, usb_ep_type_t type, usb_ep_dir_t dir, size_t buf_len); + usbdev_ep_t *(*new_ep)(usbdev_t *dev, usb_ep_type_t type, usb_ep_dir_t dir, size_t size); /** * @brief Get an option value from a given usb device @@ -359,14 +379,22 @@ typedef struct usbdev_driver { void (*ep_esr)(usbdev_ep_t *ep); /** - * @brief Signal data buffer ready for data transmission + * @brief Transmit a data buffer + * + * Ownership of the @p buf is transferred to the usbdev device after calling + * this. Do not modify (or unallocate) the buffer between calling this and + * when it is released via the @ref USBDEV_EVENT_TR_COMPLETE event. * * This clears the stall setting in the endpoint if that is enabled. * + * @note The @p buf passed here must have been declared as + * @ref usbdev_ep_buf_t before so that DMA restrictions are applied to it + * * @param[in] ep USB endpoint descriptor - * @param[in] len length of the data to be transmitted + * @param[inout] buf Buffer with the data to transfer + * @param[in] len (Max) Length of the data to transfer */ - int (*ready)(usbdev_ep_t *ep, size_t len); + int (*xmit)(usbdev_ep_t *ep, uint8_t *buf, size_t len); } usbdev_driver_t; /** @@ -410,16 +438,16 @@ static inline void usbdev_init(usbdev_t *dev) * @param[in] dev USB device descriptor * @param[in] type USB endpoint type * @param[in] dir USB endpoint direction - * @param[in] buf_len optimal USB endpoint buffer size + * @param[in] size Maximum USB endpoint buffer size used * * @return ptr to the new USB endpoint descriptor * @return NULL on error */ static inline usbdev_ep_t * usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, - usb_ep_dir_t dir, size_t buf_len) + usb_ep_dir_t dir, size_t size) { assert(dev); - return dev->driver->new_ep(dev, type, dir, buf_len); + return dev->driver->new_ep(dev, type, dir, size); } /** @@ -564,21 +592,26 @@ static inline void usbdev_ep_esr(usbdev_ep_t *ep) } /** - * @brief Signal data buffer ready for data transmission + * @brief Submit a buffer for a USB endpoint transmission * - * @see @ref usbdev_driver_t::ready + * When dealing with an OUT type endpoint, @p len must be the maximum allowed + * transfer size for the endpoint. The host is allowed to transfer fewer bytes + * than @p len. + * + * @see @ref usbdev_driver_t::xmit * * @pre `(ep != NULL)` * @pre `(ep->dev != NULL)` * - * @param[in] ep USB endpoint descriptor - * @param[in] len length of the data to be transmitted + * @param[in] ep USB endpoint descriptor + * @param[inout] buf Buffer to submit for transmission + * @param[in] len length of the buffer in bytes to be transmitted or received */ -static inline int usbdev_ep_ready(usbdev_ep_t *ep, size_t len) +static inline int usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) { assert(ep); assert(ep->dev); - return ep->dev->driver->ready(ep, len); + return ep->dev->driver->xmit(ep, buf, len); } #ifdef __cplusplus diff --git a/drivers/include/usbdev_mock.h b/drivers/include/usbdev_mock.h index 324dea8c83..d502a02a4d 100644 --- a/drivers/include/usbdev_mock.h +++ b/drivers/include/usbdev_mock.h @@ -40,10 +40,11 @@ typedef enum { * @brief usbdev mock device endpoint */ typedef struct { - usbdev_ep_t ep; /**< Generic endpoint struct */ - usbdev_mock_ep_state_t state; /**< Endpoint state */ - size_t available; /**< Bytes available in the buffer */ - uint8_t *buf_start; /**< Start location of the buffer */ + usbdev_ep_t ep; /**< Generic endpoint struct */ + usbdev_mock_ep_state_t state; /**< Endpoint state */ + size_t available; /**< Bytes available in the buffer */ + uint8_t *target_buf; /**< Buffer as passed by @ref usbdev_ep_xmit */ + uint8_t *buf; /**< Internal mock buffer pointer */ } usbdev_mock_ep_t; /** diff --git a/drivers/usbdev_mock/usbdev_mock.c b/drivers/usbdev_mock/usbdev_mock.c index a3c9a9d3bf..944cef9381 100644 --- a/drivers/usbdev_mock/usbdev_mock.c +++ b/drivers/usbdev_mock/usbdev_mock.c @@ -75,16 +75,15 @@ usbdev_ep_t *_new_ep(usbdev_t *dev, usb_ep_type_t type, usb_ep_dir_t dir, res = &testdev->out[0]; res->ep.num = 0; - res->ep.buf = _out_buf; + res->buf = _out_buf; } else { res = &testdev->in[0]; res->ep.num = 0; - res->ep.buf = _in_buf; + res->buf = _in_buf; } } if (res) { - res->buf_start = res->ep.buf; res->state = EP_STATE_READY; res->available = 0; res->ep.len = buf_len; @@ -190,26 +189,30 @@ void _ep_esr(usbdev_ep_t *ep) ep->num, ep->dir == USB_EP_DIR_OUT ? "out" : "in"); usbdev_mock_ep_t *mock_ep = (usbdev_mock_ep_t *)ep; + if (mock_ep->ep.dir == USB_EP_DIR_OUT) { + memcpy(mock_ep->target_buf, mock_ep->buf, mock_ep->available); + } if (mock_ep->state == EP_STATE_DATA_AVAILABLE) { dev->ep_esr_cb(dev, mock_ep); mock_ep->state = EP_STATE_READY; } } -int _ready(usbdev_ep_t *ep, size_t len) +int _xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len) { DEBUG("[mock]: Readying EP %u, dir %s, len %u\n", ep->num, ep->dir == USB_EP_DIR_OUT ? "out" : "in", (unsigned)len); if (ep->num == 0) { usbdev_mock_t *usbdev_mock = _ep2dev(ep); usbdev_mock_ep_t *mock_ep = (usbdev_mock_ep_t *)ep; - - mock_ep->available = len; - mock_ep->ep.buf += len; + mock_ep->target_buf = buf; + if (ep->dir == USB_EP_DIR_IN) { + memcpy(mock_ep->buf + mock_ep->available, mock_ep->target_buf, len); + mock_ep->available = len; + } mock_ep->state = EP_STATE_DATA_AVAILABLE; usbdev_mock->ready_cb(usbdev_mock, (usbdev_mock_ep_t *)ep, len); - } return 0; } @@ -224,5 +227,5 @@ static const usbdev_driver_t testdriver = { .ep_get = _ep_get, .ep_set = _ep_set, .ep_esr = _ep_esr, - .ready = _ready, + .xmit = _xmit, }; diff --git a/sys/include/usb/usbopt.h b/sys/include/usb/usbopt.h index 900f28273f..db684ebb97 100644 --- a/sys/include/usb/usbopt.h +++ b/sys/include/usb/usbopt.h @@ -91,11 +91,6 @@ typedef enum { */ USBOPT_EP_STALL, - /** - * @brief (usbopt_enable_t) Signal data ready or not ready anymore - */ - USBOPT_EP_READY, - /** * @brief (size_t) Retrieve number of bytes available on endpoint. */ diff --git a/sys/include/usb/usbus/cdc/acm.h b/sys/include/usb/usbus/cdc/acm.h index 6eba372af3..ca8901228b 100644 --- a/sys/include/usb/usbus/cdc/acm.h +++ b/sys/include/usb/usbus/cdc/acm.h @@ -142,6 +142,16 @@ struct usbus_cdcacm_device { usbus_cdcacm_line_state_t state; /**< Current line state */ event_t flush; /**< device2host forced flush event */ usb_req_cdcacm_coding_t coding; /**< Current coding configuration */ + + /** + * @brief Host to device data buffer + */ + usbdev_ep_buf_t out_buf[CONFIG_USBUS_CDC_ACM_BULK_EP_SIZE]; + + /** + * @brief Device to host data buffer + */ + usbdev_ep_buf_t in_buf[CONFIG_USBUS_CDC_ACM_STDIO_BUF_SIZE]; }; /** diff --git a/sys/include/usb/usbus/cdc/ecm.h b/sys/include/usb/usbus/cdc/ecm.h index 6f13514126..f117a32271 100644 --- a/sys/include/usb/usbus/cdc/ecm.h +++ b/sys/include/usb/usbus/cdc/ecm.h @@ -106,12 +106,26 @@ typedef struct usbus_cdcecm_device { char mac_host[13]; /**< host side's MAC address as string */ usbus_string_t mac_str; /**< String context for the host side mac address */ usbus_t *usbus; /**< Ptr to the USBUS context */ - mutex_t out_lock; /**< mutex used for locking netif/USBUS send */ - size_t tx_len; /**< Length of the current tx frame */ - uint8_t in_buf[ETHERNET_FRAME_LEN]; /**< Buffer for the received frames */ + mutex_t out_lock; /**< mutex used for locking netif/USBUS send */ + size_t tx_len; /**< Length of the current tx frame */ size_t len; /**< Length of the current rx frame */ - usbus_cdcecm_notif_t notif; /**< Startup message notification tracker */ - unsigned active_iface; /**< Current active data interface */ + usbus_cdcecm_notif_t notif; /**< Startup message notification tracker */ + unsigned active_iface; /**< Current active data interface */ + + /** + * @brief Buffer for received frames from the host + */ + usbdev_ep_buf_t data_out[ETHERNET_FRAME_LEN]; + + /** + * @brief Host in device out data buffer + */ + usbdev_ep_buf_t data_in[USBUS_CDCECM_EP_DATA_SIZE]; + + /** + * @brief Host out device in control buffer + */ + usbdev_ep_buf_t control_in[USBUS_CDCECM_EP_CTRL_SIZE]; } usbus_cdcecm_device_t; /** diff --git a/sys/include/usb/usbus/control.h b/sys/include/usb/usbus/control.h index 068e85766f..69e8028111 100644 --- a/sys/include/usb/usbus/control.h +++ b/sys/include/usb/usbus/control.h @@ -69,14 +69,24 @@ typedef struct { size_t received_len; /** - * @brief EP0 OUT endpoint + * @brief EP0 OUT endpoint reference */ usbdev_ep_t *out; /** - * @brief EP0 IN endpoint + * @brief EP0 IN endpoint reference */ usbdev_ep_t *in; + + /** + * @brief Host to device control request buffer + */ + usbdev_ep_buf_t out_buf[CONFIG_USBUS_EP0_SIZE]; + + /** + * @brief Device to host control request buffer + */ + usbdev_ep_buf_t in_buf[CONFIG_USBUS_EP0_SIZE]; } usbus_control_handler_t; /** diff --git a/sys/include/usb/usbus/hid.h b/sys/include/usb/usbus/hid.h index a7672796f4..f05191a988 100644 --- a/sys/include/usb/usbus/hid.h +++ b/sys/include/usb/usbus/hid.h @@ -77,6 +77,16 @@ struct usbus_hid_device { usbus_hid_cb_t cb; /**< Callback for data handlers */ event_t tx_ready; /**< Transmit ready event */ mutex_t in_lock; /**< mutex used for locking hid send */ + + /** + * @brief Host to device data buffer + */ + usbdev_ep_buf_t out_buf[CONFIG_USBUS_HID_INTERRUPT_EP_SIZE]; + + /** + * @brief Device to host data buffer + */ + usbdev_ep_buf_t in_buf[CONFIG_USBUS_HID_INTERRUPT_EP_SIZE]; }; /** diff --git a/sys/usb/usbus/cdc/acm/cdc_acm.c b/sys/usb/usbus/cdc/acm/cdc_acm.c index c698275e10..6ea9140db9 100644 --- a/sys/usb/usbus/cdc/acm/cdc_acm.c +++ b/sys/usb/usbus/cdc/acm/cdc_acm.c @@ -305,7 +305,8 @@ static int _control_handler(usbus_t *usbus, usbus_handler_t *handler, usbus_endpoint_t *data_out = usbus_interface_find_endpoint( &cdcacm->iface_data, USB_EP_TYPE_BULK, USB_EP_DIR_OUT); assert(data_out); - usbdev_ep_ready(data_out->ep, 0); + usbdev_ep_xmit(data_out->ep, cdcacm->out_buf, + CONFIG_USBUS_CDC_ACM_BULK_EP_SIZE); usbus_cdc_acm_flush(cdcacm); } else { @@ -331,13 +332,13 @@ static void _handle_in(usbus_cdcacm_device_t *cdcacm, unsigned old = irq_disable(); while (!tsrb_empty(&cdcacm->tsrb)) { int c = tsrb_get_one(&cdcacm->tsrb); - ep->buf[cdcacm->occupied++] = (uint8_t)c; + cdcacm->in_buf[cdcacm->occupied++] = (uint8_t)c; if (cdcacm->occupied >= CONFIG_USBUS_CDC_ACM_BULK_EP_SIZE) { break; } } irq_restore(old); - usbdev_ep_ready(ep, cdcacm->occupied); + usbdev_ep_xmit(ep, cdcacm->in_buf, cdcacm->occupied); } static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler, @@ -351,9 +352,9 @@ static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler, /* Retrieve incoming data */ usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t)); if (len > 0) { - cdcacm->cb(cdcacm, ep->buf, len); + cdcacm->cb(cdcacm, cdcacm->out_buf, len); } - usbdev_ep_ready(ep, 0); + usbdev_ep_xmit(ep, cdcacm->out_buf, CONFIG_USBUS_CDC_ACM_BULK_EP_SIZE); } if ((ep->dir == USB_EP_DIR_IN) && (ep->type == USB_EP_TYPE_BULK)) { cdcacm->occupied = 0; diff --git a/sys/usb/usbus/cdc/ecm/cdc_ecm.c b/sys/usb/usbus/cdc/ecm/cdc_ecm.c index 376ce45087..d9504ba27a 100644 --- a/sys/usb/usbus/cdc/ecm/cdc_ecm.c +++ b/sys/usb/usbus/cdc/ecm/cdc_ecm.c @@ -115,7 +115,7 @@ static void _notify_link_speed(usbus_cdcecm_device_t *cdcecm) { DEBUG("CDC ECM: sending link speed indication\n"); usb_desc_cdcecm_speed_t *notification = - (usb_desc_cdcecm_speed_t *)cdcecm->ep_ctrl->ep->buf; + (usb_desc_cdcecm_speed_t *)cdcecm->control_in; notification->setup.type = USB_SETUP_REQUEST_DEVICE2HOST | USB_SETUP_REQUEST_TYPE_CLASS | USB_SETUP_REQUEST_RECIPIENT_INTERFACE; @@ -126,7 +126,7 @@ static void _notify_link_speed(usbus_cdcecm_device_t *cdcecm) notification->down = CONFIG_USBUS_CDC_ECM_CONFIG_SPEED_DOWNSTREAM; notification->up = CONFIG_USBUS_CDC_ECM_CONFIG_SPEED_UPSTREAM; - usbdev_ep_ready(cdcecm->ep_ctrl->ep, + usbdev_ep_xmit(cdcecm->ep_ctrl->ep, cdcecm->control_in, sizeof(usb_desc_cdcecm_speed_t)); cdcecm->notif = USBUS_CDCECM_NOTIF_SPEED; } @@ -134,7 +134,7 @@ static void _notify_link_speed(usbus_cdcecm_device_t *cdcecm) static void _notify_link_up(usbus_cdcecm_device_t *cdcecm) { DEBUG("CDC ECM: sending link up indication\n"); - usb_setup_t *notification = (usb_setup_t *)cdcecm->ep_ctrl->ep->buf; + usb_setup_t *notification = (usb_setup_t *)cdcecm->control_in; notification->type = USB_SETUP_REQUEST_DEVICE2HOST | USB_SETUP_REQUEST_TYPE_CLASS | USB_SETUP_REQUEST_RECIPIENT_INTERFACE; @@ -142,7 +142,7 @@ static void _notify_link_up(usbus_cdcecm_device_t *cdcecm) notification->value = 1; notification->index = cdcecm->iface_ctrl.idx; notification->length = 0; - usbdev_ep_ready(cdcecm->ep_ctrl->ep, sizeof(usb_setup_t)); + usbdev_ep_xmit(cdcecm->ep_ctrl->ep, cdcecm->control_in, sizeof(usb_setup_t)); cdcecm->notif = USBUS_CDCECM_NOTIF_LINK_UP; } @@ -251,7 +251,8 @@ static int _control_handler(usbus_t *usbus, usbus_handler_t *handler, setup->value); cdcecm->active_iface = (uint8_t)setup->value; if (cdcecm->active_iface == 1) { - usbdev_ep_ready(cdcecm->ep_out->ep, 0); + usbdev_ep_xmit(cdcecm->ep_out->ep, cdcecm->data_out, + USBUS_CDCECM_EP_DATA_SIZE); _notify_link_up(cdcecm); } break; @@ -290,36 +291,15 @@ static void _handle_tx_xmit(event_t *ev) mutex_unlock(&cdcecm->out_lock); } /* Data prepared by netdev_send, signal ready to usbus */ - usbdev_ep_ready(cdcecm->ep_in->ep, cdcecm->tx_len); -} - -static void _handle_rx_flush(usbus_cdcecm_device_t *cdcecm) -{ - cdcecm->len = 0; + usbdev_ep_xmit(cdcecm->ep_in->ep, cdcecm->data_in, cdcecm->tx_len); } static void _handle_rx_flush_ev(event_t *ev) { usbus_cdcecm_device_t *cdcecm = container_of(ev, usbus_cdcecm_device_t, rx_flush); - - usbdev_ep_ready(cdcecm->ep_out->ep, 0); - _handle_rx_flush(cdcecm); -} - -static void _store_frame_chunk(usbus_cdcecm_device_t *cdcecm, size_t len) -{ - uint8_t *buf = cdcecm->ep_out->ep->buf; - - /* Truncate if it exceeds the expected MTU size. */ - /* TODO: Should be converted to an endpoint halt after #17090 is merged */ - if (cdcecm->len + len < ETHERNET_FRAME_LEN) { - memcpy(cdcecm->in_buf + cdcecm->len, buf, len); - cdcecm->len += len; - } - if (len < USBUS_CDCECM_EP_DATA_SIZE) { - netdev_trigger_event_isr(&cdcecm->netdev); - } + cdcecm->len = 0; /* Flush packet */ + usbdev_ep_xmit(cdcecm->ep_out->ep, cdcecm->data_out, USBUS_CDCECM_EP_DATA_SIZE); } static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler, @@ -335,9 +315,14 @@ static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler, } size_t len = 0; usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t)); - _store_frame_chunk(cdcecm, len); + cdcecm->len += len; if (len == USBUS_CDCECM_EP_DATA_SIZE) { - usbdev_ep_ready(ep, 0); + /* ready next chunk */ + usbdev_ep_xmit(ep, cdcecm->data_out + cdcecm->len, + USBUS_CDCECM_EP_DATA_SIZE); + } + else { + netdev_trigger_event_isr(&cdcecm->netdev); } } else if (ep == cdcecm->ep_in->ep) { @@ -354,9 +339,9 @@ static void _handle_reset(usbus_t *usbus, usbus_handler_t *handler) usbus_cdcecm_device_t *cdcecm = (usbus_cdcecm_device_t *)handler; DEBUG("CDC ECM: Reset\n"); - _handle_rx_flush(cdcecm); _handle_in_complete(usbus, handler); cdcecm->notif = USBUS_CDCECM_NOTIF_NONE; + cdcecm->len = 0; /* Flush received data */ cdcecm->active_iface = 0; mutex_unlock(&cdcecm->out_lock); } diff --git a/sys/usb/usbus/cdc/ecm/cdc_ecm_netdev.c b/sys/usb/usbus/cdc/ecm/cdc_ecm_netdev.c index 2009569990..587da8d4b6 100644 --- a/sys/usb/usbus/cdc/ecm/cdc_ecm_netdev.c +++ b/sys/usb/usbus/cdc/ecm/cdc_ecm_netdev.c @@ -59,7 +59,7 @@ static int _send(netdev_t *netdev, const iolist_t *iolist) { assert(iolist); usbus_cdcecm_device_t *cdcecm = _netdev_to_cdcecm(netdev); - uint8_t *buf = cdcecm->ep_in->ep->buf; + uint8_t *buf = cdcecm->data_in; const iolist_t *iolist_start = iolist; size_t len = iolist_size(iolist); /* interface with alternative function ID 1 is the interface containing the @@ -142,7 +142,8 @@ static int _recv(netdev_t *netdev, void *buf, size_t max_len, void *info) return pktlen; } if (pktlen <= max_len) { - memcpy(buf, cdcecm->in_buf, pktlen); + /* Copy the received data from the host to the netif buffer */ + memcpy(buf, cdcecm->data_out, pktlen); } _signal_rx_flush(cdcecm); return (pktlen <= max_len) ? (int)pktlen : -ENOBUFS; diff --git a/sys/usb/usbus/hid/hid.c b/sys/usb/usbus/hid/hid.c index d35e357014..33d95eaa6d 100644 --- a/sys/usb/usbus/hid/hid.c +++ b/sys/usb/usbus/hid/hid.c @@ -77,7 +77,7 @@ static void _handle_tx_ready(event_t *ev) { usbus_hid_device_t *hid = container_of(ev, usbus_hid_device_t, tx_ready); - usbdev_ep_ready(hid->ep_in->ep, hid->occupied); + usbdev_ep_xmit(hid->ep_in->ep, hid->in_buf, hid->occupied); } void usbus_hid_init(usbus_t *usbus, usbus_hid_device_t *hid, usbus_hid_cb_t cb, @@ -138,7 +138,8 @@ static void _init(usbus_t *usbus, usbus_handler_t *handler) usbus_enable_endpoint(hid->ep_out); /* signal that INTERRUPT OUT is ready to receive data */ - usbdev_ep_ready(hid->ep_out->ep, 0); + usbdev_ep_xmit(hid->ep_out->ep, hid->out_buf, + CONFIG_USBUS_HID_INTERRUPT_EP_SIZE); usbus_add_interface(usbus, &hid->iface); } @@ -222,8 +223,8 @@ static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler, size_t len; usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t)); if (len > 0) { - hid->cb(hid, ep->buf, len); + hid->cb(hid, hid->out_buf, len); } - usbdev_ep_ready(ep, 0); + usbdev_ep_xmit(ep, hid->out_buf, CONFIG_USBUS_HID_INTERRUPT_EP_SIZE); } } diff --git a/sys/usb/usbus/hid/hid_io.c b/sys/usb/usbus/hid/hid_io.c index a7b9137de5..d1267eddca 100644 --- a/sys/usb/usbus/hid/hid_io.c +++ b/sys/usb/usbus/hid/hid_io.c @@ -50,7 +50,7 @@ int usb_hid_io_read_timeout(void *buffer, size_t len, uint32_t timeout) void usb_hid_io_write(const void *buffer, size_t len) { assert(buffer); - uint8_t *buffer_ep = hid.ep_in->ep->buf; + uint8_t *buffer_ep = hid.in_buf; uint16_t max_size = hid.ep_in->maxpacketsize; size_t offset = 0; diff --git a/sys/usb/usbus/usbus.c b/sys/usb/usbus/usbus.c index 94f344cbdc..a58453aab2 100644 --- a/sys/usb/usbus/usbus.c +++ b/sys/usb/usbus/usbus.c @@ -166,7 +166,7 @@ usbus_endpoint_t *usbus_add_endpoint(usbus_t *usbus, usbus_interface_t *iface, if (usbdev_ep) { ep = dir == USB_EP_DIR_IN ? &usbus->ep_in[usbdev_ep->num] : &usbus->ep_out[usbdev_ep->num]; - ep->maxpacketsize = usbdev_ep->len; + ep->maxpacketsize = len; ep->ep = usbdev_ep; if (iface) { ep->next = iface->ep; @@ -325,6 +325,7 @@ static void _event_cb(usbdev_t *usbdev, usbdev_event_t event) sizeof(uint8_t)); flag = USBUS_HANDLER_FLAG_RESET; msg = USBUS_EVENT_USB_RESET; + DEBUG("usbus: USB reset detected\n"); break; case USBDEV_EVENT_SUSPEND: DEBUG("usbus: USB suspend detected\n"); diff --git a/sys/usb/usbus/usbus_control.c b/sys/usb/usbus/usbus_control.c index ba6a1762d5..d86f9fae44 100644 --- a/sys/usb/usbus/usbus_control.c +++ b/sys/usb/usbus/usbus_control.c @@ -292,11 +292,11 @@ static void _recv_setup(usbus_t *usbus, usbus_control_handler_t *handler) /* Signal ready for new data in case there is more */ if (handler->received_len < pkt->length) { handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_OUTDATA; - usbdev_ep_ready(handler->out, 1); + usbdev_ep_xmit(handler->out, handler->out_buf, CONFIG_USBUS_EP0_SIZE); } else { handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_INACK; - usbdev_ep_ready(handler->in, 0); + usbdev_ep_xmit(handler->in, handler->in_buf, 0); } } @@ -313,7 +313,7 @@ static void _usbus_config_ep0(usbus_control_handler_t *ep0_handler) sizeof(usbopt_enable_t)); usbdev_ep_set(ep0_handler->out, USBOPT_EP_ENABLE, &enable, sizeof(usbopt_enable_t)); - usbdev_ep_ready(ep0_handler->out, 0); + usbdev_ep_xmit(ep0_handler->out, ep0_handler->out_buf, CONFIG_USBUS_EP0_SIZE); } uint8_t *usbus_control_get_out_data(usbus_t *usbus, size_t *len) @@ -323,10 +323,9 @@ uint8_t *usbus_control_get_out_data(usbus_t *usbus, size_t *len) assert(len); assert(handler->control_request_state == USBUS_CONTROL_REQUEST_STATE_OUTDATA); - usbdev_ep_t *ep_out = handler->out; - usbdev_ep_get(ep_out, USBOPT_EP_AVAILABLE, + usbdev_ep_get(handler->out, USBOPT_EP_AVAILABLE, len, sizeof(size_t)); - return ep_out->buf; + return handler->out_buf; } static void _init(usbus_t *usbus, usbus_handler_t *handler) @@ -357,14 +356,14 @@ static int _handle_tr_complete(usbus_t *usbus, } ep0_handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY; /* Ready for new control request */ - usbdev_ep_ready(ep0_handler->out, 0); + usbdev_ep_xmit(ep0_handler->out, ep0_handler->out_buf, CONFIG_USBUS_EP0_SIZE); } break; case USBUS_CONTROL_REQUEST_STATE_OUTACK: if (ep->dir == USB_EP_DIR_OUT) { ep0_handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY; /* Ready for new control request */ - usbdev_ep_ready(ep0_handler->out, 0); + usbdev_ep_xmit(ep0_handler->out, ep0_handler->out_buf, CONFIG_USBUS_EP0_SIZE); } break; case USBUS_CONTROL_REQUEST_STATE_INDATA: @@ -375,7 +374,7 @@ static int _handle_tr_complete(usbus_t *usbus, } else { /* Ready out ZLP */ - usbdev_ep_ready(ep0_handler->out, 0); + usbdev_ep_xmit(ep0_handler->out, ep0_handler->out_buf, CONFIG_USBUS_EP0_SIZE); ep0_handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_OUTACK; } } @@ -395,7 +394,7 @@ static int _handle_tr_complete(usbus_t *usbus, case USBUS_CONTROL_REQUEST_STATE_READY: if (ep->dir == USB_EP_DIR_OUT) { memset(&ep0_handler->slicer, 0, sizeof(usbus_control_slicer_t)); - memcpy(&ep0_handler->setup, ep0_handler->out->buf, + memcpy(&ep0_handler->setup, ep0_handler->out_buf, sizeof(usb_setup_t)); ep0_handler->received_len = 0; ep0_handler->slicer.reqlen = ep0_handler->setup.length; diff --git a/sys/usb/usbus/usbus_control_slicer.c b/sys/usb/usbus/usbus_control_slicer.c index 567ee511aa..865c1972c1 100644 --- a/sys/usb/usbus/usbus_control_slicer.c +++ b/sys/usb/usbus/usbus_control_slicer.c @@ -69,7 +69,7 @@ size_t usbus_control_slicer_put_bytes(usbus_t *usbus, const uint8_t *buf, size_t start_offset = bldr->cur - bldr->start + byte_offset; bldr->cur += len; bldr->len += byte_len; - memcpy(ep0->in->buf + start_offset, buf + byte_offset, byte_len); + memcpy(ep0->in_buf + start_offset, buf + byte_offset, byte_len); return byte_len; } @@ -81,7 +81,7 @@ size_t usbus_control_slicer_put_char(usbus_t *usbus, char c) /* Only copy the char if it is within the window */ if ((bldr->start <= bldr->cur) && (bldr->cur < end)) { - uint8_t *pos = ep0->in->buf + bldr->cur - bldr->start; + uint8_t *pos = ep0->in_buf + bldr->cur - bldr->start; *pos = c; bldr->cur++; bldr->len++; @@ -99,5 +99,5 @@ void usbus_control_slicer_ready(usbus_t *usbus) len = len < bldr->reqlen - bldr->start ? len : bldr->reqlen - bldr->start; bldr->transferred += len; - usbdev_ep_ready(ep0->in, len); + usbdev_ep_xmit(ep0->in, ep0->in_buf, len); } diff --git a/tests/usbus/main.c b/tests/usbus/main.c index a2ba8b4f8f..3ca6bf32dc 100644 --- a/tests/usbus/main.c +++ b/tests/usbus/main.c @@ -146,7 +146,7 @@ static void _test_sequence(usbdev_mock_t *dev) case TESTPHASE_RESET: next_phase = TESTPHASE_REQ_DEV_INIT; DEBUG("[test]: Requesting device descriptor\n"); - _build_conf_req(dev->out[0].ep.buf, 8); /* initial config request */ + _build_conf_req(dev->out[0].buf, 8); /* initial config request */ dev->req_len = 8; dev->out[0].state = EP_STATE_DATA_AVAILABLE; dev->out[0].available = 8; @@ -157,7 +157,7 @@ static void _test_sequence(usbdev_mock_t *dev) DEBUG("[test]: validating device descriptor\n"); TEST_ASSERT_EQUAL_INT(dev->in[0].available, 8); _validate_device_desc_init( - (usb_descriptor_device_t *)dev->in[0].buf_start); + (usb_descriptor_device_t *)dev->in[0].buf); /* Reset device */ DEBUG("[test]: Signalling second USB reset condition\n"); dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_RESET); @@ -166,7 +166,7 @@ static void _test_sequence(usbdev_mock_t *dev) case TESTPHASE_RESET2: next_phase = TESTPHASE_SET_ADDRESS; DEBUG("[test]: Set USB address\n"); - _build_set_addr(dev->out[0].ep.buf); + _build_set_addr(dev->out[0].buf); dev->req_len = 0; dev->out[0].state = EP_STATE_DATA_AVAILABLE; dev->out[0].available = 8; @@ -175,7 +175,7 @@ static void _test_sequence(usbdev_mock_t *dev) case TESTPHASE_SET_ADDRESS: next_phase = TESTPHASE_REQ_DEV_FULL; DEBUG("[test]: Requesting full device descriptor\n"); - _build_conf_req(dev->out[0].ep.buf, + _build_conf_req(dev->out[0].buf, sizeof(usb_descriptor_device_t)); dev->req_len = sizeof(usb_descriptor_device_t); dev->out[0].state = EP_STATE_DATA_AVAILABLE; @@ -187,7 +187,7 @@ static void _test_sequence(usbdev_mock_t *dev) sizeof(usb_descriptor_device_t)); DEBUG("[test]: Validating full descriptor\n"); _validate_device_desc_init( - (usb_descriptor_device_t *)dev->in[0].buf_start); + (usb_descriptor_device_t *)dev->in[0].buf); next_phase = TESTPHASE_FINAL; dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_ESR); @@ -261,8 +261,6 @@ static void _handle_data(usbdev_mock_t *dev, usbdev_mock_ep_t *ep, size_t len) if (ep->available == dev->req_len) { DEBUG("[data]: Full data received from stack\n"); req_phase = TEST_REQ_PHASE_OUTACK; - /* Reset buffer ptr to the start */ - ep->ep.buf = ep->buf_start; } else { DEBUG("[data]: Expecting more data from stack: %u/%u\n",