Merge pull request #17064 from bergzand/pr/usbdev/xmit

USB: refactor to xmit-based API
This commit is contained in:
Dylan Laduranty 2021-11-17 09:07:00 +01:00 committed by GitHub
commit aa8608eff5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 295 additions and 309 deletions

View File

@ -36,11 +36,6 @@ extern "C" {
*/ */
#define NRF_USB_NUM_PERIPH 1 #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 * 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_ins[NRF_USB_NUM_EP]; /**< IN type endpoints */
usbdev_ep_t ep_outs[ NRF_USB_NUM_EP]; /**< OUT type endpoints */ usbdev_ep_t ep_outs[ NRF_USB_NUM_EP]; /**< OUT type endpoints */
NRF_USBD_Type *device; /**< Ptr to the device registers */ 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_setup_state_t sstate; /**< Setup request state machine */
} nrfusb_t; } nrfusb_t;

View File

@ -263,6 +263,17 @@ void spi_twi_irq_register_spi(NRF_SPIM_Type *bus,
*/ */
void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus, void spi_twi_irq_register_i2c(NRF_TWIM_Type *bus,
spi_twi_irq_cb_t cb, void *arg); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -27,6 +27,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include "architecture.h"
#include "cpu.h" #include "cpu.h"
#include "nrfusb.h" #include "nrfusb.h"
#include "periph/usbdev.h" #include "periph/usbdev.h"
@ -42,12 +43,12 @@ static nrfusb_t _usbdevs[NRF_USB_NUM_PERIPH];
static void _init(usbdev_t *usbdev); static void _init(usbdev_t *usbdev);
static int _get(usbdev_t *usbdev, usbopt_t opt, void *value, size_t max_len); 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 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 _esr(usbdev_t *usbdev);
static void _ep_init(usbdev_ep_t *ep); 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_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_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 void _ep_esr(usbdev_ep_t *ep);
static const usbdev_driver_t _driver = { static const usbdev_driver_t _driver = {
@ -60,7 +61,7 @@ static const usbdev_driver_t _driver = {
.ep_get = _ep_get, .ep_get = _ep_get,
.ep_set = _ep_set, .ep_set = _ep_set,
.ep_esr = _ep_esr, .ep_esr = _ep_esr,
.ready = _ep_ready, .xmit = _ep_xmit,
}; };
static inline usbdev_ep_t *_get_ep_in(nrfusb_t *usbdev, unsigned num) 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; 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) static void _copy_setup(usbdev_ep_t *ep)
{ {
nrfusb_t *usbdev = (nrfusb_t*)ep->dev; nrfusb_t *usbdev = (nrfusb_t*)ep->dev;
usb_setup_t *setup = (usb_setup_t *)ep->buf; usb_setup_t *setup = (usb_setup_t*)(intptr_t)usbdev->device->EPOUT[0].PTR;
setup->type = usbdev->device->BMREQUESTTYPE; setup->type = usbdev->device->BMREQUESTTYPE;
setup->request = usbdev->device->BREQUEST; 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) 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"); 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; nrfusb_t *usbdev = (nrfusb_t *)dev;
poweron(usbdev); poweron(usbdev);
usbdev->used = 0;
usbdev->sstate = NRFUSB_SETUP_READY; usbdev->sstate = NRFUSB_SETUP_READY;
/* Enable a set of interrupts */ /* Enable a set of interrupts */
@ -350,7 +327,7 @@ static int _set(usbdev_t *dev, usbopt_t opt,
static usbdev_ep_t *_new_ep(usbdev_t *dev, static usbdev_ep_t *_new_ep(usbdev_t *dev,
usb_ep_type_t type, usb_ep_type_t type,
usb_ep_dir_t dir, 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 */ /* The IP supports all types for all endpoints */
@ -374,23 +351,9 @@ static usbdev_ep_t *_new_ep(usbdev_t *dev,
if (res) { if (res) {
res->dev = dev; res->dev = dev;
res->dir = dir; 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->type = type;
res->dev = dev; res->len = len;
} DEBUG("nrfusb: Allocated new ep (%d %s)\n", res->num, res->dir == USB_EP_DIR_OUT ? "OUT" : "IN");
else {
DEBUG("nrfusb: error allocating buffer space\n");
}
} }
return res; return res;
} }
@ -431,8 +394,6 @@ 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) { if (ep->num == 0) {
usbdev->device->EVENTS_EP0SETUP = 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); _ep_set_stall(ep, *(usbopt_enable_t *)value);
res = sizeof(usbopt_enable_t); res = sizeof(usbopt_enable_t);
break; 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: default:
DEBUG("Unhandled set call: 0x%x\n", opt); DEBUG("Unhandled set call: 0x%x\n", opt);
break; break;
@ -507,9 +461,11 @@ static int _ep_set(usbdev_ep_t *ep, usbopt_ep_t opt,
return res; 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; 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 (ep->dir == USB_EP_DIR_IN) {
if (len == 0 && usbdev->sstate == NRFUSB_SETUP_WRITE) { 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; usbdev->sstate = NRFUSB_SETUP_ACKIN;
} }
else { 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->EPIN[0].MAXCNT = (uint32_t)len;
usbdev->device->TASKS_STARTEPIN[0] = 1; usbdev->device->TASKS_STARTEPIN[0] = 1;
} }
} }
else { else {
usbdev->device->EPOUT[0].PTR = (uint32_t)(intptr_t)buf;
usbdev->device->EPOUT[0].MAXCNT = (uint32_t)len;
/* USB_EP_DIR_OUT */ /* USB_EP_DIR_OUT */
if (usbdev->sstate == NRFUSB_SETUP_READ) { if (usbdev->sstate == NRFUSB_SETUP_READ) {
usbdev->device->TASKS_EP0STATUS = 1; usbdev->device->TASKS_EP0STATUS = 1;
@ -537,20 +495,23 @@ static int _ep0_ready(usbdev_ep_t *ep, size_t len)
return 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; nrfusb_t *usbdev = (nrfusb_t *)ep->dev;
if (ep->num == 0) { if (ep->num == 0) {
/* Endpoint 0 requires special handling as per datasheet sec 6.35.9 */ /* 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) { 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; usbdev->device->EPIN[ep->num].MAXCNT = (uint32_t)len;
_ep_dma_in(ep); _ep_dma_in(ep);
} }
else { 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 */ /* Write nonzero value to EPOUT to indicate ready */
usbdev->device->SIZE.EPOUT[ep->num] = 1; usbdev->device->SIZE.EPOUT[ep->num] = 1;
} }

View File

@ -813,6 +813,16 @@ typedef struct {
} sam0_common_gmac_config_t; } sam0_common_gmac_config_t;
#endif #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 * @brief USB peripheral parameters
*/ */

View File

@ -31,11 +31,6 @@
extern "C" { extern "C" {
#endif #endif
/**
* USB endpoint buffer space
*/
#define SAM_USB_BUF_SPACE USBDEV_EP_BUF_SPACE
/** /**
* Number of USB IN and OUT endpoints * Number of USB IN and OUT endpoints
*/ */
@ -49,11 +44,6 @@ typedef struct {
const sam0_common_usb_config_t *config; /**< USB peripheral config */ const sam0_common_usb_config_t *config; /**< USB peripheral config */
UsbDeviceDescBank banks[2 * SAM_USB_NUM_EP]; /**< Device descriptor banks */ UsbDeviceDescBank banks[2 * SAM_USB_NUM_EP]; /**< Device descriptor banks */
usbdev_ep_t endpoints[2 * SAM_USB_NUM_EP]; /**< Endpoints */ 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 */ bool suspended; /**< Suspend active */
} sam0_common_usb_t; } sam0_common_usb_t;

View File

@ -22,6 +22,7 @@
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include "architecture.h"
#include "cpu.h" #include "cpu.h"
#include "cpu_conf.h" #include "cpu_conf.h"
#include "periph/gpio.h" #include "periph/gpio.h"
@ -46,12 +47,11 @@ static sam0_common_usb_t _usbdevs[USB_INST_NUM];
const usbdev_driver_t driver; const usbdev_driver_t driver;
static void _usbdev_ep_init(usbdev_ep_t *ep); 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, 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 _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) 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; 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) static int _bank_set_size(usbdev_ep_t *ep)
{ {
UsbDeviceDescBank *bank = _bank_from_ep(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, 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; sam0_common_usb_t *usbdev = (sam0_common_usb_t *)dev;
/* The IP supports all types for all endpoints */ /* 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) { if (res) {
res->dev = dev; res->dev = dev;
res->dir = dir; 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->type = type;
res->dev = dev; res->len = size;
} _bank_set_size(res);
} }
return res; return res;
} }
@ -334,7 +319,6 @@ static void _usbdev_init(usbdev_t *dev)
/* Only one usb device on this board */ /* Only one usb device on this board */
sam0_common_usb_t *usbdev = (sam0_common_usb_t *)dev; sam0_common_usb_t *usbdev = (sam0_common_usb_t *)dev;
usbdev->used = 0;
/* Set GPIO */ /* Set GPIO */
gpio_init(usbdev->config->dp, GPIO_IN); gpio_init(usbdev->config->dp, GPIO_IN);
gpio_init(usbdev->config->dm, 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); _ep_set_stall(ep, *(usbopt_enable_t *)value);
res = sizeof(usbopt_enable_t); res = sizeof(usbopt_enable_t);
break; 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: default:
DEBUG("sam_usb: Unhandled set call: 0x%x\n", opt); DEBUG("sam_usb: Unhandled set call: 0x%x\n", opt);
break; break;
@ -705,23 +679,13 @@ static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt,
return res; return res;
} }
static int _ep_unready(usbdev_ep_t *ep) static int _usbdev_ep_xmit(usbdev_ep_t *ep, uint8_t *buf, size_t len)
{
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)
{ {
UsbDeviceEndpoint *ep_reg = _ep_reg_from_ep(ep); 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) { if (ep->dir == USB_EP_DIR_IN) {
_disable_ep_stall_in(ep_reg); _disable_ep_stall_in(ep_reg);
_bank_from_ep(ep)->PCKSIZE.bit.BYTE_COUNT = len; _bank_from_ep(ep)->PCKSIZE.bit.BYTE_COUNT = len;
@ -803,5 +767,5 @@ const usbdev_driver_t driver = {
.ep_get = _usbdev_ep_get, .ep_get = _usbdev_ep_get,
.ep_set = _usbdev_ep_set, .ep_set = _usbdev_ep_set,
.ep_esr = _usbdev_ep_esr, .ep_esr = _usbdev_ep_esr,
.ready = _usbdev_ep_ready, .xmit = _usbdev_ep_xmit,
}; };

View File

@ -782,6 +782,16 @@ typedef struct {
} i2c_timing_param_t; } i2c_timing_param_t;
#endif #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. * @brief USB OTG peripheral type.
* *

View File

@ -56,17 +56,6 @@ extern "C" {
#error Unknown USB peripheral version #error Unknown USB peripheral version
#endif #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 * @brief Number of endpoints available with the OTG FS peripheral
* including the control endpoint * including the control endpoint
@ -121,17 +110,23 @@ extern "C" {
#endif #endif
#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 * @brief stm32 USB OTG peripheral device context
*/ */
typedef struct { typedef struct {
usbdev_t usbdev; /**< Inherited usbdev struct */ usbdev_t usbdev; /**< Inherited usbdev struct */
const stm32_usb_otg_fshs_config_t *config; /**< USB peripheral config */ 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 */ size_t fifo_pos; /**< FIFO space occupied */
usbdev_ep_t *in; /**< In endpoints */ 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 */ bool suspend; /**< Suspend status */
} stm32_usb_otg_fshs_t; } stm32_usb_otg_fshs_t;

View File

@ -23,6 +23,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include "architecture.h"
#include "bitarithm.h" #include "bitarithm.h"
#include "ztimer.h" #include "ztimer.h"
#include "cpu.h" #include "cpu.h"
@ -101,7 +102,7 @@
/* List of instantiated USB peripherals */ /* List of instantiated USB peripherals */
static stm32_usb_otg_fshs_t _usbdevs[USBDEV_NUMOF] = { 0 }; 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]; static usbdev_ep_t _in[_TOTAL_NUM_ENDPOINTS];
/* Forward declaration for the usb device driver */ /* 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) { if (num >= STM32_USB_OTG_FS_NUM_EP) {
return NULL; 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) #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); 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, 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; stm32_usb_otg_fshs_t *usbdev = (stm32_usb_otg_fshs_t *)dev;
usbdev_ep_t *ep = NULL; 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]; ep = &usbdev->in[0];
} }
else { else {
ep = &usbdev->out[0]; ep = &usbdev->out[0].ep;
} }
ep->num = 0; ep->num = 0;
} }
@ -516,19 +507,14 @@ static usbdev_ep_t *_usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type,
} }
if (ep && ep->type == USB_EP_TYPE_NONE) { 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->dir = dir;
ep->type = type; ep->type = type;
ep->dev = dev; ep->dev = dev;
ep->len = buf_len; ep->len = 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) { if (ep->dir == USB_EP_DIR_IN && ep->num != 0) {
_configure_tx_fifo(usbdev, ep->num, ep->len); _configure_tx_fifo(usbdev, ep->num, ep->len);
} }
} }
}
return ep; return ep;
} }
@ -922,10 +908,12 @@ static int _usbdev_ep_set(usbdev_ep_t *ep, usbopt_ep_t opt,
return res; 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; stm32_usb_otg_fshs_t *usbdev = (stm32_usb_otg_fshs_t *)ep->dev;
const stm32_usb_otg_fshs_config_t *conf = usbdev->config; 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) { if (ep->dir == USB_EP_DIR_IN) {
/* Abort when the endpoint is not active, prevents hangs, /* 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)) { 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 /* 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)) { if (len > 0 && !_uses_dma(conf)) {
/* The FIFO requires 32 bit word reads/writes */ /* The FIFO requires 32 bit word reads/writes */
size_t words = (len + 3) / 4; 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*/ * 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); __O uint32_t *fifo = _tx_fifo(conf, ep->num);
for (size_t i = 0; i < words; i++) { for (size_t i = 0; i < words; i++) {
fifo[i] = ep_buf[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)) { 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 */ /* 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; const stm32_usb_otg_fshs_config_t *conf = usbdev->config;
/* Pop status from the receive fifo status register */ /* Pop status from the receive fifo status register */
uint32_t status = _global_regs(conf)->GRXSTSP; uint32_t status = _global_regs(conf)->GRXSTSP;
@ -1029,13 +1021,12 @@ static void _read_packet(usbdev_ep_t *ep)
* complete status*/ * complete status*/
if (pkt_status == STM32_PKTSTS_DATA_UPDT || if (pkt_status == STM32_PKTSTS_DATA_UPDT ||
pkt_status == STM32_PKTSTS_SETUP_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 #ifdef STM32_USB_OTG_CID_2x
/* CID 2x doesn't signal SETUP_COMP on non-zero length packets, signal /* CID 2x doesn't signal SETUP_COMP on non-zero length packets, signal
* the TR_COMPLETE event immediately */ * the TR_COMPLETE event immediately */
if (ep->num == 0 && len) { if (st_ep->ep.num == 0 && len) {
usbdev->usbdev.epcb(&usbdev->out[ep->num], usbdev->usbdev.epcb(&st_ep->ep, USBDEV_EVENT_TR_COMPLETE);
USBDEV_EVENT_TR_COMPLETE);
} }
#endif /* STM32_USB_OTG_CID_2x */ #endif /* STM32_USB_OTG_CID_2x */
} }
@ -1043,7 +1034,7 @@ static void _read_packet(usbdev_ep_t *ep)
* status is skipped */ * status is skipped */
else if (pkt_status == STM32_PKTSTS_XFER_COMP || else if (pkt_status == STM32_PKTSTS_XFER_COMP ||
pkt_status == STM32_PKTSTS_SETUP_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) && if ((_global_regs(conf)->GINTSTS & USB_OTG_GINTSTS_RXFLVL) &&
(_global_regs(conf)->GRXSTSR & USB_OTG_GRXSTSP_EPNUM_Msk) == ep->num && (_global_regs(conf)->GRXSTSR & USB_OTG_GRXSTSP_EPNUM_Msk) == ep->num &&
!_uses_dma(conf)) { !_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 */ /* Transfer complete seems only reliable when used with DMA */
else if (_out_regs(conf, ep->num)->DOEPINT & USB_OTG_DOEPINT_XFRC) { 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) { if (active_ep) {
unsigned epnum = bitarithm_lsb(active_ep); unsigned epnum = bitarithm_lsb(active_ep);
if (epnum >= STM32_USB_OTG_REG_EP_OUT_OFFSET) { 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); USBDEV_EVENT_ESR);
} }
else { else {
@ -1121,7 +1112,7 @@ void _isr_common(stm32_usb_otg_fshs_t *usbdev)
if (status & USB_OTG_GINTSTS_RXFLVL) { if (status & USB_OTG_GINTSTS_RXFLVL) {
unsigned epnum = _global_regs(conf)->GRXSTSR & unsigned epnum = _global_regs(conf)->GRXSTSR &
USB_OTG_GRXSTSP_EPNUM_Msk; 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 & else if (_global_regs(conf)->GINTSTS &
(USB_OTG_GINTSTS_OEPINT | USB_OTG_GINTSTS_IEPINT)) { (USB_OTG_GINTSTS_OEPINT | USB_OTG_GINTSTS_IEPINT)) {
@ -1166,5 +1157,5 @@ const usbdev_driver_t driver = {
.ep_get = _usbdev_ep_get, .ep_get = _usbdev_ep_get,
.ep_set = _usbdev_ep_set, .ep_set = _usbdev_ep_set,
.ep_esr = _usbdev_ep_esr, .ep_esr = _usbdev_ep_esr,
.ready = _usbdev_ep_ready, .xmit = _usbdev_ep_xmit,
}; };

View File

@ -37,22 +37,26 @@
* it's endpoint number. It can simply request an available endpoint from the * it's endpoint number. It can simply request an available endpoint from the
* usb device with the @ref usbdev_new_ep function. * usb device with the @ref usbdev_new_ep function.
* *
* Data transmission is done by requesting the endpoint with a max packet size. * Each interface handler can request multiple endpoints from the usbdev device.
* Memory for this buffer is allocated from dedicated memory of the MCU USB * It must supply the expected maximum endpoint transfer size and other
* peripheral or from a buffer allocated by the peripheral specific usbdev * properties of the endpoint. A pointer to an usbdev endpoint is returned if
* struct. Received data from the host ends up at this buffer automatically * an endpoint fitting the requirements is available.
* 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 * Data transmission is done via the @ref usbdev_ep_xmit function. A buffer and
* supplying a size of 0 for the @p len argument. * 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 * 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 * to be transmitted is supplied as buffer and the @ref usbdev_ep_xmit function
* @ref usbdev_ep_ready function is called with the size of the data as @p len * is called with the buffer and the size of the data.
* argument.
* *
* This approach of setting the address and only indicating new data available * To ensure that the data buffers adhere to the restrictions of the low level
* is done to allow the low level USB peripheral to use DMA to transfer the data * USB peripheral memory interface, the specific @ref usbdev_ep_buf_t data type
* from and to the MCU memory. * 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 * 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 * @ref USBDEV_EVENT_ESR is special in that it indicates that the USB peripheral
@ -75,6 +79,7 @@
#include <stddef.h> #include <stddef.h>
#include "assert.h" #include "assert.h"
#include "periph_cpu.h"
#include "usb.h" #include "usb.h"
#include "usb/usbopt.h" #include "usb/usbopt.h"
@ -93,16 +98,32 @@ typedef struct usbdev usbdev_t;
typedef struct usbdev_ep usbdev_ep_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 * Can be overridden by periph_cpu if needed by the USB peripheral DMA.
* 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
*/ */
#ifndef USBDEV_EP_BUF_SPACE #ifndef USBDEV_CPU_DMA_REQUIREMENTS
#define USBDEV_EP_BUF_SPACE 1024 #define USBDEV_CPU_DMA_REQUIREMENTS
#endif #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 * @brief Number of USB IN and OUT endpoints allocated
* *
@ -232,8 +253,7 @@ struct usbdev {
*/ */
struct usbdev_ep { struct usbdev_ep {
usbdev_t *dev; /**< USB device this endpoint belongs to */ usbdev_t *dev; /**< USB device this endpoint belongs to */
uint8_t *buf; /**< Ptr to the data buffer */ size_t len; /**< Endpoint configured max transfer size in bytes */
size_t len; /**< Size of the data buffer in bytes */
usb_ep_dir_t dir; /**< Endpoint direction */ usb_ep_dir_t dir; /**< Endpoint direction */
usb_ep_type_t type; /**< Endpoint type */ usb_ep_type_t type; /**< Endpoint type */
uint8_t num; /**< Endpoint number */ uint8_t num; /**< Endpoint number */
@ -265,12 +285,12 @@ typedef struct usbdev_driver {
* @param[in] dev USB device descriptor * @param[in] dev USB device descriptor
* @param[in] type USB endpoint type * @param[in] type USB endpoint type
* @param[in] dir USB endpoint direction * @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 ptr to the new USB endpoint descriptor
* @return NULL on error * @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 * @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); 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. * 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] 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; } usbdev_driver_t;
/** /**
@ -410,16 +438,16 @@ static inline void usbdev_init(usbdev_t *dev)
* @param[in] dev USB device descriptor * @param[in] dev USB device descriptor
* @param[in] type USB endpoint type * @param[in] type USB endpoint type
* @param[in] dir USB endpoint direction * @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 ptr to the new USB endpoint descriptor
* @return NULL on error * @return NULL on error
*/ */
static inline usbdev_ep_t * usbdev_new_ep(usbdev_t *dev, usb_ep_type_t type, 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); 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 != NULL)`
* @pre `(ep->dev != NULL)` * @pre `(ep->dev != NULL)`
* *
* @param[in] ep USB endpoint descriptor * @param[in] ep USB endpoint descriptor
* @param[in] len length of the data to be transmitted * @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);
assert(ep->dev); assert(ep->dev);
return ep->dev->driver->ready(ep, len); return ep->dev->driver->xmit(ep, buf, len);
} }
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -43,7 +43,8 @@ typedef struct {
usbdev_ep_t ep; /**< Generic endpoint struct */ usbdev_ep_t ep; /**< Generic endpoint struct */
usbdev_mock_ep_state_t state; /**< Endpoint state */ usbdev_mock_ep_state_t state; /**< Endpoint state */
size_t available; /**< Bytes available in the buffer */ size_t available; /**< Bytes available in the buffer */
uint8_t *buf_start; /**< Start location of 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; } usbdev_mock_ep_t;
/** /**

View File

@ -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 = &testdev->out[0];
res->ep.num = 0; res->ep.num = 0;
res->ep.buf = _out_buf; res->buf = _out_buf;
} }
else { else {
res = &testdev->in[0]; res = &testdev->in[0];
res->ep.num = 0; res->ep.num = 0;
res->ep.buf = _in_buf; res->buf = _in_buf;
} }
} }
if (res) { if (res) {
res->buf_start = res->ep.buf;
res->state = EP_STATE_READY; res->state = EP_STATE_READY;
res->available = 0; res->available = 0;
res->ep.len = buf_len; 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"); ep->num, ep->dir == USB_EP_DIR_OUT ? "out" : "in");
usbdev_mock_ep_t *mock_ep = (usbdev_mock_ep_t *)ep; 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) { if (mock_ep->state == EP_STATE_DATA_AVAILABLE) {
dev->ep_esr_cb(dev, mock_ep); dev->ep_esr_cb(dev, mock_ep);
mock_ep->state = EP_STATE_READY; 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", DEBUG("[mock]: Readying EP %u, dir %s, len %u\n",
ep->num, ep->dir == USB_EP_DIR_OUT ? "out" : "in", (unsigned)len); ep->num, ep->dir == USB_EP_DIR_OUT ? "out" : "in", (unsigned)len);
if (ep->num == 0) { if (ep->num == 0) {
usbdev_mock_t *usbdev_mock = _ep2dev(ep); usbdev_mock_t *usbdev_mock = _ep2dev(ep);
usbdev_mock_ep_t *mock_ep = (usbdev_mock_ep_t *)ep; usbdev_mock_ep_t *mock_ep = (usbdev_mock_ep_t *)ep;
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->available = len;
mock_ep->ep.buf += len; }
mock_ep->state = EP_STATE_DATA_AVAILABLE; mock_ep->state = EP_STATE_DATA_AVAILABLE;
usbdev_mock->ready_cb(usbdev_mock, (usbdev_mock_ep_t *)ep, len); usbdev_mock->ready_cb(usbdev_mock, (usbdev_mock_ep_t *)ep, len);
} }
return 0; return 0;
} }
@ -224,5 +227,5 @@ static const usbdev_driver_t testdriver = {
.ep_get = _ep_get, .ep_get = _ep_get,
.ep_set = _ep_set, .ep_set = _ep_set,
.ep_esr = _ep_esr, .ep_esr = _ep_esr,
.ready = _ready, .xmit = _xmit,
}; };

View File

@ -91,11 +91,6 @@ typedef enum {
*/ */
USBOPT_EP_STALL, 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. * @brief (size_t) Retrieve number of bytes available on endpoint.
*/ */

View File

@ -142,6 +142,16 @@ struct usbus_cdcacm_device {
usbus_cdcacm_line_state_t state; /**< Current line state */ usbus_cdcacm_line_state_t state; /**< Current line state */
event_t flush; /**< device2host forced flush event */ event_t flush; /**< device2host forced flush event */
usb_req_cdcacm_coding_t coding; /**< Current coding configuration */ 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];
}; };
/** /**

View File

@ -108,10 +108,24 @@ typedef struct usbus_cdcecm_device {
usbus_t *usbus; /**< Ptr to the USBUS context */ usbus_t *usbus; /**< Ptr to the USBUS context */
mutex_t out_lock; /**< mutex used for locking netif/USBUS send */ mutex_t out_lock; /**< mutex used for locking netif/USBUS send */
size_t tx_len; /**< Length of the current tx frame */ size_t tx_len; /**< Length of the current tx frame */
uint8_t in_buf[ETHERNET_FRAME_LEN]; /**< Buffer for the received frames */
size_t len; /**< Length of the current rx frame */ size_t len; /**< Length of the current rx frame */
usbus_cdcecm_notif_t notif; /**< Startup message notification tracker */ usbus_cdcecm_notif_t notif; /**< Startup message notification tracker */
unsigned active_iface; /**< Current active data interface */ 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; } usbus_cdcecm_device_t;
/** /**

View File

@ -69,14 +69,24 @@ typedef struct {
size_t received_len; size_t received_len;
/** /**
* @brief EP0 OUT endpoint * @brief EP0 OUT endpoint reference
*/ */
usbdev_ep_t *out; usbdev_ep_t *out;
/** /**
* @brief EP0 IN endpoint * @brief EP0 IN endpoint reference
*/ */
usbdev_ep_t *in; 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; } usbus_control_handler_t;
/** /**

View File

@ -77,6 +77,16 @@ struct usbus_hid_device {
usbus_hid_cb_t cb; /**< Callback for data handlers */ usbus_hid_cb_t cb; /**< Callback for data handlers */
event_t tx_ready; /**< Transmit ready event */ event_t tx_ready; /**< Transmit ready event */
mutex_t in_lock; /**< mutex used for locking hid send */ 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];
}; };
/** /**

View File

@ -305,7 +305,8 @@ static int _control_handler(usbus_t *usbus, usbus_handler_t *handler,
usbus_endpoint_t *data_out = usbus_interface_find_endpoint( usbus_endpoint_t *data_out = usbus_interface_find_endpoint(
&cdcacm->iface_data, USB_EP_TYPE_BULK, USB_EP_DIR_OUT); &cdcacm->iface_data, USB_EP_TYPE_BULK, USB_EP_DIR_OUT);
assert(data_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); usbus_cdc_acm_flush(cdcacm);
} }
else { else {
@ -331,13 +332,13 @@ static void _handle_in(usbus_cdcacm_device_t *cdcacm,
unsigned old = irq_disable(); unsigned old = irq_disable();
while (!tsrb_empty(&cdcacm->tsrb)) { while (!tsrb_empty(&cdcacm->tsrb)) {
int c = tsrb_get_one(&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) { if (cdcacm->occupied >= CONFIG_USBUS_CDC_ACM_BULK_EP_SIZE) {
break; break;
} }
} }
irq_restore(old); 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, 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 */ /* Retrieve incoming data */
usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t)); usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t));
if (len > 0) { 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)) { if ((ep->dir == USB_EP_DIR_IN) && (ep->type == USB_EP_TYPE_BULK)) {
cdcacm->occupied = 0; cdcacm->occupied = 0;

View File

@ -115,7 +115,7 @@ static void _notify_link_speed(usbus_cdcecm_device_t *cdcecm)
{ {
DEBUG("CDC ECM: sending link speed indication\n"); DEBUG("CDC ECM: sending link speed indication\n");
usb_desc_cdcecm_speed_t *notification = 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 | notification->setup.type = USB_SETUP_REQUEST_DEVICE2HOST |
USB_SETUP_REQUEST_TYPE_CLASS | USB_SETUP_REQUEST_TYPE_CLASS |
USB_SETUP_REQUEST_RECIPIENT_INTERFACE; 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->down = CONFIG_USBUS_CDC_ECM_CONFIG_SPEED_DOWNSTREAM;
notification->up = CONFIG_USBUS_CDC_ECM_CONFIG_SPEED_UPSTREAM; 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)); sizeof(usb_desc_cdcecm_speed_t));
cdcecm->notif = USBUS_CDCECM_NOTIF_SPEED; 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) static void _notify_link_up(usbus_cdcecm_device_t *cdcecm)
{ {
DEBUG("CDC ECM: sending link up indication\n"); 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 | notification->type = USB_SETUP_REQUEST_DEVICE2HOST |
USB_SETUP_REQUEST_TYPE_CLASS | USB_SETUP_REQUEST_TYPE_CLASS |
USB_SETUP_REQUEST_RECIPIENT_INTERFACE; USB_SETUP_REQUEST_RECIPIENT_INTERFACE;
@ -142,7 +142,7 @@ static void _notify_link_up(usbus_cdcecm_device_t *cdcecm)
notification->value = 1; notification->value = 1;
notification->index = cdcecm->iface_ctrl.idx; notification->index = cdcecm->iface_ctrl.idx;
notification->length = 0; 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; cdcecm->notif = USBUS_CDCECM_NOTIF_LINK_UP;
} }
@ -251,7 +251,8 @@ static int _control_handler(usbus_t *usbus, usbus_handler_t *handler,
setup->value); setup->value);
cdcecm->active_iface = (uint8_t)setup->value; cdcecm->active_iface = (uint8_t)setup->value;
if (cdcecm->active_iface == 1) { 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); _notify_link_up(cdcecm);
} }
break; break;
@ -290,36 +291,15 @@ static void _handle_tx_xmit(event_t *ev)
mutex_unlock(&cdcecm->out_lock); mutex_unlock(&cdcecm->out_lock);
} }
/* Data prepared by netdev_send, signal ready to usbus */ /* Data prepared by netdev_send, signal ready to usbus */
usbdev_ep_ready(cdcecm->ep_in->ep, cdcecm->tx_len); usbdev_ep_xmit(cdcecm->ep_in->ep, cdcecm->data_in, cdcecm->tx_len);
}
static void _handle_rx_flush(usbus_cdcecm_device_t *cdcecm)
{
cdcecm->len = 0;
} }
static void _handle_rx_flush_ev(event_t *ev) static void _handle_rx_flush_ev(event_t *ev)
{ {
usbus_cdcecm_device_t *cdcecm = container_of(ev, usbus_cdcecm_device_t, usbus_cdcecm_device_t *cdcecm = container_of(ev, usbus_cdcecm_device_t,
rx_flush); rx_flush);
cdcecm->len = 0; /* Flush packet */
usbdev_ep_ready(cdcecm->ep_out->ep, 0); usbdev_ep_xmit(cdcecm->ep_out->ep, cdcecm->data_out, USBUS_CDCECM_EP_DATA_SIZE);
_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);
}
} }
static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler, 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; size_t len = 0;
usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t)); 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) { 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) { 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; usbus_cdcecm_device_t *cdcecm = (usbus_cdcecm_device_t *)handler;
DEBUG("CDC ECM: Reset\n"); DEBUG("CDC ECM: Reset\n");
_handle_rx_flush(cdcecm);
_handle_in_complete(usbus, handler); _handle_in_complete(usbus, handler);
cdcecm->notif = USBUS_CDCECM_NOTIF_NONE; cdcecm->notif = USBUS_CDCECM_NOTIF_NONE;
cdcecm->len = 0; /* Flush received data */
cdcecm->active_iface = 0; cdcecm->active_iface = 0;
mutex_unlock(&cdcecm->out_lock); mutex_unlock(&cdcecm->out_lock);
} }

View File

@ -59,7 +59,7 @@ static int _send(netdev_t *netdev, const iolist_t *iolist)
{ {
assert(iolist); assert(iolist);
usbus_cdcecm_device_t *cdcecm = _netdev_to_cdcecm(netdev); 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; const iolist_t *iolist_start = iolist;
size_t len = iolist_size(iolist); size_t len = iolist_size(iolist);
/* interface with alternative function ID 1 is the interface containing the /* 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; return pktlen;
} }
if (pktlen <= max_len) { 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); _signal_rx_flush(cdcecm);
return (pktlen <= max_len) ? (int)pktlen : -ENOBUFS; return (pktlen <= max_len) ? (int)pktlen : -ENOBUFS;

View File

@ -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); 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, 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); usbus_enable_endpoint(hid->ep_out);
/* signal that INTERRUPT OUT is ready to receive data */ /* 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); usbus_add_interface(usbus, &hid->iface);
} }
@ -222,8 +223,8 @@ static void _transfer_handler(usbus_t *usbus, usbus_handler_t *handler,
size_t len; size_t len;
usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t)); usbdev_ep_get(ep, USBOPT_EP_AVAILABLE, &len, sizeof(size_t));
if (len > 0) { 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);
} }
} }

View File

@ -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) void usb_hid_io_write(const void *buffer, size_t len)
{ {
assert(buffer); 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; uint16_t max_size = hid.ep_in->maxpacketsize;
size_t offset = 0; size_t offset = 0;

View File

@ -166,7 +166,7 @@ usbus_endpoint_t *usbus_add_endpoint(usbus_t *usbus, usbus_interface_t *iface,
if (usbdev_ep) { if (usbdev_ep) {
ep = dir == USB_EP_DIR_IN ? &usbus->ep_in[usbdev_ep->num] ep = dir == USB_EP_DIR_IN ? &usbus->ep_in[usbdev_ep->num]
: &usbus->ep_out[usbdev_ep->num]; : &usbus->ep_out[usbdev_ep->num];
ep->maxpacketsize = usbdev_ep->len; ep->maxpacketsize = len;
ep->ep = usbdev_ep; ep->ep = usbdev_ep;
if (iface) { if (iface) {
ep->next = iface->ep; ep->next = iface->ep;
@ -325,6 +325,7 @@ static void _event_cb(usbdev_t *usbdev, usbdev_event_t event)
sizeof(uint8_t)); sizeof(uint8_t));
flag = USBUS_HANDLER_FLAG_RESET; flag = USBUS_HANDLER_FLAG_RESET;
msg = USBUS_EVENT_USB_RESET; msg = USBUS_EVENT_USB_RESET;
DEBUG("usbus: USB reset detected\n");
break; break;
case USBDEV_EVENT_SUSPEND: case USBDEV_EVENT_SUSPEND:
DEBUG("usbus: USB suspend detected\n"); DEBUG("usbus: USB suspend detected\n");

View File

@ -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 */ /* Signal ready for new data in case there is more */
if (handler->received_len < pkt->length) { if (handler->received_len < pkt->length) {
handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_OUTDATA; 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 { else {
handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_INACK; 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)); sizeof(usbopt_enable_t));
usbdev_ep_set(ep0_handler->out, USBOPT_EP_ENABLE, &enable, usbdev_ep_set(ep0_handler->out, USBOPT_EP_ENABLE, &enable,
sizeof(usbopt_enable_t)); 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) 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(len);
assert(handler->control_request_state == USBUS_CONTROL_REQUEST_STATE_OUTDATA); assert(handler->control_request_state == USBUS_CONTROL_REQUEST_STATE_OUTDATA);
usbdev_ep_t *ep_out = handler->out; usbdev_ep_get(handler->out, USBOPT_EP_AVAILABLE,
usbdev_ep_get(ep_out, USBOPT_EP_AVAILABLE,
len, sizeof(size_t)); len, sizeof(size_t));
return ep_out->buf; return handler->out_buf;
} }
static void _init(usbus_t *usbus, usbus_handler_t *handler) 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; ep0_handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY;
/* Ready for new control request */ /* 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; break;
case USBUS_CONTROL_REQUEST_STATE_OUTACK: case USBUS_CONTROL_REQUEST_STATE_OUTACK:
if (ep->dir == USB_EP_DIR_OUT) { if (ep->dir == USB_EP_DIR_OUT) {
ep0_handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY; ep0_handler->control_request_state = USBUS_CONTROL_REQUEST_STATE_READY;
/* Ready for new control request */ /* 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; break;
case USBUS_CONTROL_REQUEST_STATE_INDATA: case USBUS_CONTROL_REQUEST_STATE_INDATA:
@ -375,7 +374,7 @@ static int _handle_tr_complete(usbus_t *usbus,
} }
else { else {
/* Ready out ZLP */ /* 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; 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: case USBUS_CONTROL_REQUEST_STATE_READY:
if (ep->dir == USB_EP_DIR_OUT) { if (ep->dir == USB_EP_DIR_OUT) {
memset(&ep0_handler->slicer, 0, sizeof(usbus_control_slicer_t)); 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)); sizeof(usb_setup_t));
ep0_handler->received_len = 0; ep0_handler->received_len = 0;
ep0_handler->slicer.reqlen = ep0_handler->setup.length; ep0_handler->slicer.reqlen = ep0_handler->setup.length;

View File

@ -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; size_t start_offset = bldr->cur - bldr->start + byte_offset;
bldr->cur += len; bldr->cur += len;
bldr->len += byte_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; 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 */ /* Only copy the char if it is within the window */
if ((bldr->start <= bldr->cur) && (bldr->cur < end)) { 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; *pos = c;
bldr->cur++; bldr->cur++;
bldr->len++; 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; len = len < bldr->reqlen - bldr->start ? len : bldr->reqlen - bldr->start;
bldr->transferred += len; bldr->transferred += len;
usbdev_ep_ready(ep0->in, len); usbdev_ep_xmit(ep0->in, ep0->in_buf, len);
} }

View File

@ -146,7 +146,7 @@ static void _test_sequence(usbdev_mock_t *dev)
case TESTPHASE_RESET: case TESTPHASE_RESET:
next_phase = TESTPHASE_REQ_DEV_INIT; next_phase = TESTPHASE_REQ_DEV_INIT;
DEBUG("[test]: Requesting device descriptor\n"); 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->req_len = 8;
dev->out[0].state = EP_STATE_DATA_AVAILABLE; dev->out[0].state = EP_STATE_DATA_AVAILABLE;
dev->out[0].available = 8; dev->out[0].available = 8;
@ -157,7 +157,7 @@ static void _test_sequence(usbdev_mock_t *dev)
DEBUG("[test]: validating device descriptor\n"); DEBUG("[test]: validating device descriptor\n");
TEST_ASSERT_EQUAL_INT(dev->in[0].available, 8); TEST_ASSERT_EQUAL_INT(dev->in[0].available, 8);
_validate_device_desc_init( _validate_device_desc_init(
(usb_descriptor_device_t *)dev->in[0].buf_start); (usb_descriptor_device_t *)dev->in[0].buf);
/* Reset device */ /* Reset device */
DEBUG("[test]: Signalling second USB reset condition\n"); DEBUG("[test]: Signalling second USB reset condition\n");
dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_RESET); dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_RESET);
@ -166,7 +166,7 @@ static void _test_sequence(usbdev_mock_t *dev)
case TESTPHASE_RESET2: case TESTPHASE_RESET2:
next_phase = TESTPHASE_SET_ADDRESS; next_phase = TESTPHASE_SET_ADDRESS;
DEBUG("[test]: Set USB address\n"); 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->req_len = 0;
dev->out[0].state = EP_STATE_DATA_AVAILABLE; dev->out[0].state = EP_STATE_DATA_AVAILABLE;
dev->out[0].available = 8; dev->out[0].available = 8;
@ -175,7 +175,7 @@ static void _test_sequence(usbdev_mock_t *dev)
case TESTPHASE_SET_ADDRESS: case TESTPHASE_SET_ADDRESS:
next_phase = TESTPHASE_REQ_DEV_FULL; next_phase = TESTPHASE_REQ_DEV_FULL;
DEBUG("[test]: Requesting full device descriptor\n"); 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)); sizeof(usb_descriptor_device_t));
dev->req_len = sizeof(usb_descriptor_device_t); dev->req_len = sizeof(usb_descriptor_device_t);
dev->out[0].state = EP_STATE_DATA_AVAILABLE; 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)); sizeof(usb_descriptor_device_t));
DEBUG("[test]: Validating full descriptor\n"); DEBUG("[test]: Validating full descriptor\n");
_validate_device_desc_init( _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; next_phase = TESTPHASE_FINAL;
dev->usbdev.cb(&dev->usbdev, USBDEV_EVENT_ESR); 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) { if (ep->available == dev->req_len) {
DEBUG("[data]: Full data received from stack\n"); DEBUG("[data]: Full data received from stack\n");
req_phase = TEST_REQ_PHASE_OUTACK; req_phase = TEST_REQ_PHASE_OUTACK;
/* Reset buffer ptr to the start */
ep->ep.buf = ep->buf_start;
} }
else { else {
DEBUG("[data]: Expecting more data from stack: %u/%u\n", DEBUG("[data]: Expecting more data from stack: %u/%u\n",