Merge pull request #17064 from bergzand/pr/usbdev/xmit
USB: refactor to xmit-based API
This commit is contained in:
commit
aa8608eff5
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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,9 +327,9 @@ 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 */
|
||||||
usbdev_ep_t *res = NULL;
|
usbdev_ep_t *res = NULL;
|
||||||
|
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
@ -429,10 +392,8 @@ static void _ep_disable_irq(usbdev_ep_t *ep)
|
|||||||
|
|
||||||
static void _ep_init(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) {
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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");
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user