mirror of
https://github.com/Rockbox/rockbox.git
synced 2026-04-12 00:47:49 -04:00
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:
parent
f13f80c506
commit
350a2250b1
27 changed files with 579 additions and 714 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue