usb: implement endpoint allocation

this commit has following changes:
- introduce `usb_drv_ep_spec` table to udc drivers, which represents
  endpoint characteristics.
- introduce 'ep_allocs' table to class drivers, which represents what
  endpoint type does the class driver want.
- implement endpoint matching logic to usb core.

this is a required step to implement usb config switching, because we
need to create config descriptors without actually initializing endpoints.

Change-Id: I11c324cd35189ab636744488f6259d0cdb2179f0
This commit is contained in:
mojyack 2025-12-17 11:13:43 +09:00 committed by Solomon Peachy
parent f13f80c506
commit 350a2250b1
27 changed files with 579 additions and 714 deletions

View file

@ -29,6 +29,9 @@
#include "logf.h"
#include "stdio.h"
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;
struct usb_endpoint
{
unsigned char *out_buf;
@ -48,7 +51,6 @@ struct usb_endpoint
unsigned char enabled[2];
short max_pkt_size[2];
short type;
char allocation;
};
static unsigned char setup_pkt_buf[8];
@ -470,6 +472,14 @@ void usb_drv_init(void)
//tick_add_task(usb_helper);
/* 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) {
usb_drv_ep_specs[i].type[DIR_OUT] = USB_ENDPOINT_XFER_BULK;
usb_drv_ep_specs[i].type[DIR_IN] = USB_ENDPOINT_XFER_BULK;
}
logf("usb_init_device() finished");
}
@ -616,29 +626,15 @@ void usb_drv_cancel_all_transfers(void)
endpoints[i].halt[0] = endpoints[i].halt[1] = 1;
}
int usb_drv_request_endpoint(int type, int dir)
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size)
{
int i, bit;
if (type != USB_ENDPOINT_XFER_BULK)
return -1;
bit=(dir & USB_DIR_IN)? 2:1;
for (i=1; i < USB_NUM_ENDPOINTS; i++) {
if((endpoints[i].allocation & bit)!=0)
continue;
endpoints[i].allocation |= bit;
return i | dir;
}
return -1;
(void)max_packet_size; /* FIXME: support max packet size override */
return 0;
}
void usb_drv_release_endpoint(int ep)
int usb_drv_deinit_endpoint(int endpoint)
{
int mask = (ep & USB_DIR_IN)? ~2:~1;
endpoints[ep & 0x7f].allocation &= mask;
return 0;
}
static void bus_reset(void)

View file

@ -59,6 +59,9 @@
* stack visible functions.
******************************************************************************/
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS]; /* filled in usb_drv_init */
uint8_t usb_drv_ep_specs_flags = USB_ENDPOINT_SPEC_IO_EXCLUSIVE;
static volatile unsigned short * pipe_ctrl_addr(int pipe);
static void pipe_handshake(int pipe, int handshake);
static void pipe_c_select (int pipe, bool dir);
@ -78,7 +81,6 @@ struct M66591_epstat {
int length; /* how match data will fit */
volatile int count; /* actual data count */
bool waiting; /* is there data to transfer? */
bool busy; /* has the pipe been requested for use? */
} ;
static struct M66591_epstat M66591_eps[USB_NUM_ENDPOINTS];
@ -638,82 +640,63 @@ void usb_drv_set_test_mode(int mode) {
M66591_TESTMODE |= mode;
}
/* Request an unused endpoint */
int usb_drv_request_endpoint(int type, int dir) {
int ep;
int pipecfg = 0;
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
(void)max_packet_size; /* FIXME: support max packet size override */
if (type == USB_ENDPOINT_XFER_BULK) {
int pipecfg;
if(type == USB_ENDPOINT_XFER_BULK) {
/* Enable double buffer mode (only used for ep 1 and 2) */
pipecfg |= 1<<9 | 1<<8;
/* Bulk endpoints must be between 1 and 4 inclusive */
ep=1;
while(M66591_eps[ep].busy && ep++<5);
/* If this reached 5 the endpoints were all busy */
if(ep==5) {
logf("mxx: ep %d busy", ep);
return -1;
}
} else if (type == USB_ENDPOINT_XFER_INT) {
ep=5;
} else if(type == USB_ENDPOINT_XFER_BULK) {
pipecfg |= 1<<13;
while(M66591_eps[ep].busy && ++ep<USB_NUM_ENDPOINTS);
/* If this reached USB_NUM_ENDPOINTS the endpoints were all busy */
if(ep==USB_NUM_ENDPOINTS) {
logf("mxx: ep %d busy", ep);
return -1;
}
} else {
/* Not a supported type */
return -1;
}
int num = endpoint & USB_ENDPOINT_NUMBER_MASK;
int dir = endpoint & USB_ENDPOINT_DIR_MASK;
if (dir == USB_DIR_IN) {
pipecfg |= (1<<4);
}
M66591_eps[num].dir = dir;
M66591_eps[ep].busy = true;
M66591_eps[ep].dir = dir;
M66591_PIPE_CFGSEL=ep;
M66591_PIPE_CFGSEL=num;
/* Enable pipe (15) */
pipecfg |= 1<<15;
pipe_handshake(ep, PIPE_SHAKE_NAK);
pipe_handshake(num, PIPE_SHAKE_NAK);
/* Setup the flags */
M66591_PIPE_CFGWND=pipecfg;
pipe_init(ep);
pipe_init(num);
logf("mxx: ep req ep#: %d config: 0x%04x", ep, M66591_PIPE_CFGWND);
logf("mxx: ep req ep#: %d config: 0x%04x", num, M66591_PIPE_CFGWND);
return ep | dir;
return 0;
}
/* Used by stack to tell the helper functions that the pipe is not in use */
void usb_drv_release_endpoint(int ep) {
int flags;
ep &= 0x7f;
int usb_drv_deinit_endpoint(int endpoint) {
int num = endpoint & USB_ENDPOINT_NUMBER_MASK;
if (ep < 1 || ep > USB_NUM_ENDPOINTS || M66591_eps[ep].busy == false)
return ;
if (num < 1 || num > USB_NUM_ENDPOINTS) {
return -1;
}
flags = disable_irq_save();
int flags = disable_irq_save();
logf("mxx: ep %d release", ep);
logf("mxx: ep %d release", num);
M66591_eps[ep].busy = false;
M66591_eps[ep].dir = -1;
M66591_eps[num].dir = -1;
restore_irq(flags);
return 0;
}
/* Periodically called to check if a cable was plugged into the device */
@ -744,6 +727,18 @@ void usb_drv_init(void) {
M66591_TRN_CTRL |=0x0001;
M66591_INTCFG_MAIN |=0x8000; /* Enable VBUS interrupt */
/* 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 < 5; i += 1) {
usb_drv_ep_specs[i].type[DIR_OUT] = USB_ENDPOINT_XFER_BULK;
usb_drv_ep_specs[i].type[DIR_IN] = USB_ENDPOINT_XFER_BULK;
}
for(int i = 5; i < USB_NUM_ENDPOINTS; i += 1) {
usb_drv_ep_specs[i].type[DIR_OUT] = USB_ENDPOINT_XFER_INT;
usb_drv_ep_specs[i].type[DIR_IN] = USB_ENDPOINT_XFER_INT;
}
}
/* fully enable driver */
@ -757,7 +752,6 @@ void usb_attach(void) {
M66591_eps[i].length = 0;
M66591_eps[i].count = 0;
M66591_eps[i].waiting = false;
M66591_eps[i].busy = false;
}
/* Issue a h/w reset */

View file

@ -144,6 +144,9 @@ struct usb_dw_ep0
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] =
{
[USB_DW_EPDIR_IN] = "IN",
@ -1495,6 +1498,17 @@ static void usb_dw_init(void)
/* Soft reconnect */
udelay(3000);
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)
@ -1592,56 +1606,50 @@ void INT_USB_FUNC(void)
usb_dw_irq();
}
int usb_drv_request_endpoint(int type, int dir)
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size)
{
int request_ep = -1;
enum usb_dw_epdir epdir = (EP_DIR(dir) == DIR_IN) ?
USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
(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;
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(endpoint), epdir);
int maxpktsize;
if(type == EPTYP_ISOCHRONOUS)
{
maxpktsize = 1023;
}
else
{
maxpktsize = usb_drv_port_speed() ? 512 : 64;
}
usb_dw_target_disable_irq();
for (int ep = 1; ep < USB_NUM_ENDPOINTS; ep++)
{
if (usb_endpoints & (1 << (ep + USB_DW_DIR_OFF(epdir))))
{
struct usb_dw_ep* dw_ep = usb_dw_get_ep(ep, epdir);
if (!dw_ep->active)
{
int maxpktsize = 64;
if (type == EPTYP_ISOCHRONOUS){
maxpktsize = 1023;
} else {
maxpktsize = usb_drv_port_speed() ? 512 : 64;
}
if (usb_dw_configure_ep(ep, epdir, type,
maxpktsize) >= 0)
{
dw_ep->active = true;
request_ep = ep | dir;
}
break;
}
}
}
int res = usb_dw_configure_ep(EP_NUM(endpoint), epdir, type, maxpktsize);
usb_dw_target_enable_irq();
return request_ep;
if(res >= 0)
{
dw_ep->active = true;
return 0;
}
else
{
return -1;
}
}
void usb_drv_release_endpoint(int endpoint)
int usb_drv_deinit_endpoint(int endpoint)
{
int epnum = EP_NUM(endpoint);
if (!epnum) return;
enum usb_dw_epdir epdir = (EP_DIR(endpoint) == DIR_IN) ?
USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
struct usb_dw_ep* dw_ep = usb_dw_get_ep(epnum, epdir);
enum usb_dw_epdir epdir = (EP_DIR(endpoint) == DIR_IN) ? USB_DW_EPDIR_IN : USB_DW_EPDIR_OUT;
struct usb_dw_ep* dw_ep = usb_dw_get_ep(EP_NUM(endpoint), epdir);
usb_dw_target_disable_irq();
if (dw_ep->active)
{
usb_dw_unconfigure_ep(epnum, epdir);
dw_ep->active = false;
}
usb_dw_unconfigure_ep(EP_NUM(endpoint), epdir);
usb_dw_target_enable_irq();
dw_ep->active = false;
return 0;
}
int usb_drv_recv_nonblocking(int endpoint, void* ptr, int length)

View file

@ -66,9 +66,6 @@ void usb_core_handle_notify(long id, intptr_t data);
void usb_core_notify_set_address(uint8_t addr);
void usb_core_notify_set_config(uint8_t config);
int usb_core_request_endpoint(int type, int dir,struct usb_class_driver* drv);
void usb_core_release_endpoint(int dir);
#ifdef HAVE_HOTSWAP
void usb_core_hotswap_event(int volume,bool inserted);
#endif

View file

@ -62,6 +62,19 @@ enum usb_control_response {
USB_CONTROL_RECEIVE,
};
#define USB_ENDPOINT_TYPE_ANY (-1)
#define USB_ENDPOINT_TYPE_NONE (-2)
struct usb_drv_ep_spec {
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];
#define USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH (1 << 0)
#define USB_ENDPOINT_SPEC_IO_EXCLUSIVE (1 << 1)
extern uint8_t usb_drv_ep_specs_flags;
/* one-time initialisation of the USB driver */
void usb_drv_startup(void);
void usb_drv_int_enable(bool enable); /* Target implemented */
@ -85,8 +98,8 @@ int usb_drv_port_speed(void);
void usb_drv_cancel_all_transfers(void);
void usb_drv_set_test_mode(int mode);
bool usb_drv_connected(void);
int usb_drv_request_endpoint(int type, int dir);
void usb_drv_release_endpoint(int ep);
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size);
int usb_drv_deinit_endpoint(int endpoint);
#ifdef USB_HAS_ISOCHRONOUS
/* 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)

View file

@ -36,6 +36,15 @@
#include "usb-drv-as3525.h"
/* OUT EP 2 is an alias for OUT EP 0 on this HW! */
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_EPS] = {
[0] = {USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_CONTROL},
[1] = {USB_ENDPOINT_TYPE_ANY, USB_ENDPOINT_TYPE_ANY},
[2] = {USB_ENDPOINT_TYPE_NONE, USB_ENDPOINT_TYPE_ANY},
[3] = {USB_ENDPOINT_TYPE_ANY, USB_ENDPOINT_TYPE_ANY},
};
uint8_t usb_drv_ep_specs_flags = 0;
static struct usb_endpoint endpoints[USB_NUM_EPS][2];
static int got_set_configuration = 0;
static int usb_enum_timeout = -1;
@ -155,16 +164,6 @@ static void reset_endpoints(int init)
{
int i;
/*
* OUT EP 2 is an alias for OUT EP 0 on this HW!
*
* Resonates with "3 bidirectional- plus 1 in-endpoints in device mode"
* from the datasheet, but why ep2 and not ep3?
*
* Reserve it here so we will skip over it in request_endpoint().
*/
endpoints[2][1].state |= EP_STATE_ALLOCATED;
for(i = 0; i < USB_NUM_EPS; i++) {
/*
* MPS sizes depending on speed:
@ -344,62 +343,37 @@ int usb_drv_port_speed(void)
return (USB_DEV_STS & USB_DEV_STS_MASK_SPD) ? 0 : 1;
}
int usb_drv_request_endpoint(int type, int dir)
{
int d = dir == USB_DIR_IN ? 0 : 1;
int i = 1; /* skip the control EP */
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
(void)max_packet_size;
for(; i < USB_NUM_EPS; i++) {
if (endpoints[i][d].state & EP_STATE_ALLOCATED)
continue;
int i = EP_NUM(endpoint);
int d = EP_DIR(endpoint) == DIR_IN ? 0 : 1;
endpoints[i][d].state |= EP_STATE_ALLOCATED;
if (dir == USB_DIR_IN) {
USB_IEP_CTRL(i) = USB_EP_CTRL_FLUSH |
USB_EP_CTRL_SNAK |
USB_EP_CTRL_ACT |
(type << 4);
USB_DEV_EP_INTR_MASK &= ~(1<<i);
} else {
USB_OEP_CTRL(i) = USB_EP_CTRL_FLUSH |
USB_EP_CTRL_SNAK |
USB_EP_CTRL_ACT |
(type << 4);
USB_DEV_EP_INTR_MASK &= ~(1<<(16+i));
}
/* logf("usb_drv_request_endpoint(%d, %d): returning %02x\n", type, dir, i | dir); */
return i | dir;
if (EP_DIR(endpoint) == DIR_IN) {
USB_IEP_CTRL(i) = USB_EP_CTRL_FLUSH |
USB_EP_CTRL_SNAK |
USB_EP_CTRL_ACT |
(type << 4);
USB_DEV_EP_INTR_MASK &= ~(1<<i);
} else {
USB_OEP_CTRL(i) = USB_EP_CTRL_FLUSH |
USB_EP_CTRL_SNAK |
USB_EP_CTRL_ACT |
(type << 4);
USB_DEV_EP_INTR_MASK &= ~(1<<(16+i));
}
logf("usb_drv_request_endpoint(%d, %d): no free endpoint found\n", type, dir);
return -1;
return 0;
}
void usb_drv_release_endpoint(int ep)
{
int i = ep & 0x7f;
int d = ep & USB_DIR_IN ? 0 : 1;
int usb_drv_deinit_endpoint(int endpoint) {
int i = EP_NUM(endpoint);
int d = EP_DIR(endpoint) == DIR_IN ? 0 : 1;
if (i >= USB_NUM_EPS)
return;
/*
* Check for control EP and ignore it.
* Unfortunately the usb core calls
* usb_drv_release_endpoint() for ep=0..(USB_NUM_ENDPOINTS-1),
* but doesn't request a new control EP after that...
*/
if (i == 0 || /* Don't mask control EP */
(i == 2 && d == 1)) /* See reset_endpoints(), EP2_OUT == EP0_OUT */
return;
if (!(endpoints[i][d].state & EP_STATE_ALLOCATED))
return;
/* logf("usb_drv_release_endpoint(%d, %d)\n", i, d); */
endpoints[i][d].state = 0;
USB_DEV_EP_INTR_MASK |= (1<<(16*d+i));
USB_EP_CTRL(i, !d) = USB_EP_CTRL_FLUSH | USB_EP_CTRL_SNAK;
return 0;
}
void usb_drv_cancel_all_transfers(void)

View file

@ -53,7 +53,6 @@ struct endpoint_t
const int type; /* EP type */
const int dir; /* DIR_IN/DIR_OUT */
volatile unsigned long *stat; /* RXSTAT/TXSTAT register */
bool allocated; /* flag to mark EPs taken */
volatile void *buf; /* tx/rx buffer address */
volatile int len; /* size of the transfer (bytes) */
volatile int cnt; /* number of bytes transfered/received */
@ -102,6 +101,9 @@ static struct endpoint_t endpoints[16] =
ENDPOINT(15, INT, IN, &TX15STAT), /* IIN15 */
};
struct usb_drv_ep_spec usb_drv_ep_specs[16]; /* filled in usb_drv_startup */
uint8_t usb_drv_ep_specs_flags = 0;
static volatile bool set_address = false;
static volatile bool set_configuration = false;
@ -260,48 +262,47 @@ static void udc_helper(void)
}
}
void usb_drv_startup(void) {
/* fill the endpoint spec table */
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 ep_num = 1; ep_num < 16; ep_num++) {
int dir = endpoints[ep_num].dir;
int type = endpoints[ep_num].type;
usb_drv_ep_specs[ep_num].type[dir] = type;
usb_drv_ep_specs[ep_num].type[!dir] = USB_ENDPOINT_TYPE_NONE;
}
}
/* return port speed FS=0, HS=1 */
int usb_drv_port_speed(void)
{
return (DEV_INFO & DEV_SPEED) ? 0 : 1;
}
/* Reserve endpoint */
int usb_drv_request_endpoint(int type, int dir)
{
logf("req: %s %s", XFER_DIR_STR(dir), XFER_TYPE_STR(type));
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
(void)max_packet_size; /* FIXME: support max packet size override */
/* Find an available ep/dir pair */
for(int ep_num = 1; ep_num<USB_NUM_ENDPOINTS;ep_num++)
{
struct endpoint_t *endp = &endpoints[ep_num];
int num = EP_NUM(endpoint);
int dir = EP_DIR(endpoint);
if(endp->allocated || endp->type != type || endp->dir != dir)
continue;
/* allocate endpoint and enable interrupt */
endp->allocated = true;
if(dir == USB_DIR_IN)
TXCON(endp) = (ep_num << 8) | TXEPEN | TXNAK | TXACKINTEN | TXCFINTE;
else
RXCON(endp) = (ep_num << 8) | RXEPEN | RXNAK | RXACKINTEN | RXCFINTE | RXERRINTEN;
EN_INT |= 1 << (ep_num + 7);
struct endpoint_t *endp = &endpoints[num];
logf("add: ep%d %s", ep_num, XFER_DIR_STR(dir));
return ep_num | dir;
}
return -1;
if(EP_DIR(endpoint) == DIR_IN)
TXCON(endp) = (num << 8) | TXEPEN | TXNAK | TXACKINTEN | TXCFINTE;
else
RXCON(endp) = (num << 8) | RXEPEN | RXNAK | RXACKINTEN | RXCFINTE | RXERRINTEN;
EN_INT |= 1 << (num + 7);
return 0;
}
/* Free endpoint */
void usb_drv_release_endpoint(int ep)
{
int ep_num = EP_NUM(ep);
logf("rel: ep%d", ep_num);
endpoints[ep_num].allocated = false;
int usb_drv_deinit_endpoint(int endpoint) {
int num = EP_NUM(endpoint);
struct endpoint_t *endp = &endpoints[num];
/* disable interrupt from this endpoint */
EN_INT &= ~(1 << (ep_num + 7));
EN_INT &= ~(1 << (num + 7));
}
/* Set the address (usually it's in a register).

View file

@ -46,6 +46,8 @@ void usb_init_device(void)
/* configure INTCON */
INTCON = UDC_INTHIGH_ACT | /* interrupt high active */
UDC_INTEN; /* enable EP0 interrupts */
usb_drv_startup();
}
void usb_attach(void)

View file

@ -60,11 +60,12 @@ static bool setup_is_set_address;
static cppi_info cppi;
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS]; /* filled in usb_drv_startup */
uint8_t usb_drv_ep_specs_flags = 0;
static struct ep_runtime_t
{
int max_packet_size;
bool in_allocated;
bool out_allocated;
uint8_t *rx_buf; /* OUT */
int rx_remaining;
int rx_size;
@ -1239,13 +1240,22 @@ void usb_charging_maxcurrent_change(int maxcurrent)
}
}
void usb_drv_startup(void)
{
/* fill the endpoint spec table */
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) {
usb_drv_ep_specs[i].type[DIR_OUT] = ep_const_data[i].type;
usb_drv_ep_specs[i].type[DIR_IN] = ep_const_data[i].type;
}
}
void usb_drv_init(void)
{
int epn;
memset(ep_runtime, 0, sizeof(ep_runtime));
ep_runtime[0].max_packet_size = EP0_MAX_PACKET_SIZE;
ep_runtime[0].in_allocated = true;
ep_runtime[0].out_allocated = true;
for (epn = 0; epn < USB_NUM_ENDPOINTS; epn++)
{
semaphore_init(&ep_runtime[epn].complete, 1, 0);
@ -1479,41 +1489,16 @@ void usb_drv_set_test_mode(int mode)
tnetv_usb_reg_write(TNETV_USB_CTRL, usbCtrl.val);
}
int usb_drv_request_endpoint(int type, int dir)
{
int epn;
for (epn = 1; epn < USB_NUM_ENDPOINTS; epn++)
{
if (type == ep_const_data[epn].type)
{
if ((dir == USB_DIR_IN) && (!ep_runtime[epn].in_allocated))
{
ep_runtime[epn].in_allocated = true;
tnetv_gadget_ep_enable(epn, true);
return epn | USB_DIR_IN;
}
if ((dir == USB_DIR_OUT) && (!ep_runtime[epn].out_allocated))
{
ep_runtime[epn].out_allocated = true;
tnetv_gadget_ep_enable(epn, false);
return epn | USB_DIR_OUT;
}
}
}
return -1;
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
(void)max_packet_size; /* FIXME: support max packet size override */
int num = EP_NUM(endpoint);
int dir = EP_DIR(endpoint);
return tnetv_gadget_ep_enable(num, dir == EP_IN);
}
void usb_drv_release_endpoint(int ep)
{
int epn = EP_NUM(ep);
if (EP_DIR(ep) == DIR_IN)
{
ep_runtime[epn].in_allocated = false;
tnetv_gadget_ep_disable(epn, true);
}
else
{
ep_runtime[epn].out_allocated = false;
tnetv_gadget_ep_disable(epn, false);
}
int usb_drv_deinit_endpoint(int endpoint) {
int num = EP_NUM(endpoint);
int dir = EP_DIR(endpoint);
return tnetv_gadget_ep_disable(num, dir == EP_IN);
}

View file

@ -23,6 +23,7 @@
#include "system.h"
#include "kernel.h"
#include "usb_core.h"
#include "usb_drv.h"
static int usb_detect_callback(struct timeout *tmo)
{
@ -82,6 +83,8 @@ void usb_init_device(void)
/* Enable USB insert detection interrupt */
IO_INTC_EINT1 |= (1 << 14);
usb_drv_startup();
}
void usb_enable(bool on)

View file

@ -308,13 +308,8 @@
transfer size, so it seems like a good size */
#define NUM_TDS_PER_EP 4
typedef struct usb_endpoint
{
bool allocated[2];
short type[2];
short max_pkt_size[2];
} usb_endpoint_t;
static usb_endpoint_t endpoints[USB_NUM_ENDPOINTS];
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS]; /* filled in usb_drv_startup */
uint8_t usb_drv_ep_specs_flags = USB_ENDPOINT_SPEC_FORCE_IO_TYPE_MATCH;
/* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */
struct transfer_descriptor {
@ -372,8 +367,6 @@ static void prepare_td(struct transfer_descriptor* td,
struct transfer_descriptor* previous_td, void *ptr, int len,int pipe);
static void bus_reset(void);
static void init_control_queue_heads(void);
static void init_queue_heads(void);
static void init_endpoints(void);
/*-------------------------------------------------------------------------*/
static void usb_drv_stop(void)
{
@ -430,6 +423,14 @@ void usb_drv_startup(void)
for(i=0;i<USB_NUM_ENDPOINTS*2;i++) {
semaphore_init(&transfer_completion_signal[i], 1, 0);
}
/* Fill the endpoint spec table */
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) {
usb_drv_ep_specs[i].type[DIR_OUT] = USB_ENDPOINT_TYPE_ANY;
usb_drv_ep_specs[i].type[DIR_IN] = USB_ENDPOINT_TYPE_ANY;
}
}
#ifdef LOGF_ENABLE
@ -439,18 +440,6 @@ void usb_drv_startup(void)
((type) == USB_ENDPOINT_XFER_ISOC ? "ISOC" : \
((type) == USB_ENDPOINT_XFER_BULK ? "BULK" : \
((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL"))))
static void log_ep(int ep_num, int ep_dir, char* prefix)
{
usb_endpoint_t* endpoint = &endpoints[ep_num];
logf("%s: ep%d %s %s %d", prefix, ep_num, XFER_DIR_STR(ep_dir),
XFER_TYPE_STR(endpoint->type[ep_dir]),
endpoint->max_pkt_size[ep_dir]);
}
#else
#undef log_ep
#define log_ep(...)
#endif
/* manual: 32.14.1 Device Controller Initialization */
@ -491,6 +480,14 @@ void usb_drv_init(void)
logf("usb dccparams %x", REG_DCCPARAMS);
/* now a bus reset will occur. see bus_reset() */
/* manual: 32.9.5.18 (Caution): Leaving an unconfigured endpoint control
* will cause undefined behavior for the data pid tracking on the active
* endpoint/direction. */
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);
usb_drv_init_endpoint(ep_num | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, -1);
}
}
void usb_drv_exit(void)
@ -631,8 +628,6 @@ bool usb_drv_powered(void)
void usb_drv_set_address(int address)
{
REG_DEVICEADDR = address << USBDEVICEADDRESS_BIT_POS;
init_queue_heads();
init_endpoints();
}
void usb_drv_reset_endpoint(int endpoint, bool send)
@ -797,52 +792,58 @@ void usb_drv_cancel_all_transfers(void)
}
}
int usb_drv_request_endpoint(int type, int dir)
{
int ep_num, ep_dir;
short ep_type;
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
int ep_num = EP_NUM(endpoint);
int ep_dir = EP_DIR(endpoint);
/* Safety */
ep_dir = EP_DIR(dir);
ep_type = type & USB_ENDPOINT_XFERTYPE_MASK;
logf("ep init: %d %s %s", ep_num, XFER_DIR_STR(ep_dir), XFER_TYPE_STR(type));
logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_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;
/* Find an available ep/dir pair */
for (ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) {
usb_endpoint_t* endpoint=&endpoints[ep_num];
int other_dir=(ep_dir ? 0:1);
if (endpoint->allocated[ep_dir])
continue;
if (endpoint->allocated[other_dir] &&
endpoint->type[other_dir] != ep_type) {
logf("ep of different type!");
continue;
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;
endpoint->allocated[ep_dir] = 1;
endpoint->type[ep_dir] = ep_type;
return 0;
}
log_ep(ep_num, ep_dir, "add");
return (ep_num | (dir & USB_ENDPOINT_DIR_MASK));
int usb_drv_deinit_endpoint(int endpoint) {
int ep_num = EP_NUM(endpoint);
int ep_dir = EP_DIR(endpoint);
logf("ep deinit: %d %s", ep_num, XFER_DIR_STR(ep_dir));
if(ep_dir == DIR_IN) {
REG_ENDPTCTRL(ep_num) &= ~EPCTRL_TX_ENABLE & ~EPCTRL_TX_TYPE;
} else {
REG_ENDPTCTRL(ep_num) &= ~EPCTRL_RX_ENABLE & ~EPCTRL_RX_TYPE;
}
return -1;
return 0;
}
void usb_drv_release_endpoint(int ep)
{
int ep_num = EP_NUM(ep);
int ep_dir = EP_DIR(ep);
log_ep(ep_num, ep_dir, "rel");
endpoints[ep_num].allocated[ep_dir] = 0;
}
static void prepare_td(struct transfer_descriptor* td,
struct transfer_descriptor* previous_td,
void *ptr, int len,int pipe)
@ -978,57 +979,3 @@ static void init_control_queue_heads(void)
qh_array[EP_CONTROL+1].max_pkt_length = 64 << QH_MAX_PKT_LEN_POS;
qh_array[EP_CONTROL+1].dtd.next_td_ptr = QH_NEXT_TERMINATE;
}
/* manual: 32.14.4.1 Queue Head Initialization */
static void init_queue_heads(void)
{
int packetsize = (usb_drv_port_speed() ? 512 : 64);
int isopacketsize = (usb_drv_port_speed() ? 1024 : 1024);
int i;
/* TODO: this should take ep_allocation into account */
for (i=1;i<USB_NUM_ENDPOINTS;i++) {
/* OUT */
if(endpoints[i].type[DIR_OUT] == USB_ENDPOINT_XFER_ISOC)
/* FIXME: we can adjust the number of packets per frame, currently use one */
qh_array[i*2].max_pkt_length = isopacketsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
else
qh_array[i*2].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
qh_array[i*2].dtd.next_td_ptr = QH_NEXT_TERMINATE;
/* IN */
if(endpoints[i].type[DIR_IN] == USB_ENDPOINT_XFER_ISOC)
/* FIXME: we can adjust the number of packets per frame, currently use one */
qh_array[i*2+1].max_pkt_length = isopacketsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL | 1 << QH_MULT_POS;
else
qh_array[i*2+1].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
qh_array[i*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE;
}
}
static void init_endpoints(void)
{
int ep_num;
logf("init_endpoints");
/* RX/TX from the device POV: OUT/IN, respectively */
for(ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) {
usb_endpoint_t *endpoint = &endpoints[ep_num];
/* manual: 32.9.5.18 (Caution): Leaving an unconfigured endpoint control
* will cause undefined behavior for the data pid tracking on the active
* endpoint/direction. */
if (!endpoint->allocated[DIR_OUT])
endpoint->type[DIR_OUT] = USB_ENDPOINT_XFER_BULK;
if (!endpoint->allocated[DIR_IN])
endpoint->type[DIR_IN] = USB_ENDPOINT_XFER_BULK;
REG_ENDPTCTRL(ep_num) =
EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE |
EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE |
(endpoint->type[DIR_OUT] << EPCTRL_RX_EP_TYPE_SHIFT) |
(endpoint->type[DIR_IN] << EPCTRL_TX_EP_TYPE_SHIFT);
}
}

View file

@ -59,7 +59,6 @@ struct ep_type
unsigned int size; /* length of the data buffer */
struct semaphore complete; /* wait object */
int8_t status; /* completion status (0 for success) */
bool active; /* true is endpoint has been requested (true for EP0) */
bool done; /* transfer completed */
bool busy; /* true is a transfer is pending */
};
@ -67,6 +66,16 @@ struct ep_type
static const uint8_t in_ep_list[] = {0, 1, 3, 5};
static const uint8_t out_ep_list[] = {0, 2, 4};
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS] = {
{.type = {USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_CONTROL}},
{.type = {USB_ENDPOINT_TYPE_NONE, USB_ENDPOINT_TYPE_ANY}},
{.type = {USB_ENDPOINT_TYPE_ANY, USB_ENDPOINT_TYPE_NONE}},
{.type = {USB_ENDPOINT_TYPE_NONE, USB_ENDPOINT_TYPE_ANY}},
{.type = {USB_ENDPOINT_TYPE_ANY, USB_ENDPOINT_TYPE_NONE}},
{.type = {USB_ENDPOINT_TYPE_NONE, USB_ENDPOINT_TYPE_ANY}},
};
uint8_t usb_drv_ep_specs_flags = 0;
/* state of EP0 (to correctly schedule setup packet enqueing) */
enum ep0state
{
@ -225,7 +234,6 @@ static void reset_endpoints(void)
{
int ep = ((dir == DIR_IN) ? in_ep_list : out_ep_list)[i];
struct ep_type *endpoint = &endpoints[ep][out];
endpoint->active = false;
endpoint->busy = false;
endpoint->status = -1;
endpoint->done = true;
@ -580,29 +588,19 @@ void INT_USB_FUNC(void)
GINTSTS = sts;
}
int usb_drv_request_endpoint(int type, int dir)
{
bool out = dir == USB_DIR_OUT;
for (unsigned i = 1; i < num_eps(out); i++)
{
int ep = (out ? out_ep_list : in_ep_list)[i];
bool *active = &endpoints[ep][out ? DIR_OUT : DIR_IN].active;
if(*active)
continue;
*active = true;
DEPCTL(ep, out) = (DEPCTL(ep, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp))
| DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp) | DEPCTL_usbactep;
return ep | dir;
}
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
(void)max_packet_size; /* FIXME: support max packet size override */
return -1;
int num = EP_NUM(endpoint);
int dir = EP_DIR(endpoint);
bool out = dir == DIR_OUT;
DEPCTL(num, out) = (DEPCTL(num, out) & ~(DEPCTL_eptype_bits << DEPCTL_eptype_bitp))
| DEPCTL_setd0pid | (type << DEPCTL_eptype_bitp) | DEPCTL_usbactep;
return 0;
}
void usb_drv_release_endpoint(int ep)
{
if ((ep & 0x7f) == 0)
return;
endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false;
int usb_drv_deinit_endpoint(int endpoint) {
return 0;
}
void usb_drv_cancel_all_transfers()

View file

@ -32,6 +32,7 @@
#ifdef HAVE_USBSTACK
#include "usb_ch9.h"
#include "usb_core.h"
#include "usb_drv.h"
#define TCC7xx_USB_EPIF_IRQ_MASK 0xf
@ -70,9 +71,15 @@ struct tcc_ep {
char *buf; /* user buffer to store data */
int max_len; /* how match data will fit */
int count; /* actual data count */
bool busy;
} ;
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS] = {
{.type = {USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_CONTROL}},
{.type = {USB_ENDPOINT_TYPE_NONE, USB_ENDPOINT_XFER_BULK}},
{.type = {USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_TYPE_NONE}},
};
uint8_t usb_drv_ep_specs_flags = 0;
static struct tcc_ep tcc_endpoints[] = {
/* control */
{
@ -93,46 +100,16 @@ static struct tcc_ep tcc_endpoints[] = {
static bool usb_drv_write_ep(struct tcc_ep *ep);
static void usb_set_speed(int);
int usb_drv_request_endpoint(int type, int dir)
{
int flags = disable_irq_save();
size_t ep;
int ret = 0;
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
(void)max_packet_size; /* FIXME: support max packet size override */
if (type != USB_ENDPOINT_XFER_BULK)
return -1;
if (dir == USB_DIR_IN)
ep = 1;
else
ep = 2;
if (!tcc_endpoints[ep].busy) {
tcc_endpoints[ep].busy = true;
tcc_endpoints[ep].dir = dir;
ret = ep | dir;
} else {
ret = -1;
}
restore_irq(flags);
return ret;
tcc_endpoints[EP_NUM(endpoint)].dir = EP_DIR(endpoint) == DIR_IN ? USB_DIR_IN : USB_DIR_OUT;
return 0;
}
void usb_drv_release_endpoint(int ep)
{
int flags;
ep = ep & 0x7f;
if (ep < 1 || ep > USB_NUM_ENDPOINTS)
return ;
flags = disable_irq_save();
tcc_endpoints[ep].busy = false;
tcc_endpoints[ep].dir = -1;
restore_irq(flags);
int usb_drv_deinit_endpoint(int endpoint) {
tcc_endpoints[EP_NUM(endpoint)].dir = -1;
return 0;
}
static inline void pullup_on(void)
@ -349,8 +326,6 @@ void handle_ep(unsigned short ep_irq)
if (0 == (ep_irq & (1 << endpoint)))
continue;
if (!tcc_ep->busy)
panicf_my("ep%d: wasn't requested", endpoint);
TCC7xx_USB_INDEX = endpoint;
stat = TCC7xx_USB_EP_STAT;
@ -698,7 +673,6 @@ void usb_drv_init(void)
tcc_endpoints[i].id = i;
tcc_endpoints[i].mask = 1 << i;
tcc_endpoints[i].buf = NULL;
tcc_endpoints[i].busy = false;
tcc_endpoints[i].dir = -1;
}

View file

@ -81,6 +81,13 @@ static struct usb_endpoint endpoints[] =
{ .type = ep_interrupt, .fifo_addr = USB_FIFO_EP2, .fifo_size = 64 },
};
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS] = {
{.type = {USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_CONTROL}},
{.type = {USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_BULK}},
{.type = {USB_ENDPOINT_TYPE_NONE, USB_ENDPOINT_XFER_INT}},
};
uint8_t usb_drv_ep_specs_flags = 0;
static inline void select_endpoint(int ep)
{
REG_USB_REG_INDEX = ep;
@ -829,33 +836,14 @@ void usb_drv_cancel_all_transfers(void)
restore_irq(flags);
}
void usb_drv_release_endpoint(int ep)
{
(void)ep;
logf("%s(%d, %s)", __func__, (ep & 0x7F), (ep >> 7) ? "IN" : "OUT");
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
(void)endpoint;
(void)type;
(void)max_packet_size; /* FIXME: support max packet size override */
return 0;
}
int usb_drv_request_endpoint(int type, int dir)
{
logf("%s(%d, %s)", __func__, type, (dir == USB_DIR_IN) ? "IN" : "OUT");
dir &= USB_ENDPOINT_DIR_MASK;
type &= USB_ENDPOINT_XFERTYPE_MASK;
/* There are only 3+2 endpoints, so hardcode this ... */
switch(type)
{
case USB_ENDPOINT_XFER_BULK:
if(dir == USB_DIR_IN)
return (1 | USB_DIR_IN);
else
return (1 | USB_DIR_OUT);
case USB_ENDPOINT_XFER_INT:
if(dir == USB_DIR_IN)
return (2 | USB_DIR_IN);
default:
return -1;
}
int usb_drv_deinit_endpoint(int endpoint) {
(void)endpoint;
return 0;
}

View file

@ -109,6 +109,13 @@ static struct usb_endpoint endpoints[] =
EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL),
};
struct usb_drv_ep_spec usb_drv_ep_specs[USB_NUM_ENDPOINTS] = {
{.type = {USB_ENDPOINT_XFER_CONTROL, USB_ENDPOINT_XFER_CONTROL}},
{.type = {USB_ENDPOINT_XFER_BULK, USB_ENDPOINT_XFER_BULK}},
{.type = {USB_ENDPOINT_XFER_INT, USB_ENDPOINT_XFER_INT}},
};
uint8_t usb_drv_ep_specs_flags = 0;
static inline void select_endpoint(int ep)
{
REG_USB_INDEX = ep;
@ -1185,78 +1192,28 @@ void usb_drv_cancel_all_transfers(void)
restore_irq(flags);
}
void usb_drv_release_endpoint(int ep)
{
int n = ep & 0x7f;
int usb_drv_init_endpoint(int endpoint, int type, int max_packet_size) {
(void)max_packet_size; /* FIXME: support max packet size override */
logf("%s(%d, %s)", __func__, (ep & 0x7F), (ep >> 7) ? "IN" : "OUT");
if (n)
{
int dir = ep & USB_ENDPOINT_DIR_MASK;
if(dir == USB_DIR_IN)
{
REG_USB_INTRINE &= ~USB_INTR_EP(n);
endpoints[n << 1].allocated = false;
}
else
{
REG_USB_INTROUTE &= ~USB_INTR_EP(n);
endpoints[(n << 1) + 1].allocated = false;
}
}
int num = EP_NUM(endpoint);
int dir = EP_DIR(endpoint);
int index = num * 2 + (dir == DIR_OUT ? 1 : 0);
endpoints[index].allocated = true;
if(dir == DIR_IN)
REG_USB_INTRINE |= USB_INTR_EP(num);
else
REG_USB_INTROUTE |= USB_INTR_EP(num);
return 0;
}
int usb_drv_request_endpoint(int type, int dir)
{
logf("%s(%d, %s)", __func__, type, (dir == USB_DIR_IN) ? "IN" : "OUT");
dir &= USB_ENDPOINT_DIR_MASK;
type &= USB_ENDPOINT_XFERTYPE_MASK;
/* There are only 3+2 endpoints, so hardcode this ... */
switch(type)
{
case USB_ENDPOINT_XFER_BULK:
if(dir == USB_DIR_IN)
{
if (endpoints[2].allocated)
break;
endpoints[2].allocated = true;
REG_USB_INTRINE |= USB_INTR_EP(1);
return (1 | USB_DIR_IN);
}
else
{
if (endpoints[3].allocated)
break;
endpoints[3].allocated = true;
REG_USB_INTROUTE |= USB_INTR_EP(1);
return (1 | USB_DIR_OUT);
}
case USB_ENDPOINT_XFER_INT:
if(dir == USB_DIR_IN)
{
if (endpoints[4].allocated)
break;
endpoints[4].allocated = true;
REG_USB_INTRINE |= USB_INTR_EP(2);
return (2 | USB_DIR_IN);
}
else
{
if (endpoints[5].allocated)
break;
endpoints[5].allocated = true;
REG_USB_INTROUTE |= USB_INTR_EP(2);
return (2 | USB_DIR_OUT);
}
default:
break;
}
return -1;
int usb_drv_deinit_endpoint(int endpoint) {
int num = EP_NUM(endpoint);
int dir = EP_DIR(endpoint);
int index = num * 2 + (dir == DIR_OUT ? 1 : 0);
endpoints[index].allocated = false;
if(dir == DIR_IN)
REG_USB_INTRINE &= ~USB_INTR_EP(num);
else
REG_USB_INTROUTE &= ~USB_INTR_EP(num);
return 0;
}

View file

@ -297,8 +297,15 @@ static int usb_as_playback_intf_alt; /* playback streaming interface alternate s
static int as_playback_freq_idx; /* audio playback streaming frequency index (in hw_freq_sampr) */
static int out_iso_ep_adr; /* output isochronous endpoint */
static int in_iso_feedback_ep_adr; /* input feedback isochronous endpoint */
struct usb_class_driver_ep_allocation usb_audio_ep_allocs[2] = {
/* output isochronous endpoint */
{.type = USB_ENDPOINT_XFER_ISOC, .dir = DIR_OUT, .optional = false},
/* input feedback isochronous endpoint */
{.type = USB_ENDPOINT_XFER_ISOC, .dir = DIR_IN, .optional = false},
};
#define EP_ISO_OUT (usb_audio_ep_allocs[0].ep)
#define EP_ISO_FEEDBACK_IN (usb_audio_ep_allocs[1].ep)
/* small buffer used for control transfers */
static unsigned char usb_buffer[128] USB_DEVBSS_ATTR;
@ -561,47 +568,14 @@ void usb_audio_free_buf(void)
dsp_buf = NULL;
}
int usb_audio_request_endpoints(struct usb_class_driver *drv)
{
// make sure we can get the buffers first...
// return -1 if the allocation _failed_
if (usb_audio_request_buf())
return -1;
out_iso_ep_adr = usb_core_request_endpoint(USB_ENDPOINT_XFER_ISOC, USB_DIR_OUT, drv);
if(out_iso_ep_adr < 0)
{
logf("usbaudio: cannot get an out iso endpoint");
return -1;
}
in_iso_feedback_ep_adr = usb_core_request_endpoint(USB_ENDPOINT_XFER_ISOC, USB_DIR_IN, drv);
if(in_iso_feedback_ep_adr < 0)
{
usb_core_release_endpoint(out_iso_ep_adr);
logf("usbaudio: cannot get an in iso endpoint");
return -1;
}
logf("usbaudio: iso out ep is 0x%x, in ep is 0x%x", out_iso_ep_adr, in_iso_feedback_ep_adr);
as_iso_audio_out_ep.bEndpointAddress = out_iso_ep_adr;
as_iso_audio_out_ep.bSynchAddress = in_iso_feedback_ep_adr;
as_iso_synch_in_ep.bEndpointAddress = in_iso_feedback_ep_adr;
as_iso_synch_in_ep.bSynchAddress = 0;
return 0;
}
unsigned int usb_audio_get_out_ep(void)
{
return out_iso_ep_adr;
return EP_ISO_OUT;
}
unsigned int usb_audio_get_in_ep(void)
{
return in_iso_feedback_ep_adr;
return EP_ISO_FEEDBACK_IN;
}
int usb_audio_set_first_interface(int interface)
@ -638,6 +612,10 @@ int usb_audio_get_config_descriptor(unsigned char *dest, int max_packet_size)
/* endpoints */
as_iso_audio_out_ep.wMaxPacketSize = 1023;
as_iso_audio_out_ep.bEndpointAddress = EP_ISO_OUT;
as_iso_audio_out_ep.bSynchAddress = EP_ISO_FEEDBACK_IN;
as_iso_synch_in_ep.bEndpointAddress = EP_ISO_FEEDBACK_IN;
as_iso_synch_in_ep.bSynchAddress = 0;
/** Endpoint Interval calculation:
* typically sampling frequency is 44100 Hz and top is 192000 Hz, which
@ -691,7 +669,7 @@ static void playback_audio_get_more(const void **start, size_t *size)
{
logf("usbaudio: recover usb rx overflow");
usb_rx_overflow = false;
usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer, BUFFER_SIZE);
usb_drv_recv_nonblocking(EP_ISO_OUT, rx_buffer, BUFFER_SIZE);
}
restore_irq(oldlevel);
}
@ -731,7 +709,7 @@ static void usb_audio_start_playback(void)
pcm_apply_settings();
mixer_channel_set_amplitude(PCM_MIXER_CHAN_USBAUDIO, MIX_AMP_UNITY);
usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer, BUFFER_SIZE);
usb_drv_recv_nonblocking(EP_ISO_OUT, rx_buffer, BUFFER_SIZE);
}
static void usb_audio_stop_playback(void)
@ -883,7 +861,7 @@ static bool usb_audio_endpoint_request(struct usb_ctrlrequest* req, void *reqdat
{
int ep = req->wIndex & 0xff;
if(ep == out_iso_ep_adr)
if(ep == EP_ISO_OUT)
return usb_audio_as_ctrldata_endpoint_request(req, reqdata);
else
{
@ -1184,6 +1162,11 @@ void usb_audio_init_connection(void)
{
logf("usbaudio: init connection");
// make sure we can get the buffers first...
// TODO: disable this driver when failed
if (usb_audio_request_buf())
return;
usbaudio_active = true;
dsp = dsp_get_config(CODEC_IDX_AUDIO);
dsp_configure(dsp, DSP_RESET, 0);
@ -1204,6 +1187,9 @@ void usb_audio_disconnect(void)
{
logf("usbaudio: disconnect");
if(!usbaudio_active)
return;
usb_audio_stop_playback();
usb_audio_free_buf();
usbaudio_active = false;
@ -1289,7 +1275,7 @@ bool usb_audio_fast_transfer_complete(int ep, int dir, int status, int length)
(void) dir;
bool retval = false;
if(ep == out_iso_ep_adr && usb_as_playback_intf_alt == 1)
if(ep == EP_ISO_OUT && usb_as_playback_intf_alt == 1)
{
// check for dropped frames
if (last_frame != usb_drv_get_frame_number())
@ -1340,7 +1326,7 @@ bool usb_audio_fast_transfer_complete(int ep, int dir, int status, int length)
if(rx_usb_idx != rx_play_idx)
{
logf("usbaudio: new transaction");
usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer, BUFFER_SIZE);
usb_drv_recv_nonblocking(EP_ISO_OUT, rx_buffer, BUFFER_SIZE);
}
else
{
@ -1399,7 +1385,7 @@ bool usb_audio_fast_transfer_complete(int ep, int dir, int status, int length)
encodeFBfixedpt(sendFf, samples_fb, usb_drv_port_speed());
logf("usbaudio: frame %d fbval 0x%02X%02X%02X%02X", usb_drv_get_frame_number(), sendFf[3], sendFf[2], sendFf[1], sendFf[0]);
usb_drv_send_nonblocking(in_iso_feedback_ep_adr, sendFf, usb_drv_port_speed()?4:3);
usb_drv_send_nonblocking(EP_ISO_FEEDBACK_IN, sendFf, usb_drv_port_speed()?4:3);
// debug screen counters
//

View file

@ -30,20 +30,7 @@
* Relevant specifications are USB 2.0 and USB Audio Class 1.0.
*/
/*
* usb_audio_request_endpoints():
*
* Calls usb_core_request_endpoint() to request one IN and one OUT
* isochronous endpoint.
*
* Called by allocate_interfaces_and_endpoints().
*
* Returns -1 if either request fails, returns 0 if success.
*
* Also requests buffer allocations. If allocation fails,
* returns -1 so that the driver will be disabled by the USB core.
*/
int usb_audio_request_endpoints(struct usb_class_driver *);
extern struct usb_class_driver_ep_allocation usb_audio_ep_allocs[2];
/*
* usb_audio_set_first_interface():

View file

@ -46,12 +46,6 @@ static struct usb_interface_descriptor __attribute__((aligned(2)))
static int usb_interface;
int usb_charging_only_request_endpoints(struct usb_class_driver *drv)
{
(void) drv;
return 0;
}
int usb_charging_only_set_first_interface(int interface)
{
usb_interface = interface;

View file

@ -24,7 +24,6 @@
#include "usb_ch9.h"
void usb_charging_only_init(void);
int usb_charging_only_request_endpoints(struct usb_class_driver *);
int usb_charging_only_set_first_interface(int interface);
int usb_charging_only_get_config_descriptor(unsigned char *dest,int max_packet_size);
bool usb_charging_only_control_request(struct usb_ctrlrequest* req);

View file

@ -29,6 +29,13 @@
/* Common api, implemented by all class drivers */
struct usb_class_driver_ep_allocation {
uint8_t type; /* by driver, required ep type. USB_ENDPOINT_XFER_* */
uint8_t dir; /* by driver, required ep dir. DIR_{IN,OUT} */
uint8_t ep; /* by core, allocated ep. > 0 are valid but can be 0 if optional==true */
bool optional; /* by driver, set true to mark this requirement to be optional */
};
struct usb_class_driver {
/* First some runtime data */
bool enabled;
@ -40,8 +47,9 @@ struct usb_class_driver {
/* Set this to true if the driver needs exclusive disk access (e.g. usb storage) */
bool needs_exclusive_storage;
/* Let the driver request endpoints it need. Returns zero on success */
int (*request_endpoints)(struct usb_class_driver *);
/* Endpoint allocation state table */
uint8_t ep_allocs_size;
struct usb_class_driver_ep_allocation* ep_allocs;
/* Tells the driver what its first interface number will be. The driver
returns the number of the first available interface for the next driver

View file

@ -183,6 +183,13 @@ static struct
struct usb_transfer_completion_event_data completion_event[2];
} ep_data[USB_NUM_ENDPOINTS];
struct ep_alloc_state {
int8_t type[2];
struct usb_class_driver* owner[2];
};
static struct ep_alloc_state ep_alloc_states[1][USB_NUM_ENDPOINTS];
static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
{
#ifdef USB_ENABLE_STORAGE
@ -191,7 +198,8 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
.needs_exclusive_storage = true,
.first_interface = 0,
.last_interface = 0,
.request_endpoints = usb_storage_request_endpoints,
.ep_allocs_size = ARRAYLEN(usb_storage_ep_allocs),
.ep_allocs = usb_storage_ep_allocs,
.set_first_interface = usb_storage_set_first_interface,
.get_config_descriptor = usb_storage_get_config_descriptor,
.init_connection = usb_storage_init_connection,
@ -210,7 +218,8 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
.needs_exclusive_storage = false,
.first_interface = 0,
.last_interface = 0,
.request_endpoints = usb_serial_request_endpoints,
.ep_allocs_size = ARRAYLEN(usb_serial_ep_allocs),
.ep_allocs = usb_serial_ep_allocs,
.set_first_interface = usb_serial_set_first_interface,
.get_config_descriptor = usb_serial_get_config_descriptor,
.init_connection = usb_serial_init_connection,
@ -229,7 +238,8 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
.needs_exclusive_storage = false,
.first_interface = 0,
.last_interface = 0,
.request_endpoints = usb_charging_only_request_endpoints,
.ep_allocs_size = 0,
.ep_allocs = NULL,
.set_first_interface = usb_charging_only_set_first_interface,
.get_config_descriptor = usb_charging_only_get_config_descriptor,
.init_connection = NULL,
@ -248,7 +258,8 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
.needs_exclusive_storage = false,
.first_interface = 0,
.last_interface = 0,
.request_endpoints = usb_hid_request_endpoints,
.ep_allocs_size = ARRAYLEN(usb_hid_ep_allocs),
.ep_allocs = usb_hid_ep_allocs,
.set_first_interface = usb_hid_set_first_interface,
.get_config_descriptor = usb_hid_get_config_descriptor,
.init_connection = usb_hid_init_connection,
@ -267,7 +278,8 @@ static struct usb_class_driver drivers[USB_NUM_DRIVERS] =
.needs_exclusive_storage = false,
.first_interface = 0,
.last_interface = 0,
.request_endpoints = usb_audio_request_endpoints,
.ep_allocs_size = ARRAYLEN(usb_audio_ep_allocs),
.ep_allocs = usb_audio_ep_allocs,
.set_first_interface = usb_audio_set_first_interface,
.get_config_descriptor = usb_audio_get_config_descriptor,
.init_connection = usb_audio_init_connection,
@ -459,6 +471,9 @@ void usb_core_init(void)
if(drivers[i].init != NULL)
drivers[i].init();
/* clear endpoint allocation state */
memset(ep_alloc_states, 0, sizeof(ep_alloc_states));
initialized = true;
usb_state = DEFAULT;
#ifdef HAVE_USB_CHARGING_ENABLE
@ -558,63 +573,99 @@ static void usb_core_set_serial_function_id(void)
usb_string_iSerial.wString[0] = hex[id];
}
int usb_core_request_endpoint(int type, int dir, struct usb_class_driver* drv)
{
int ret, ep;
ret = usb_drv_request_endpoint(type, dir);
if(ret == -1)
return -1;
dir = EP_DIR(ret);
ep = EP_NUM(ret);
ep_data[ep].completion_handler[dir] = drv->transfer_complete;
ep_data[ep].fast_completion_handler[dir] = drv->fast_transfer_complete;
ep_data[ep].control_handler[dir] = drv->control_request;
return ret;
}
void usb_core_release_endpoint(int ep)
{
int dir;
usb_drv_release_endpoint(ep);
dir = EP_DIR(ep);
ep = EP_NUM(ep);
ep_data[ep].completion_handler[dir] = NULL;
ep_data[ep].control_handler[dir] = NULL;
}
static void allocate_interfaces_and_endpoints(void)
{
int i;
int interface = 0;
memset(ep_data, 0, sizeof(ep_data));
for(i = 0; i < USB_NUM_ENDPOINTS; i++) {
usb_drv_release_endpoint(i | USB_DIR_OUT);
usb_drv_release_endpoint(i | USB_DIR_IN);
}
for(i = 0; i < USB_NUM_DRIVERS; i++) {
if(drivers[i].enabled) {
drivers[i].first_interface = interface;
if(drivers[i].request_endpoints(&drivers[i])) {
drivers[i].enabled = false;
continue;
/* deinit previously allocated endpoints */
for(int conf = 0; conf < 1; conf += 1) {
for(int epnum = 0; epnum < USB_NUM_ENDPOINTS; epnum += 1) {
for(int dir = 0; dir < 2; dir += 1) {
struct ep_alloc_state* alloc = &ep_alloc_states[0][epnum];
if(alloc->owner[dir] != NULL) {
int ep = epnum | (dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
usb_drv_deinit_endpoint(ep);
alloc->owner[dir] = NULL;
}
}
interface = drivers[i].set_first_interface(interface);
drivers[i].last_interface = interface;
}
}
for(int i = 0; i < USB_NUM_DRIVERS; i++) {
struct usb_class_driver* driver = &drivers[i];
if(!driver->enabled) {
continue;
}
/* assign endpoints */
for(int reqnum = 0; reqnum < driver->ep_allocs_size; reqnum += 1) {
/* find matching ep */
struct usb_class_driver_ep_allocation* req = &driver->ep_allocs[reqnum];
req->ep = 0;
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 */
struct ep_alloc_state* alloc = &ep_alloc_states[0][epnum];
if(alloc->owner[req->dir] != NULL) {
continue;
}
/* this ep's requested direction is free */
/* another checks */
if(usb_drv_ep_specs_flags & USB_ENDPOINT_SPEC_IO_EXCLUSIVE) {
/* check for the other direction type */
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 */
const int ep = epnum | (req->dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
req->ep = ep;
alloc->owner[req->dir] = driver;
alloc->type[req->dir] = req->type;
break;
}
if(req->ep == 0 && !req->optional) {
/* no matching ep found, disable the driver */
driver->enabled = false;
/* also revert all allocations for this driver */
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[0][epnum].owner[dir] = NULL;
}
break;
}
}
if(!driver->enabled) {
continue;
}
/* assign interfaces */
driver->first_interface = interface;
interface = driver->set_first_interface(interface);
driver->last_interface = interface;
}
usb_core_num_interfaces = interface;
}
@ -778,6 +829,35 @@ static void usb_core_do_set_addr(uint8_t address)
static void usb_core_do_set_config(uint8_t config)
{
logf("usb_core: SET_CONFIG %d",config);
/* (de)initialize allocated endpoints */
const bool init = usb_state == ADDRESS && config;
const bool deinit = usb_state == CONFIGURED && !config;
if(init || deinit) {
memset(ep_data, 0, sizeof(ep_data));
for(int epnum = 0; epnum < USB_NUM_ENDPOINTS; epnum += 1) {
for(int dir = 0; dir < 2; dir += 1) {
struct ep_alloc_state* alloc = &ep_alloc_states[0][epnum];
if(alloc->owner[dir] == NULL) {
continue;
}
int ep = epnum | (dir == DIR_OUT ? USB_DIR_OUT : USB_DIR_IN);
int ret = init ?
usb_drv_init_endpoint(ep, alloc->type[dir], -1) :
usb_drv_deinit_endpoint(ep);
if(ret) {
logf("usb_core: usb_drv_%s_endpoint failed ep=%d dir=%e", init ? "init" : "deinit", epnum, dir);
continue;
}
if(init) {
ep_data[epnum].completion_handler[dir] = alloc->owner[dir]->transfer_complete;
ep_data[epnum].fast_completion_handler[dir] = alloc->owner[dir]->fast_transfer_complete;
ep_data[epnum].control_handler[dir] = alloc->owner[dir]->control_request;
}
}
}
}
if(config) {
usb_state = CONFIGURED;

View file

@ -186,9 +186,14 @@ static int cur_buf_send;
static bool active = false;
static bool currently_sending = false;
static int ep_in;
static int usb_interface;
struct usb_class_driver_ep_allocation usb_hid_ep_allocs[1] = {
{.type = USB_ENDPOINT_XFER_INT, .dir = DIR_IN, .optional = false},
};
#define EP_IN (usb_hid_ep_allocs[0].ep)
static void usb_hid_try_send_drv(void);
static void pack_parameter(unsigned char **dest, bool is_signed, bool mark_size,
@ -235,15 +240,6 @@ static void pack_parameter(unsigned char **dest, bool is_signed, bool mark_size,
}
}
int usb_hid_request_endpoints(struct usb_class_driver *drv)
{
ep_in = usb_core_request_endpoint(USB_ENDPOINT_XFER_INT, USB_DIR_IN, drv);
if (ep_in < 0)
return -1;
return 0;
}
int usb_hid_set_first_interface(int interface)
{
usb_interface = interface;
@ -608,7 +604,7 @@ int usb_hid_get_config_descriptor(unsigned char *dest, int max_packet_size)
/* Endpoint descriptor */
endpoint_descriptor.wMaxPacketSize = 8;
endpoint_descriptor.bInterval = 8;
endpoint_descriptor.bEndpointAddress = ep_in;
endpoint_descriptor.bEndpointAddress = EP_IN;
PACK_DATA(&dest, endpoint_descriptor);
return (int)(dest - orig_dest);
@ -832,7 +828,7 @@ static void usb_hid_try_send_drv(void)
}
logf("HID: Sending %d bytes",length);
rc = usb_drv_send_nonblocking(ep_in, send_buffer[cur_buf_send], length);
rc = usb_drv_send_nonblocking(EP_IN, send_buffer[cur_buf_send], length);
currently_sending = true;
if (rc)
send_buffer_len[cur_buf_send] = 0;

View file

@ -21,11 +21,12 @@
#ifndef USB_HID_H
#define USB_HID_H
#include "usb_ch9.h"
#include "usb_core.h"
#include "usb_class_driver.h"
#include "usb_hid_usage_tables.h"
int usb_hid_request_endpoints(struct usb_class_driver *drv);
extern struct usb_class_driver_ep_allocation usb_hid_ep_allocs[1];
int usb_hid_set_first_interface(int interface);
int usb_hid_get_config_descriptor(unsigned char *dest, int max_packet_size);
void usb_hid_init_connection(void);

View file

@ -206,32 +206,18 @@ static int buffer_length;
static int buffer_transitlength;
static bool active = false;
static int ep_in, ep_out, ep_int;
struct usb_class_driver_ep_allocation usb_serial_ep_allocs[3] = {
{.type = USB_ENDPOINT_XFER_BULK, .dir = DIR_IN, .optional = false},
{.type = USB_ENDPOINT_XFER_BULK, .dir = DIR_OUT, .optional = false},
{.type = USB_ENDPOINT_XFER_INT, .dir = DIR_IN, .optional = true},
};
#define EP_IN (usb_serial_ep_allocs[0].ep)
#define EP_OUT (usb_serial_ep_allocs[1].ep)
#define EP_INT (usb_serial_ep_allocs[2].ep)
static int control_interface, data_interface;
int usb_serial_request_endpoints(struct usb_class_driver *drv)
{
ep_in = usb_core_request_endpoint(USB_ENDPOINT_XFER_BULK, USB_DIR_IN, drv);
if (ep_in < 0)
return -1;
ep_out = usb_core_request_endpoint(USB_ENDPOINT_XFER_BULK, USB_DIR_OUT,
drv);
if (ep_out < 0) {
usb_core_release_endpoint(ep_in);
return -1;
}
/* Optional interrupt endpoint. While the code does not actively use it,
* it is needed to get out-of-the-box serial port experience on Windows
* and Linux. If this endpoint is not available, only CDC Data interface
* will be exported (can still work on Linux with manual modprobe).
*/
ep_int = usb_core_request_endpoint(USB_ENDPOINT_XFER_INT, USB_DIR_IN, drv);
return 0;
}
int usb_serial_set_first_interface(int interface)
{
control_interface = interface;
@ -250,7 +236,7 @@ int usb_serial_get_config_descriptor(unsigned char *dest, int max_packet_size)
union_descriptor.bSubordinateInterface0 = data_interface;
data_interface_descriptor.bInterfaceNumber = data_interface;
if (ep_int > 0)
if (EP_INT > 0)
{
PACK_DATA(&dest, association_descriptor);
PACK_DATA(&dest, control_interface_descriptor);
@ -263,7 +249,7 @@ int usb_serial_get_config_descriptor(unsigned char *dest, int max_packet_size)
* both on Full and High speed. Note that max_packet_size is for bulk.
* Maximum bInterval for High Speed is 16 and for Full Speed is 255.
*/
endpoint_descriptor.bEndpointAddress = ep_int;
endpoint_descriptor.bEndpointAddress = EP_INT;
endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_INT;
endpoint_descriptor.wMaxPacketSize = 64;
endpoint_descriptor.bInterval = 16;
@ -271,13 +257,13 @@ int usb_serial_get_config_descriptor(unsigned char *dest, int max_packet_size)
}
PACK_DATA(&dest, data_interface_descriptor);
endpoint_descriptor.bEndpointAddress = ep_in;
endpoint_descriptor.bEndpointAddress = EP_IN;
endpoint_descriptor.bmAttributes = USB_ENDPOINT_XFER_BULK;
endpoint_descriptor.wMaxPacketSize = max_packet_size;
endpoint_descriptor.bInterval = 0;
PACK_DATA(&dest, endpoint_descriptor);
endpoint_descriptor.bEndpointAddress = ep_out;
endpoint_descriptor.bEndpointAddress = EP_OUT;
PACK_DATA(&dest, endpoint_descriptor);
return (dest - orig_dest);
@ -346,7 +332,7 @@ bool usb_serial_control_request(struct usb_ctrlrequest* req, void* reqdata, unsi
void usb_serial_init_connection(void)
{
/* prime rx endpoint */
usb_drv_recv_nonblocking(ep_out, receive_buffer, RECV_BUFFER_SIZE);
usb_drv_recv_nonblocking(EP_OUT, receive_buffer, RECV_BUFFER_SIZE);
/* we come here too after a bus reset, so reset some data */
buffer_transitlength = 0;
@ -379,7 +365,7 @@ static void sendout(void)
buffer_transitlength = MIN(buffer_transitlength,TRANSIT_BUFFER_SIZE);
buffer_length -= buffer_transitlength;
memcpy(transit_buffer,&send_buffer[buffer_start],buffer_transitlength);
usb_drv_send_nonblocking(ep_in,transit_buffer,buffer_transitlength);
usb_drv_send_nonblocking(EP_IN,transit_buffer,buffer_transitlength);
}
}
@ -437,7 +423,7 @@ void usb_serial_transfer_complete(int ep,int dir, int status, int length)
/* Data received. TODO : Do something with it ? */
/* Get the next bit */
usb_drv_recv_nonblocking(ep_out, receive_buffer, RECV_BUFFER_SIZE);
usb_drv_recv_nonblocking(EP_OUT, receive_buffer, RECV_BUFFER_SIZE);
break;
case USB_DIR_IN:

View file

@ -21,9 +21,10 @@
#ifndef USB_SERIAL_H
#define USB_SERIAL_H
#include "usb_ch9.h"
#include "usb_class_driver.h"
extern struct usb_class_driver_ep_allocation usb_serial_ep_allocs[3];
int usb_serial_request_endpoints(struct usb_class_driver *);
int usb_serial_set_first_interface(int interface);
int usb_serial_get_config_descriptor(unsigned char *dest,int max_packet_size);
void usb_serial_init_connection(void);

View file

@ -321,7 +321,14 @@ static bool ejected[NUM_DRIVES];
static bool locked[NUM_DRIVES];
static int usb_interface;
static int ep_in, ep_out;
struct usb_class_driver_ep_allocation usb_storage_ep_allocs[2] = {
{.type = USB_ENDPOINT_XFER_BULK, .dir = DIR_IN, .optional = false},
{.type = USB_ENDPOINT_XFER_BULK, .dir = DIR_OUT, .optional = false},
};
#define EP_IN (usb_storage_ep_allocs[0].ep)
#define EP_OUT (usb_storage_ep_allocs[1].ep)
#if defined(HAVE_MULTIDRIVE)
static bool skip_first = 0;
@ -399,24 +406,6 @@ void usb_storage_init(void)
logf("usb_storage_init done");
}
int usb_storage_request_endpoints(struct usb_class_driver *drv)
{
ep_in = usb_core_request_endpoint(USB_ENDPOINT_XFER_BULK, USB_DIR_IN, drv);
if(ep_in<0)
return -1;
ep_out = usb_core_request_endpoint(USB_ENDPOINT_XFER_BULK, USB_DIR_OUT,
drv);
if(ep_out<0) {
usb_core_release_endpoint(ep_in);
return -1;
}
return 0;
}
int usb_storage_set_first_interface(int interface)
{
usb_interface = interface;
@ -432,10 +421,10 @@ int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size)
endpoint_descriptor.wMaxPacketSize = max_packet_size;
endpoint_descriptor.bEndpointAddress = ep_in;
endpoint_descriptor.bEndpointAddress = EP_IN;
PACK_DATA(&dest, endpoint_descriptor);
endpoint_descriptor.bEndpointAddress = ep_out;
endpoint_descriptor.bEndpointAddress = EP_OUT;
PACK_DATA(&dest, endpoint_descriptor);
return (dest - orig_dest);
@ -486,7 +475,7 @@ void usb_storage_init_connection(void)
ramdisk_buffer = tb.transfer_buffer + ALLOCATE_BUFFER_SIZE;
#endif
#endif
usb_drv_recv_nonblocking(ep_out, cbw_buffer, MAX_CBW_SIZE);
usb_drv_recv_nonblocking(EP_OUT, cbw_buffer, MAX_CBW_SIZE);
int i;
for(i=0;i<storage_num_drives();i++) {
@ -731,8 +720,8 @@ bool usb_storage_control_request(struct usb_ctrlrequest* req, void* reqdata, uns
data toggle bits and endpoint STALL conditions despite
the Bulk-Only Mass Storage Reset. */
#if 0
usb_drv_reset_endpoint(ep_in, false);
usb_drv_reset_endpoint(ep_out, true);
usb_drv_reset_endpoint(EP_IN, false);
usb_drv_reset_endpoint(EP_OUT, true);
#endif
usb_drv_control_response(USB_CONTROL_ACK, NULL, 0);
handled = true;
@ -789,8 +778,8 @@ static void handle_scsi(struct command_block_wrapper* cbw)
if(letoh32(cbw->signature) != CBW_SIGNATURE) {
logf("ums: bad cbw signature (%x)", cbw->signature);
usb_drv_stall(ep_in, true,true);
usb_drv_stall(ep_out, true,false);
usb_drv_stall(EP_IN, true,true);
usb_drv_stall(EP_OUT, true,false);
return;
}
/* Clear the signature to prevent possible bugs elsewhere
@ -1407,33 +1396,33 @@ static void handle_scsi(struct command_block_wrapper* cbw)
static void send_block_data(void *data,int size)
{
usb_drv_send_nonblocking(ep_in, data,size);
usb_drv_send_nonblocking(EP_IN, data,size);
state = SENDING_BLOCKS;
}
static void send_command_result(void *data,int size)
{
usb_drv_send_nonblocking(ep_in, data,size);
usb_drv_send_nonblocking(EP_IN, data,size);
state = SENDING_RESULT;
}
static void send_command_failed_result(void)
{
usb_drv_send_nonblocking(ep_in, NULL, 0);
usb_drv_send_nonblocking(EP_IN, NULL, 0);
state = SENDING_FAILED_RESULT;
}
#if CONFIG_RTC
static void receive_time(void)
{
usb_drv_recv_nonblocking(ep_out, tb.transfer_buffer, 12);
usb_drv_recv_nonblocking(EP_OUT, tb.transfer_buffer, 12);
state = RECEIVING_TIME;
}
#endif /* CONFIG_RTC */
static void receive_block_data(void *data,int size)
{
usb_drv_recv_nonblocking(ep_out, data, size);
usb_drv_recv_nonblocking(EP_OUT, data, size);
state = RECEIVING_BLOCKS;
}
@ -1444,12 +1433,12 @@ static void send_csw(int status)
tb.csw->data_residue = 0;
tb.csw->status = status;
usb_drv_send_nonblocking(ep_in, tb.csw,
usb_drv_send_nonblocking(EP_IN, tb.csw,
sizeof(struct command_status_wrapper));
state = WAITING_FOR_CSW_COMPLETION_OR_COMMAND;
//logf("CSW: %X",status);
/* Already start waiting for the next command */
usb_drv_recv_nonblocking(ep_out, cbw_buffer, MAX_CBW_SIZE);
usb_drv_recv_nonblocking(EP_OUT, cbw_buffer, MAX_CBW_SIZE);
/* The next completed transfer will be either the CSW one
* or the new command */

View file

@ -21,9 +21,10 @@
#ifndef USB_STORAGE_H
#define USB_STORAGE_H
#include "usb_ch9.h"
#include "usb_class_driver.h"
extern struct usb_class_driver_ep_allocation usb_storage_ep_allocs[2];
int usb_storage_request_endpoints(struct usb_class_driver *);
int usb_storage_set_first_interface(int interface);
int usb_storage_get_config_descriptor(unsigned char *dest,int max_packet_size);
void usb_storage_init_connection(void);