mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-05-12 11:43:16 -04:00
usb: allow more flexible endpoint allocation
the capabilities of endpoint of several devices such as dwc2 change during runtime, so they cannot be determined during driver initialization. therefore, allocation using ep_specs is inappropriate. to support these devices, add functions to the driver that determine whether endpoints are available and make allocation more flexible. tested with ipodvideo(arc) and erosqnative(designware) Change-Id: I8005c17f3d763cd17306bf49918e1cd8084bdeff
This commit is contained in:
parent
42841d493f
commit
41caf678fe
14 changed files with 348 additions and 283 deletions
|
|
@ -626,18 +626,17 @@ void usb_drv_cancel_all_transfers(void)
|
||||||
endpoints[i].halt[0] = endpoints[i].halt[1] = 1;
|
endpoints[i].halt[0] = endpoints[i].halt[1] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size)
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
{
|
{
|
||||||
(void)max_packet_size; /* FIXME: support max packet size override */
|
/* FIXME: support max packet size override */
|
||||||
(void)type;
|
(void)ctx;
|
||||||
(void)endpoint;
|
(void)ep;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint)
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
{
|
{
|
||||||
(void)endpoint;
|
(void)ctx;
|
||||||
return 0;
|
(void)ep;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bus_reset(void)
|
static void bus_reset(void)
|
||||||
|
|
|
||||||
|
|
@ -640,8 +640,11 @@ void usb_drv_set_test_mode(int mode) {
|
||||||
M66591_TESTMODE |= mode;
|
M66591_TESTMODE |= mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep) {
|
||||||
(void)max_packet_size; /* FIXME: support max packet size override */
|
/* FIXME: support max packet size override */
|
||||||
|
const int epnum = EP_NUM(ep);
|
||||||
|
const int epdir = EP_DIR(ep);
|
||||||
|
const int type = ctx->type[epnum][epdir];
|
||||||
|
|
||||||
int pipecfg = 0;
|
int pipecfg = 0;
|
||||||
|
|
||||||
|
|
@ -651,41 +654,38 @@ int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
||||||
} else if(type == USB_ENDPOINT_XFER_BULK) {
|
} else if(type == USB_ENDPOINT_XFER_BULK) {
|
||||||
pipecfg |= 1<<13;
|
pipecfg |= 1<<13;
|
||||||
} else {
|
} else {
|
||||||
/* Not a supported type */
|
panicf("mxx: unsupported type %d", type);
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int num = endpoint & USB_ENDPOINT_NUMBER_MASK;
|
if (epdir == DIR_IN) {
|
||||||
int dir = endpoint & USB_ENDPOINT_DIR_MASK;
|
|
||||||
if (dir == USB_DIR_IN) {
|
|
||||||
pipecfg |= (1<<4);
|
pipecfg |= (1<<4);
|
||||||
}
|
}
|
||||||
|
|
||||||
M66591_eps[num].dir = dir;
|
M66591_eps[epnum].dir = epdir == DIR_IN ? USB_DIR_IN : USB_DIR_OUT;
|
||||||
|
|
||||||
M66591_PIPE_CFGSEL=num;
|
M66591_PIPE_CFGSEL = epnum;
|
||||||
|
|
||||||
/* Enable pipe (15) */
|
/* Enable pipe (15) */
|
||||||
pipecfg |= 1<<15;
|
pipecfg |= 1<<15;
|
||||||
|
|
||||||
pipe_handshake(num, PIPE_SHAKE_NAK);
|
pipe_handshake(epnum, PIPE_SHAKE_NAK);
|
||||||
|
|
||||||
/* Setup the flags */
|
/* Setup the flags */
|
||||||
M66591_PIPE_CFGWND=pipecfg;
|
M66591_PIPE_CFGWND=pipecfg;
|
||||||
|
|
||||||
pipe_init(num);
|
pipe_init(epnum);
|
||||||
|
|
||||||
logf("mxx: ep req ep#: %d config: 0x%04x", num, M66591_PIPE_CFGWND);
|
logf("mxx: ep req ep#: %d config: 0x%04x", epnum, M66591_PIPE_CFGWND);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Used by stack to tell the helper functions that the pipe is not in use */
|
/* Used by stack to tell the helper functions that the pipe is not in use */
|
||||||
int usb_drv_deinit_endpoint(int endpoint) {
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep) {
|
||||||
int num = endpoint & USB_ENDPOINT_NUMBER_MASK;
|
(void)ctx;
|
||||||
|
|
||||||
|
int num = ep & USB_ENDPOINT_NUMBER_MASK;
|
||||||
|
|
||||||
if (num < 1 || num > USB_NUM_ENDPOINTS) {
|
if (num < 1 || num > USB_NUM_ENDPOINTS) {
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int flags = disable_irq_save();
|
int flags = disable_irq_save();
|
||||||
|
|
@ -695,8 +695,6 @@ int usb_drv_deinit_endpoint(int endpoint) {
|
||||||
M66591_eps[num].dir = -1;
|
M66591_eps[num].dir = -1;
|
||||||
|
|
||||||
restore_irq(flags);
|
restore_irq(flags);
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Periodically called to check if a cable was plugged into the device */
|
/* Periodically called to check if a cable was plugged into the device */
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "usb-designware.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
@ -35,8 +37,6 @@
|
||||||
#include "usb_ch9.h"
|
#include "usb_ch9.h"
|
||||||
#include "usb_core.h"
|
#include "usb_core.h"
|
||||||
|
|
||||||
#include "usb-designware.h"
|
|
||||||
|
|
||||||
/* Define LOGF_ENABLE to enable logf output in this file */
|
/* Define LOGF_ENABLE to enable logf output in this file */
|
||||||
/*#define LOGF_ENABLE*/
|
/*#define LOGF_ENABLE*/
|
||||||
#include "logf.h"
|
#include "logf.h"
|
||||||
|
|
@ -155,9 +155,6 @@ struct usb_dw_ep0
|
||||||
struct usb_ctrlrequest pending_req;
|
struct usb_ctrlrequest pending_req;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS]; /* filled in usb_drv_init */
|
|
||||||
uint8_t usb_drv_ep_specs_flags = 0;
|
|
||||||
|
|
||||||
static const char* const dw_dir_str[USB_DW_NUM_DIRS] =
|
static const char* const dw_dir_str[USB_DW_NUM_DIRS] =
|
||||||
{
|
{
|
||||||
[USB_DW_EPDIR_IN] = "IN",
|
[USB_DW_EPDIR_IN] = "IN",
|
||||||
|
|
@ -195,7 +192,6 @@ static uint32_t usb_endpoints; /* available EPs mask */
|
||||||
(usually 1), otherwise it is the number of dedicated Tx FIFOs
|
(usually 1), otherwise it is the number of dedicated Tx FIFOs
|
||||||
(not counting NPTX FIFO that is always dedicated for IN0). */
|
(not counting NPTX FIFO that is always dedicated for IN0). */
|
||||||
static int n_ptxfifos;
|
static int n_ptxfifos;
|
||||||
static uint16_t ptxfifo_usage;
|
|
||||||
|
|
||||||
static uint32_t hw_maxbytes;
|
static uint32_t hw_maxbytes;
|
||||||
static uint32_t hw_maxpackets;
|
static uint32_t hw_maxpackets;
|
||||||
|
|
@ -672,47 +668,28 @@ static void usb_dw_unconfigure_ep(int epnum, enum usb_dw_epdir epdir)
|
||||||
#endif
|
#endif
|
||||||
ep_periodic_msk &= ~(1 << epnum);
|
ep_periodic_msk &= ~(1 << epnum);
|
||||||
#endif
|
#endif
|
||||||
ptxfifo_usage &= ~(1 << GET_DTXFNUM(epnum));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_dw_flush_endpoint(epnum, epdir);
|
usb_dw_flush_endpoint(epnum, epdir);
|
||||||
DWC_EPCTL(epnum, epdir) = epctl;
|
DWC_EPCTL(epnum, epdir) = epctl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usb_dw_configure_ep(int epnum,
|
static void usb_dw_configure_ep(const struct usb_drv_ep_alloc_ctx* ctx, int epnum, enum usb_dw_epdir epdir, int type, int maxpktsize)
|
||||||
enum usb_dw_epdir epdir, int type, int maxpktsize)
|
|
||||||
{
|
{
|
||||||
uint32_t epctl = SETD0PIDEF|EPTYP(type)|USBAEP|maxpktsize;
|
uint32_t epctl = SETD0PIDEF|EPTYP(type)|USBAEP|maxpktsize;
|
||||||
|
|
||||||
if (epdir == USB_DW_EPDIR_IN)
|
if (epdir == USB_DW_EPDIR_IN && ctx->assigned_txfifos[epnum] > 0)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* If the hardware has dedicated fifos, we must give each
|
|
||||||
* IN EP a unique tx-fifo even if it is non-periodic.
|
|
||||||
*/
|
|
||||||
#ifdef USB_DW_SHARED_FIFO
|
#ifdef USB_DW_SHARED_FIFO
|
||||||
|
ep_periodic_msk |= (1 << epnum);
|
||||||
#ifndef USB_DW_ARCH_SLAVE
|
#ifndef USB_DW_ARCH_SLAVE
|
||||||
epctl |= DWC_DIEPCTL(epnum) & NEXTEP(0xf);
|
epctl |= DWC_DIEPCTL(epnum) & NEXTEP(0xf);
|
||||||
#endif
|
#endif
|
||||||
if (type == USB_ENDPOINT_XFER_INT)
|
|
||||||
#endif
|
#endif
|
||||||
{
|
epctl |= DTXFNUM(ctx->assigned_txfifos[epnum]);
|
||||||
int fnum;
|
|
||||||
for (fnum = 1; fnum <= n_ptxfifos; fnum++)
|
|
||||||
if (~ptxfifo_usage & (1 << fnum))
|
|
||||||
break;
|
|
||||||
if (fnum > n_ptxfifos)
|
|
||||||
return -1; /* no available fifos */
|
|
||||||
ptxfifo_usage |= (1 << fnum);
|
|
||||||
epctl |= DTXFNUM(fnum);
|
|
||||||
#ifdef USB_DW_SHARED_FIFO
|
|
||||||
ep_periodic_msk |= (1 << epnum);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DWC_EPCTL(epnum, epdir) = epctl;
|
DWC_EPCTL(epnum, epdir) = epctl;
|
||||||
return 0; /* ok */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_dw_reset_endpoints(void)
|
static void usb_dw_reset_endpoints(void)
|
||||||
|
|
@ -753,7 +730,6 @@ static void usb_dw_reset_endpoints(void)
|
||||||
usb_dw_unconfigure_ep(ep, USB_DW_EPDIR_IN);
|
usb_dw_unconfigure_ep(ep, USB_DW_EPDIR_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
ptxfifo_usage = 0;
|
|
||||||
#ifdef USB_DW_SHARED_FIFO
|
#ifdef USB_DW_SHARED_FIFO
|
||||||
ep_periodic_msk = 0;
|
ep_periodic_msk = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1509,17 +1485,6 @@ static void usb_dw_init(void)
|
||||||
/* Soft reconnect */
|
/* Soft reconnect */
|
||||||
udelay(3000);
|
udelay(3000);
|
||||||
DWC_DCTL &= ~SDIS;
|
DWC_DCTL &= ~SDIS;
|
||||||
|
|
||||||
/* Fill endpoint spec table FIXME: should be done in usb_drv_startup() */
|
|
||||||
usb_drv_ep_specs[0].type[DIR_OUT] = USB_ENDPOINT_XFER_CONTROL;
|
|
||||||
usb_drv_ep_specs[0].type[DIR_IN] = USB_ENDPOINT_XFER_CONTROL;
|
|
||||||
for(int i = 1; i < USB_NUM_ENDPOINTS; i += 1) {
|
|
||||||
bool out_avail = usb_endpoints & (1 << (i + USB_DW_DIR_OFF(USB_DW_EPDIR_OUT)));
|
|
||||||
usb_drv_ep_specs[i].type[DIR_OUT] = out_avail ? USB_ENDPOINT_TYPE_ANY : USB_ENDPOINT_TYPE_NONE;
|
|
||||||
|
|
||||||
bool in_avail = usb_endpoints & (1 << (i + USB_DW_DIR_OFF(USB_DW_EPDIR_IN)));
|
|
||||||
usb_drv_ep_specs[i].type[DIR_IN] = in_avail ? USB_ENDPOINT_TYPE_ANY : USB_ENDPOINT_TYPE_NONE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void usb_dw_exit(void)
|
static void usb_dw_exit(void)
|
||||||
|
|
@ -1617,12 +1582,65 @@ void INT_USB_FUNC(void)
|
||||||
usb_dw_irq();
|
usb_dw_irq();
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size)
|
void usb_drv_ep_reset_alloc_ctx(struct usb_drv_ep_alloc_ctx* ctx)
|
||||||
|
{
|
||||||
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool usb_drv_ep_allocate(struct usb_drv_ep_alloc_ctx* ctx, int ep, int type, int max_packet_size)
|
||||||
{
|
{
|
||||||
(void)max_packet_size; /* FIXME: support max packet size override */
|
(void)max_packet_size; /* FIXME: support max packet size override */
|
||||||
|
|
||||||
enum usb_dw_epdir epdir = (EP_DIR(endpoint) == DIR_IN) ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
|
const uint8_t epnum = EP_NUM(ep);
|
||||||
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(endpoint), epdir);
|
const uint8_t epdir = EP_DIR(ep);
|
||||||
|
|
||||||
|
if(ep == EP_CONTROL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum usb_dw_epdir dwdir = epdir == DIR_IN ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
|
||||||
|
if(!(usb_endpoints & (1 << (epnum + USB_DW_DIR_OFF(dwdir)))))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool need_fifo = epdir == DIR_IN;
|
||||||
|
#ifdef USB_DW_SHARED_FIFO
|
||||||
|
/* in shared fifo mode, only periodic endpoints need dedicated fifo */
|
||||||
|
need_fifo &= type == USB_ENDPOINT_XFER_ISOC || type == USB_ENDPOINT_XFER_INT;
|
||||||
|
#endif
|
||||||
|
if(!need_fifo)
|
||||||
|
{
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int fnum = 1; fnum <= n_ptxfifos; fnum++)
|
||||||
|
{
|
||||||
|
if (~ctx->txfifo_usage & (1 << fnum))
|
||||||
|
{
|
||||||
|
ctx->txfifo_usage |= 1 << fnum;
|
||||||
|
ctx->assigned_txfifos[epnum] = fnum;
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ok:
|
||||||
|
ctx->type[epnum][epdir] = type;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
|
{
|
||||||
|
/* FIXME: support max packet size override */
|
||||||
|
const int epnum = EP_NUM(ep);
|
||||||
|
const int epdir_ = EP_DIR(ep);
|
||||||
|
const int type = ctx->type[epnum][epdir_];
|
||||||
|
|
||||||
|
enum usb_dw_epdir epdir = (epdir_ == DIR_IN) ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
|
||||||
|
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(ep), epdir);
|
||||||
|
|
||||||
int maxpktsize;
|
int maxpktsize;
|
||||||
if(type == EPTYP_ISOCHRONOUS)
|
if(type == EPTYP_ISOCHRONOUS)
|
||||||
|
|
@ -1635,32 +1653,23 @@ int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_dw_target_disable_irq();
|
usb_dw_target_disable_irq();
|
||||||
int res = usb_dw_configure_ep(EP_NUM(endpoint), epdir, type, maxpktsize);
|
usb_dw_configure_ep(ctx, epnum, epdir, type, maxpktsize);
|
||||||
usb_dw_target_enable_irq();
|
usb_dw_target_enable_irq();
|
||||||
|
|
||||||
if(res >= 0)
|
dw_ep->active = true;
|
||||||
{
|
|
||||||
dw_ep->active = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint)
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
{
|
{
|
||||||
enum usb_dw_epdir epdir = (EP_DIR(endpoint) == DIR_IN) ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
|
(void)ctx;
|
||||||
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(endpoint), epdir);
|
enum usb_dw_epdir epdir = (EP_DIR(ep) == DIR_IN) ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
|
||||||
|
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(ep), epdir);
|
||||||
|
|
||||||
usb_dw_target_disable_irq();
|
usb_dw_target_disable_irq();
|
||||||
usb_dw_unconfigure_ep(EP_NUM(endpoint), epdir);
|
usb_dw_unconfigure_ep(EP_NUM(ep), epdir);
|
||||||
usb_dw_target_enable_irq();
|
usb_dw_target_enable_irq();
|
||||||
|
|
||||||
dw_ep->active = false;
|
dw_ep->active = false;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length)
|
int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
#ifndef REG32_PTR_T
|
#ifndef REG32_PTR_T
|
||||||
#define REG32_PTR_T volatile uint32_t *
|
#define REG32_PTR_T volatile uint32_t *
|
||||||
|
|
@ -288,4 +289,13 @@ extern void usb_dw_target_enable_irq(void);
|
||||||
extern void usb_dw_target_disable_irq(void);
|
extern void usb_dw_target_disable_irq(void);
|
||||||
extern void usb_dw_target_clear_irq(void);
|
extern void usb_dw_target_clear_irq(void);
|
||||||
|
|
||||||
|
/* endpoint allocation */
|
||||||
|
struct usb_drv_ep_alloc_ctx_dw
|
||||||
|
{
|
||||||
|
int8_t type[USB_NUM_ENDPOINTS][2];
|
||||||
|
uint16_t txfifo_usage;
|
||||||
|
uint8_t assigned_txfifos[USB_NUM_ENDPOINTS];
|
||||||
|
};
|
||||||
|
#define usb_drv_ep_alloc_ctx usb_drv_ep_alloc_ctx_dw
|
||||||
|
|
||||||
#endif /* __USB_DESIGNWARE_H__ */
|
#endif /* __USB_DESIGNWARE_H__ */
|
||||||
|
|
|
||||||
|
|
@ -62,19 +62,42 @@ enum usb_control_response {
|
||||||
USB_CONTROL_RECEIVE,
|
USB_CONTROL_RECEIVE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* endpoint allocation:
|
||||||
|
* there are two ways to implement endpoint allocation.
|
||||||
|
* 1. define usb_drv_ep_specs and usb_drv_ep_specs_flags in the driver.
|
||||||
|
* this is the simplest option when the types accepted by each endpoint are mutually independent.
|
||||||
|
* these variables are set only once during driver initialization and should not be modified afterward.
|
||||||
|
* 2. define usb_drv_ep_alloc_ctx and implement usb_drv_ep_reset_alloc_ctx and usb_drv_ep_allocate in the driver.
|
||||||
|
* if the available endpoint types change based on allocation status,
|
||||||
|
* these functions can be overridden to allow the driver to track the endpoint state.
|
||||||
|
* */
|
||||||
|
|
||||||
|
#ifndef usb_drv_ep_alloc_ctx
|
||||||
|
/* option 1 */
|
||||||
#define USB_ENDPOINT_TYPE_ANY (-1)
|
#define USB_ENDPOINT_TYPE_ANY (-1)
|
||||||
#define USB_ENDPOINT_TYPE_NONE (-2)
|
#define USB_ENDPOINT_TYPE_NONE (-2)
|
||||||
|
|
||||||
struct usb_drv_ep_spec {
|
struct usb_drv_ep_spec {
|
||||||
int8_t type[2]; /* USB_ENDPOINT_TYPE_{ANY,NONE} USB_ENDPOINT_XFER_* */
|
int8_t type[2]; /* USB_ENDPOINT_TYPE_{ANY,NONE} USB_ENDPOINT_XFER_* */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS];
|
extern struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS];
|
||||||
|
|
||||||
#define USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH (1 << 0)
|
#define USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH (1 << 0)
|
||||||
#define USB_ENDPOINT_SPEC_IO_EXCLUSIVE (1 << 1)
|
#define USB_ENDPOINT_SPEC_IO_EXCLUSIVE (1 << 1)
|
||||||
extern uint8_t usb_drv_ep_specs_flags;
|
extern uint8_t usb_drv_ep_specs_flags;
|
||||||
|
|
||||||
|
struct usb_drv_ep_alloc_ctx {
|
||||||
|
int8_t type[USB_NUM_ENDPOINTS][2];
|
||||||
|
int max_packet_size[USB_NUM_ENDPOINTS][2];
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
/* option 2 */
|
||||||
|
void usb_drv_ep_reset_alloc_ctx(struct usb_drv_ep_alloc_ctx* ctx);
|
||||||
|
bool usb_drv_ep_allocate(struct usb_drv_ep_alloc_ctx* ctx, int ep, int type, int max_packet_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep);
|
||||||
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep);
|
||||||
|
|
||||||
/* one-time initialisation of the USB driver */
|
/* one-time initialisation of the USB driver */
|
||||||
void usb_drv_startup(void);
|
void usb_drv_startup(void);
|
||||||
void usb_drv_int_enable(bool enable); /* Target implemented */
|
void usb_drv_int_enable(bool enable); /* Target implemented */
|
||||||
|
|
@ -98,8 +121,6 @@ int usb_drv_port_speed(void);
|
||||||
void usb_drv_cancel_all_transfers(void);
|
void usb_drv_cancel_all_transfers(void);
|
||||||
void usb_drv_set_test_mode(int mode);
|
void usb_drv_set_test_mode(int mode);
|
||||||
bool usb_drv_connected(void);
|
bool usb_drv_connected(void);
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size);
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint);
|
|
||||||
#ifdef USB_HAS_ISOCHRONOUS
|
#ifdef USB_HAS_ISOCHRONOUS
|
||||||
/* returns the last received frame number (the 11-bit number contained in the last SOF):
|
/* returns the last received frame number (the 11-bit number contained in the last SOF):
|
||||||
* - full-speed: the host sends one SOF every 1ms (so 1000 SOF/s)
|
* - full-speed: the host sends one SOF every 1ms (so 1000 SOF/s)
|
||||||
|
|
|
||||||
|
|
@ -343,37 +343,37 @@ int usb_drv_port_speed(void)
|
||||||
return (USB_DEV_STS & USB_DEV_STS_MASK_SPD) ? 0 : 1;
|
return (USB_DEV_STS & USB_DEV_STS_MASK_SPD) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
(void)max_packet_size;
|
{
|
||||||
|
/* FIXME: support max packet size override */
|
||||||
|
const int epnum = EP_NUM(ep);
|
||||||
|
const int epdir = EP_DIR(ep);
|
||||||
|
const int type = ctx->type[epnum][epdir];
|
||||||
|
|
||||||
int i = EP_NUM(endpoint);
|
if (epdir == DIR_IN) {
|
||||||
// int d = EP_DIR(endpoint) == DIR_IN ? 0 : 1;
|
USB_IEP_CTRL(epnum) = USB_EP_CTRL_FLUSH |
|
||||||
|
USB_EP_CTRL_SNAK |
|
||||||
if (EP_DIR(endpoint) == DIR_IN) {
|
USB_EP_CTRL_ACT |
|
||||||
USB_IEP_CTRL(i) = USB_EP_CTRL_FLUSH |
|
(type << 4);
|
||||||
USB_EP_CTRL_SNAK |
|
USB_DEV_EP_INTR_MASK &= ~(1<<epnum);
|
||||||
USB_EP_CTRL_ACT |
|
|
||||||
(type << 4);
|
|
||||||
USB_DEV_EP_INTR_MASK &= ~(1<<i);
|
|
||||||
} else {
|
} else {
|
||||||
USB_OEP_CTRL(i) = USB_EP_CTRL_FLUSH |
|
USB_OEP_CTRL(epnum) = USB_EP_CTRL_FLUSH |
|
||||||
USB_EP_CTRL_SNAK |
|
USB_EP_CTRL_SNAK |
|
||||||
USB_EP_CTRL_ACT |
|
USB_EP_CTRL_ACT |
|
||||||
(type << 4);
|
(type << 4);
|
||||||
USB_DEV_EP_INTR_MASK &= ~(1<<(16+i));
|
USB_DEV_EP_INTR_MASK &= ~(1<<(16+epnum));
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint) {
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
int i = EP_NUM(endpoint);
|
{
|
||||||
int d = EP_DIR(endpoint) == DIR_IN ? 0 : 1;
|
(void)ctx;
|
||||||
|
int i = EP_NUM(ep);
|
||||||
|
int d = EP_DIR(ep) == DIR_IN ? 0 : 1;
|
||||||
|
|
||||||
endpoints[i][d].state = 0;
|
endpoints[i][d].state = 0;
|
||||||
USB_DEV_EP_INTR_MASK |= (1<<(16*d+i));
|
USB_DEV_EP_INTR_MASK |= (1<<(16*d+i));
|
||||||
USB_EP_CTRL(i, !d) = USB_EP_CTRL_FLUSH | USB_EP_CTRL_SNAK;
|
USB_EP_CTRL(i, !d) = USB_EP_CTRL_FLUSH | USB_EP_CTRL_SNAK;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_drv_cancel_all_transfers(void)
|
void usb_drv_cancel_all_transfers(void)
|
||||||
|
|
|
||||||
|
|
@ -280,27 +280,30 @@ int usb_drv_port_speed(void)
|
||||||
return (DEV_INFO & DEV_SPEED) ? 0 : 1;
|
return (DEV_INFO & DEV_SPEED) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
(void)max_packet_size; /* FIXME: support max packet size override */
|
{
|
||||||
|
/* FIXME: support max packet size override */
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
int num = EP_NUM(endpoint);
|
const int epnum = EP_NUM(ep);
|
||||||
// int dir = EP_DIR(endpoint);
|
const int epdir = EP_DIR(ep);
|
||||||
(void)type;
|
|
||||||
|
|
||||||
struct endpoint_t *endp = &endpoints[num];
|
struct endpoint_t *endp = &endpoints[epnum];
|
||||||
|
|
||||||
if(EP_DIR(endpoint) == DIR_IN)
|
if(epdir == DIR_IN)
|
||||||
TXCON(endp) = (num << 8) | TXEPEN | TXNAK | TXACKINTEN | TXCFINTE;
|
TXCON(endp) = (epnum << 8) | TXEPEN | TXNAK | TXACKINTEN | TXCFINTE;
|
||||||
else
|
else
|
||||||
RXCON(endp) = (num << 8) | RXEPEN | RXNAK | RXACKINTEN | RXCFINTE | RXERRINTEN;
|
RXCON(endp) = (epnum << 8) | RXEPEN | RXNAK | RXACKINTEN | RXCFINTE | RXERRINTEN;
|
||||||
EN_INT |= 1 << (num + 7);
|
EN_INT |= 1 << (epnum + 7);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint) {
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
int num = EP_NUM(endpoint);
|
{
|
||||||
// struct endpoint_t *endp = &endpoints[num];
|
(void)ctx;
|
||||||
|
|
||||||
|
int num = EP_NUM(ep);
|
||||||
|
|
||||||
/* disable interrupt from this endpoint */
|
/* disable interrupt from this endpoint */
|
||||||
EN_INT &= ~(1 << (num + 7));
|
EN_INT &= ~(1 << (num + 7));
|
||||||
|
|
|
||||||
|
|
@ -1489,17 +1489,21 @@ void usb_drv_set_test_mode(int mode)
|
||||||
tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val);
|
tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val);
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
(void)max_packet_size; /* FIXME: support max packet size override */
|
{
|
||||||
(void)type;
|
/* FIXME: support max packet size override */
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
int num = EP_NUM(endpoint);
|
int num = EP_NUM(ep);
|
||||||
int dir = EP_DIR(endpoint);
|
int dir = EP_DIR(ep);
|
||||||
return tnetv_gadget_ep_enable(num, dir == DIR_IN);
|
return tnetv_gadget_ep_enable(num, dir == DIR_IN);
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint) {
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
int num = EP_NUM(endpoint);
|
{
|
||||||
int dir = EP_DIR(endpoint);
|
(void)ctx;
|
||||||
|
|
||||||
|
int num = EP_NUM(ep);
|
||||||
|
int dir = EP_DIR(ep);
|
||||||
return tnetv_gadget_ep_disable(num, dir == DIR_IN);
|
return tnetv_gadget_ep_disable(num, dir == DIR_IN);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -451,6 +451,42 @@ void usb_drv_startup(void)
|
||||||
((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL"))))
|
((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL"))))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void init_endpoint(int ep, int type, int mps) {
|
||||||
|
const int ep_num = EP_NUM(ep);
|
||||||
|
const int ep_dir = EP_DIR(ep);
|
||||||
|
|
||||||
|
logf("ep init: %d %s %s", ep_num, XFER_DIR_STR(ep_dir), XFER_TYPE_STR(type));
|
||||||
|
|
||||||
|
struct queue_head* qh;
|
||||||
|
unsigned int ctrl = REG_ENDPTCTRL(ep_num);
|
||||||
|
if(ep_dir == DIR_IN) {
|
||||||
|
ctrl &= ~EPCTRL_TX_TYPE;
|
||||||
|
ctrl |= EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE | type << EPCTRL_TX_EP_TYPE_SHIFT;
|
||||||
|
qh = &qh_array[ep_num * 2 + 1];
|
||||||
|
} else {
|
||||||
|
ctrl &= ~EPCTRL_RX_TYPE;
|
||||||
|
ctrl |= EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE | type << EPCTRL_RX_EP_TYPE_SHIFT;
|
||||||
|
qh = &qh_array[ep_num * 2];
|
||||||
|
}
|
||||||
|
REG_ENDPTCTRL(ep_num) = ctrl;
|
||||||
|
|
||||||
|
if(mps == -1) {
|
||||||
|
if(type == USB_ENDPOINT_XFER_ISOC) {
|
||||||
|
mps = 1024;
|
||||||
|
} else {
|
||||||
|
mps = usb_drv_port_speed() ? 512 : 64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(type == USB_ENDPOINT_XFER_ISOC)
|
||||||
|
/* FIXME: we can adjust the number of packets per frame, currently use one */
|
||||||
|
qh->max_pkt_length = mps << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
|
||||||
|
else
|
||||||
|
qh->max_pkt_length = mps << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
|
||||||
|
|
||||||
|
qh->dtd.next_td_ptr = QH_NEXT_TERMINATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* manual: 32.14.1 Device Controller Initialization */
|
/* manual: 32.14.1 Device Controller Initialization */
|
||||||
void usb_drv_init(void)
|
void usb_drv_init(void)
|
||||||
{
|
{
|
||||||
|
|
@ -494,8 +530,8 @@ void usb_drv_init(void)
|
||||||
* will cause undefined behavior for the data pid tracking on the active
|
* will cause undefined behavior for the data pid tracking on the active
|
||||||
* endpoint/direction. */
|
* endpoint/direction. */
|
||||||
for(int ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) {
|
for(int ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) {
|
||||||
usb_drv_init_endpoint(ep_num | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, -1);
|
init_endpoint(ep_num | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, -1);
|
||||||
usb_drv_init_endpoint(ep_num | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, -1);
|
init_endpoint(ep_num | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -984,46 +1020,16 @@ void usb_drv_cancel_all_transfers(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep) {
|
||||||
int ep_num = EP_NUM(endpoint);
|
const int ep_num = EP_NUM(ep);
|
||||||
int ep_dir = EP_DIR(endpoint);
|
const int ep_dir = EP_DIR(ep);
|
||||||
|
init_endpoint(ep, ctx->type[ep_num][ep_dir], ctx->max_packet_size[ep_num][ep_dir]);
|
||||||
logf("ep init: %d %s %s", ep_num, XFER_DIR_STR(ep_dir), XFER_TYPE_STR(type));
|
|
||||||
|
|
||||||
struct queue_head* qh;
|
|
||||||
unsigned int ctrl = REG_ENDPTCTRL(ep_num);
|
|
||||||
if(ep_dir == DIR_IN) {
|
|
||||||
ctrl &= ~EPCTRL_TX_TYPE;
|
|
||||||
ctrl |= EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE | type << EPCTRL_TX_EP_TYPE_SHIFT;
|
|
||||||
qh = &qh_array[ep_num * 2 + 1];
|
|
||||||
} else {
|
|
||||||
ctrl &= ~EPCTRL_RX_TYPE;
|
|
||||||
ctrl |= EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE | type << EPCTRL_RX_EP_TYPE_SHIFT;
|
|
||||||
qh = &qh_array[ep_num * 2];
|
|
||||||
}
|
|
||||||
REG_ENDPTCTRL(ep_num) = ctrl;
|
|
||||||
|
|
||||||
if(max_packet_size == -1) {
|
|
||||||
if(type == USB_ENDPOINT_XFER_ISOC) {
|
|
||||||
max_packet_size = 1024;
|
|
||||||
} else {
|
|
||||||
max_packet_size = usb_drv_port_speed() ? 512 : 64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(type == USB_ENDPOINT_XFER_ISOC)
|
|
||||||
/* FIXME: we can adjust the number of packets per frame, currently use one */
|
|
||||||
qh->max_pkt_length = max_packet_size << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
|
|
||||||
else
|
|
||||||
qh->max_pkt_length = max_packet_size << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
|
|
||||||
|
|
||||||
qh->dtd.next_td_ptr = QH_NEXT_TERMINATE;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint) {
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep) {
|
||||||
int ep_num = EP_NUM(endpoint);
|
(void)ctx;
|
||||||
int ep_dir = EP_DIR(endpoint);
|
int ep_num = EP_NUM(ep);
|
||||||
|
int ep_dir = EP_DIR(ep);
|
||||||
|
|
||||||
logf("ep deinit: %d %s", ep_num, XFER_DIR_STR(ep_dir));
|
logf("ep deinit: %d %s", ep_num, XFER_DIR_STR(ep_dir));
|
||||||
|
|
||||||
|
|
@ -1032,8 +1038,6 @@ int usb_drv_deinit_endpoint(int endpoint) {
|
||||||
} else {
|
} else {
|
||||||
REG_ENDPTCTRL(ep_num) &= ~EPCTRL_RX_ENABLE & ~EPCTRL_RX_TYPE;
|
REG_ENDPTCTRL(ep_num) &= ~EPCTRL_RX_ENABLE & ~EPCTRL_RX_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void prepare_td(struct transfer_descriptor* td,
|
static void prepare_td(struct transfer_descriptor* td,
|
||||||
|
|
|
||||||
|
|
@ -588,19 +588,23 @@ void INT_USB_FUNC(void)
|
||||||
GINTSTS = sts;
|
GINTSTS = sts;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
(void)max_packet_size; /* FIXME: support max packet size override */
|
{
|
||||||
|
/* FIXME: support max packet size override */
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
int num = EP_NUM(endpoint);
|
const int epnum = EP_NUM(ep);
|
||||||
int dir = EP_DIR(endpoint);
|
const int epdir = EP_DIR(ep);
|
||||||
bool out = dir == DIR_OUT;
|
const int type = ctx->type[epnum][epdir];
|
||||||
DEPCTL(num, out) = (DEPCTL(num, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp))
|
|
||||||
|
bool out = epdir == DIR_OUT;
|
||||||
|
DEPCTL(epnum, out) = (DEPCTL(epnum, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp))
|
||||||
| DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp) | DEPCTL_usbactep;
|
| DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp) | DEPCTL_usbactep;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint) {
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
return 0;
|
{
|
||||||
|
(void)ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usb_drv_cancel_all_transfers()
|
void usb_drv_cancel_all_transfers()
|
||||||
|
|
|
||||||
|
|
@ -100,16 +100,17 @@ static struct tcc_ep tcc_endpoints[] = {
|
||||||
static bool usb_drv_write_ep(struct tcc_ep *ep);
|
static bool usb_drv_write_ep(struct tcc_ep *ep);
|
||||||
static void usb_set_speed(int);
|
static void usb_set_speed(int);
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
(void)max_packet_size; /* FIXME: support max packet size override */
|
{
|
||||||
|
/* FIXME: support max packet size override */
|
||||||
tcc_endpoints[EP_NUM(endpoint)].dir = EP_DIR(endpoint) == DIR_IN ? USB_DIR_IN : USB_DIR_OUT;
|
(void)ctx;
|
||||||
return 0;
|
tcc_endpoints[EP_NUM(ep)].dir = EP_DIR(ep) == DIR_IN ? USB_DIR_IN : USB_DIR_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint) {
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
tcc_endpoints[EP_NUM(endpoint)].dir = -1;
|
{
|
||||||
return 0;
|
(void)ctx;
|
||||||
|
tcc_endpoints[EP_NUM(ep)].dir = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void pullup_on(void)
|
static inline void pullup_on(void)
|
||||||
|
|
|
||||||
|
|
@ -836,14 +836,15 @@ void usb_drv_cancel_all_transfers(void)
|
||||||
restore_irq(flags);
|
restore_irq(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
(void)endpoint;
|
{
|
||||||
(void)type;
|
/* FIXME: support max packet size override */
|
||||||
(void)max_packet_size; /* FIXME: support max packet size override */
|
(void)ctx;
|
||||||
return 0;
|
(void)ep;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint) {
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
(void)endpoint;
|
{
|
||||||
return 0;
|
(void)ctx;
|
||||||
|
(void)ep;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1192,12 +1192,12 @@ void usb_drv_cancel_all_transfers(void)
|
||||||
restore_irq(flags);
|
restore_irq(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
void usb_drv_ep_init(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
(void)max_packet_size; /* FIXME: support max packet size override */
|
{
|
||||||
(void)type;
|
/* FIXME: support max packet size override */
|
||||||
|
(void)ctx;
|
||||||
int num = EP_NUM(endpoint);
|
int num = EP_NUM(ep);
|
||||||
int dir = EP_DIR(endpoint);
|
int dir = EP_DIR(ep);
|
||||||
int index = num * 2 + (dir == DIR_OUT ? 1 : 0);
|
int index = num * 2 + (dir == DIR_OUT ? 1 : 0);
|
||||||
endpoints[index].allocated = true;
|
endpoints[index].allocated = true;
|
||||||
if(dir == DIR_IN)
|
if(dir == DIR_IN)
|
||||||
|
|
@ -1207,9 +1207,11 @@ int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_deinit_endpoint(int endpoint) {
|
void usb_drv_ep_deinit(const struct usb_drv_ep_alloc_ctx* ctx, int ep)
|
||||||
int num = EP_NUM(endpoint);
|
{
|
||||||
int dir = EP_DIR(endpoint);
|
(void)ctx;
|
||||||
|
int num = EP_NUM(ep);
|
||||||
|
int dir = EP_DIR(ep);
|
||||||
int index = num * 2 + (dir == DIR_OUT ? 1 : 0);
|
int index = num * 2 + (dir == DIR_OUT ? 1 : 0);
|
||||||
endpoints[index].allocated = false;
|
endpoints[index].allocated = false;
|
||||||
if(dir == DIR_IN)
|
if(dir == DIR_IN)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "usb_ch9.h"
|
#include "usb_ch9.h"
|
||||||
#include "usb_drv.h"
|
|
||||||
#include "usb_core.h"
|
#include "usb_core.h"
|
||||||
#include "usb_class_driver.h"
|
#include "usb_class_driver.h"
|
||||||
|
|
||||||
|
|
@ -57,6 +56,12 @@
|
||||||
#include "usb_iap.h"
|
#include "usb_iap.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* include order matters, include driver header before usb_drv.h */
|
||||||
|
#if CONFIG_USBOTG == USBOTG_DESIGNWARE
|
||||||
|
#include "usb-designware.h"
|
||||||
|
#endif
|
||||||
|
#include "usb_drv.h"
|
||||||
|
|
||||||
/* TODO: Move target-specific stuff somewhere else (serial number reading) */
|
/* TODO: Move target-specific stuff somewhere else (serial number reading) */
|
||||||
|
|
||||||
#if defined(IPOD_ARCH) && defined(CPU_PP)
|
#if defined(IPOD_ARCH) && defined(CPU_PP)
|
||||||
|
|
@ -179,8 +184,6 @@ static int usb_no_host_callback(struct timeout *tmo)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int usb_core_num_interfaces[NUM_CONFIGS];
|
|
||||||
|
|
||||||
typedef void (*completion_handler_t)(int ep, int dir, int status, int length);
|
typedef void (*completion_handler_t)(int ep, int dir, int status, int length);
|
||||||
typedef bool (*fast_completion_handler_t)(int ep, int dir, int status, int length);
|
typedef bool (*fast_completion_handler_t)(int ep, int dir, int status, int length);
|
||||||
typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, void* reqdata,
|
typedef bool (*control_handler_t)(struct usb_ctrlrequest* req, void* reqdata,
|
||||||
|
|
@ -199,7 +202,13 @@ struct ep_alloc_state {
|
||||||
struct usb_class_driver* owner[2];
|
struct usb_class_driver* owner[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ep_alloc_state ep_alloc_states[NUM_CONFIGS][USB_NUM_ENDPOINTS];
|
struct config_state {
|
||||||
|
struct usb_drv_ep_alloc_ctx ep_alloc_ctx;
|
||||||
|
struct ep_alloc_state ep_alloc_states[USB_NUM_ENDPOINTS];
|
||||||
|
uint8_t num_interfaces;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_state config_states[NUM_CONFIGS];
|
||||||
|
|
||||||
static struct usb_class_driver* drivers[USB_NUM_DRIVERS] =
|
static struct usb_class_driver* drivers[USB_NUM_DRIVERS] =
|
||||||
{
|
{
|
||||||
|
|
@ -407,9 +416,6 @@ void usb_core_init(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear endpoint allocation state */
|
|
||||||
memset(ep_alloc_states, 0, sizeof(ep_alloc_states));
|
|
||||||
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
usb_state = DEFAULT;
|
usb_state = DEFAULT;
|
||||||
usb_config = 0;
|
usb_config = 0;
|
||||||
|
|
@ -548,52 +554,86 @@ static void usb_core_set_serial_function_id(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* synchronize endpoint initialization state to allocation state */
|
/* synchronize endpoint initialization state to allocation state */
|
||||||
static void init_deinit_endpoints(uint8_t conf_index, bool init) {
|
static void init_deinit_endpoints(int config, bool init) {
|
||||||
for(int epnum = 0; epnum < USB_NUM_ENDPOINTS; epnum += 1) {
|
for(int epnum = 0; epnum < USB_NUM_ENDPOINTS; epnum += 1) {
|
||||||
for(int dir = 0; dir < 2; dir += 1) {
|
for(int dir = 0; dir < 2; dir += 1) {
|
||||||
struct ep_alloc_state* alloc = &ep_alloc_states[conf_index][epnum];
|
struct config_state* cstate = &config_states[config - 1];
|
||||||
struct usb_class_driver* driver = alloc->owner[dir];
|
struct ep_alloc_state* astate = &cstate->ep_alloc_states[epnum];
|
||||||
|
struct usb_class_driver* driver = astate->owner[dir];
|
||||||
if(driver == NULL) {
|
if(driver == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int ep = epnum | (dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
|
int ep = epnum | (dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
|
||||||
int ret;
|
|
||||||
if(init) {
|
|
||||||
int ps = driver->get_max_packet_size ? driver->get_max_packet_size(ep) : -1;
|
|
||||||
ret = usb_drv_init_endpoint(ep, alloc->type[dir], ps);
|
|
||||||
} else {
|
|
||||||
ret = usb_drv_deinit_endpoint(ep);
|
|
||||||
}
|
|
||||||
if(ret) {
|
|
||||||
logf("usb_core: usb_drv_%s_endpoint failed ep=%d dir=%d", init ? "init" : "deinit", epnum, dir);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(init) {
|
if(init) {
|
||||||
|
usb_drv_ep_init(&cstate->ep_alloc_ctx, ep);
|
||||||
ep_data[epnum].completion_handler[dir] = driver->transfer_complete;
|
ep_data[epnum].completion_handler[dir] = driver->transfer_complete;
|
||||||
ep_data[epnum].fast_completion_handler[dir] = driver->fast_transfer_complete;
|
ep_data[epnum].fast_completion_handler[dir] = driver->fast_transfer_complete;
|
||||||
ep_data[epnum].control_handler[dir] = driver->control_request;
|
ep_data[epnum].control_handler[dir] = driver->control_request;
|
||||||
|
} else {
|
||||||
|
usb_drv_ep_deinit(&cstate->ep_alloc_ctx, ep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef usb_drv_ep_alloc_ctx
|
||||||
|
/* default endpoint allocator using usb_drv_ep_specs table */
|
||||||
|
static void usb_drv_ep_reset_alloc_ctx(struct usb_drv_ep_alloc_ctx* ctx) {
|
||||||
|
for(int i = 0; i < USB_NUM_ENDPOINTS; i += 1) {
|
||||||
|
ctx->type[i][0] = -1;
|
||||||
|
ctx->type[i][1] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool usb_drv_ep_allocate(struct usb_drv_ep_alloc_ctx* ctx, int ep, int type, int max_packet_size) {
|
||||||
|
const uint8_t epnum = EP_NUM(ep);
|
||||||
|
const uint8_t epdir = EP_DIR(ep);
|
||||||
|
|
||||||
|
struct usb_drv_ep_spec* spec = &usb_drv_ep_specs[epnum];
|
||||||
|
|
||||||
|
const int8_t spec_type = spec->type[epdir];
|
||||||
|
if(spec_type != type && spec_type != USB_ENDPOINT_TYPE_ANY) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int8_t other_type = ctx->type[epnum][!epdir];
|
||||||
|
if(usb_drv_ep_specs_flags & USB_ENDPOINT_SPEC_IO_EXCLUSIVE && other_type != -1) {
|
||||||
|
/* the other side is allocated */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(usb_drv_ep_specs_flags & USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH && other_type != -1 && other_type != type) {
|
||||||
|
/* the other side is allocated with another type */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->type[epnum][epdir] = type;
|
||||||
|
ctx->max_packet_size[epnum][epdir] = max_packet_size;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void allocate_interfaces_and_endpoints(void)
|
static void allocate_interfaces_and_endpoints(void)
|
||||||
{
|
{
|
||||||
if(usb_config != 0) {
|
if(usb_config != 0) {
|
||||||
/* deinit currently used endpoints */
|
/* deinit currently used endpoints */
|
||||||
init_deinit_endpoints(usb_config - 1, false);
|
init_deinit_endpoints(usb_config, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
retry:
|
||||||
/* reset allocations */
|
/* reset allocations */
|
||||||
memset(ep_alloc_states, 0, sizeof(ep_alloc_states));
|
for(int i = 0; i < NUM_CONFIGS; i += 1) {
|
||||||
|
config_states[i].num_interfaces = 0;
|
||||||
int interface[NUM_CONFIGS] = {0};
|
memset(config_states[i].ep_alloc_states, 0, sizeof(config_states[i].ep_alloc_states));
|
||||||
|
usb_drv_ep_reset_alloc_ctx(&config_states[i].ep_alloc_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < USB_NUM_DRIVERS; i++) {
|
for(int i = 0; i < USB_NUM_DRIVERS; i++) {
|
||||||
struct usb_class_driver* driver = drivers[i];
|
struct usb_class_driver* driver = drivers[i];
|
||||||
const uint8_t conf_index = driver->config - 1;
|
struct config_state* cstate = &config_states[driver->config - 1];
|
||||||
|
|
||||||
if(!driver->enabled) {
|
if(!driver->enabled || driver->error) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -603,69 +643,38 @@ static void allocate_interfaces_and_endpoints(void)
|
||||||
struct usb_class_driver_ep_allocation* req = &driver->ep_allocs[reqnum];
|
struct usb_class_driver_ep_allocation* req = &driver->ep_allocs[reqnum];
|
||||||
req->ep = 0;
|
req->ep = 0;
|
||||||
for(int epnum = 1; epnum < USB_NUM_ENDPOINTS; epnum += 1) {
|
for(int epnum = 1; epnum < USB_NUM_ENDPOINTS; epnum += 1) {
|
||||||
struct usb_drv_ep_spec* spec = &usb_drv_ep_specs[epnum];
|
|
||||||
/* ep type check */
|
|
||||||
const int8_t spec_type = spec->type[req->dir];
|
|
||||||
if(spec_type != req->type && spec_type != USB_ENDPOINT_TYPE_ANY) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* free check */
|
/* free check */
|
||||||
struct ep_alloc_state* alloc = &ep_alloc_states[conf_index][epnum];
|
struct ep_alloc_state* alloc = &cstate->ep_alloc_states[epnum];
|
||||||
if(alloc->owner[req->dir] != NULL) {
|
if(alloc->owner[req->dir] != NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this ep's requested direction is free */
|
/* driver specific check */
|
||||||
|
const int ep = epnum | (req->dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
|
||||||
/* another checks */
|
const int ps = driver->get_max_packet_size ? driver->get_max_packet_size(ep) : -1;
|
||||||
if(usb_drv_ep_specs_flags & USB_ENDPOINT_SPEC_IO_EXCLUSIVE) {
|
if(!usb_drv_ep_allocate(&cstate->ep_alloc_ctx, ep, req->type, ps)) {
|
||||||
/* check for the other direction type */
|
continue;
|
||||||
if(alloc->owner[!req->dir] != NULL) {
|
|
||||||
/* the other side is allocated */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(usb_drv_ep_specs_flags & USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH) {
|
|
||||||
/* check for other direction type */
|
|
||||||
if(alloc->owner[!req->dir] != NULL && alloc->type[!req->dir] != req->type) {
|
|
||||||
/* the other side is allocated with another type */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* all checks passed, assign it */
|
/* all checks passed, assign it */
|
||||||
const int ep = epnum | (req->dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
|
|
||||||
req->ep = ep;
|
req->ep = ep;
|
||||||
alloc->owner[req->dir] = driver;
|
alloc->owner[req->dir] = driver;
|
||||||
alloc->type[req->dir] = req->type;
|
alloc->type[req->dir] = req->type;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(req->ep == 0 && !req->optional) {
|
if(req->ep == 0 && !req->optional) {
|
||||||
/* no matching ep found, disable the driver */
|
/* no matching ep found, retry allocation excluding this driver */
|
||||||
|
logf("usb_core: no endpoint allocated for driver %d", i);
|
||||||
driver->enabled = false;
|
driver->enabled = false;
|
||||||
/* also revert all allocations for this driver */
|
goto retry;
|
||||||
for(reqnum = reqnum - 1; reqnum >= 0; reqnum -= 1) {
|
|
||||||
const uint8_t ep = driver->ep_allocs[reqnum].ep;
|
|
||||||
const uint8_t epnum = EP_NUM(ep);
|
|
||||||
const uint8_t epdir = EP_DIR(ep);
|
|
||||||
const uint8_t dir = epdir == USB_DIR_OUT ? DIR_OUT : DIR_IN;
|
|
||||||
ep_alloc_states[conf_index][epnum].owner[dir] = NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!driver->enabled) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* assign interfaces */
|
/* assign interfaces */
|
||||||
driver->first_interface = interface[conf_index];
|
driver->first_interface = cstate->num_interfaces;
|
||||||
interface[conf_index] = driver->set_first_interface(interface[conf_index]);
|
cstate->num_interfaces = driver->set_first_interface(cstate->num_interfaces);
|
||||||
driver->last_interface = interface[conf_index];
|
driver->last_interface = cstate->num_interfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(usb_core_num_interfaces, interface, sizeof(interface));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -765,7 +774,7 @@ static void request_handler_device_get_descriptor(struct usb_ctrlrequest* req, v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config_descriptor.bNumInterfaces = usb_core_num_interfaces[index];
|
config_descriptor.bNumInterfaces = config_states[index].num_interfaces;
|
||||||
config_descriptor.bConfigurationValue = index + 1;
|
config_descriptor.bConfigurationValue = index + 1;
|
||||||
config_descriptor.wTotalLength = (uint16_t)size;
|
config_descriptor.wTotalLength = (uint16_t)size;
|
||||||
memcpy(&response_data[0], &config_descriptor, sizeof(struct usb_config_descriptor));
|
memcpy(&response_data[0], &config_descriptor, sizeof(struct usb_config_descriptor));
|
||||||
|
|
@ -844,7 +853,7 @@ static int usb_core_do_set_config(uint8_t new_config)
|
||||||
drivers[i]->disconnect();
|
drivers[i]->disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
init_deinit_endpoints(usb_config - 1, false);
|
init_deinit_endpoints(usb_config, false);
|
||||||
|
|
||||||
/* clear any pending transfer completions,
|
/* clear any pending transfer completions,
|
||||||
* because they are depend on contents of ep_data */
|
* because they are depend on contents of ep_data */
|
||||||
|
|
@ -861,7 +870,7 @@ static int usb_core_do_set_config(uint8_t new_config)
|
||||||
|
|
||||||
/* activate new config */
|
/* activate new config */
|
||||||
if(usb_config != 0) {
|
if(usb_config != 0) {
|
||||||
init_deinit_endpoints(usb_config - 1, true);
|
init_deinit_endpoints(usb_config, true);
|
||||||
for(int i = 0; i < USB_NUM_DRIVERS; i++) {
|
for(int i = 0; i < USB_NUM_DRIVERS; i++) {
|
||||||
if(!is_active(drivers[i])) {
|
if(!is_active(drivers[i])) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue