mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 20:55:17 -05:00
as3525v2-usb: define number of enpoints correctly, write interrupt handler
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27098 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
58ad1e7c4b
commit
237d9666cc
3 changed files with 157 additions and 118 deletions
|
|
@ -34,4 +34,10 @@
|
||||||
|
|
||||||
#define CGU_SDSLOT (*(volatile unsigned long *)(CGU_BASE + 0x3C))
|
#define CGU_SDSLOT (*(volatile unsigned long *)(CGU_BASE + 0x3C))
|
||||||
|
|
||||||
|
#ifdef USB_NUM_ENDPOINTS
|
||||||
|
#undef USB_NUM_ENDPOINTS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define USB_NUM_ENDPOINTS 6
|
||||||
|
|
||||||
#endif /* __AS3525V2_H__ */
|
#endif /* __AS3525V2_H__ */
|
||||||
|
|
|
||||||
|
|
@ -38,32 +38,38 @@
|
||||||
|
|
||||||
static int __in_ep_list[NUM_IN_EP] = {IN_EP_LIST};
|
static int __in_ep_list[NUM_IN_EP] = {IN_EP_LIST};
|
||||||
static int __out_ep_list[NUM_OUT_EP] = {OUT_EP_LIST};
|
static int __out_ep_list[NUM_OUT_EP] = {OUT_EP_LIST};
|
||||||
|
static int __in_ep_list_ep0[NUM_IN_EP + 1] = {0, IN_EP_LIST};
|
||||||
|
static int __out_ep_list_ep0[NUM_OUT_EP + 1] = {0, OUT_EP_LIST};
|
||||||
|
|
||||||
/* iterate through each in/out ep except EP0
|
/* iterate through each in/out ep except EP0
|
||||||
* 'counter' is the counter, 'ep' is the actual value */
|
* 'counter' is the counter, 'ep' is the actual value */
|
||||||
#define FOR_EACH_IN_EP(counter, ep) \
|
#define FOR_EACH_IN_EP(counter, ep) \
|
||||||
for(counter = 0, ep = __in_ep_list[0]; counter < NUM_IN_EP; counter++, ep = __in_ep_list[counter])
|
for(counter = 0, ep = __in_ep_list[0]; counter < NUM_IN_EP; counter++, ep = __in_ep_list[counter])
|
||||||
|
|
||||||
|
#define FOR_EACH_IN_EP_AND_EP0(counter, ep) \
|
||||||
|
for(counter = 0, ep = __in_ep_list_ep0[0]; counter <= NUM_IN_EP; counter++, ep = __in_ep_list_ep0[counter])
|
||||||
|
|
||||||
#define FOR_EACH_OUT_EP(counter, ep) \
|
#define FOR_EACH_OUT_EP(counter, ep) \
|
||||||
for(counter = 0, ep = __out_ep_list[0]; counter < NUM_OUT_EP; counter++, ep = __out_ep_list[counter])
|
for(counter = 0, ep = __out_ep_list[0]; counter < NUM_OUT_EP; counter++, ep = __out_ep_list[counter])
|
||||||
|
|
||||||
|
#define FOR_EACH_OUT_EP_AND_EP0(counter, ep) \
|
||||||
|
for(counter = 0, ep = __out_ep_list_ep0[0]; counter <= NUM_OUT_EP; counter++, ep = __out_ep_list_ep0[counter])
|
||||||
|
|
||||||
struct usb_endpoint
|
struct usb_endpoint
|
||||||
{
|
{
|
||||||
void *buf;
|
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
union
|
|
||||||
{
|
|
||||||
unsigned int sent;
|
|
||||||
unsigned int received;
|
|
||||||
};
|
|
||||||
bool wait;
|
bool wait;
|
||||||
bool busy;
|
bool busy;
|
||||||
|
bool done;
|
||||||
|
int status;
|
||||||
|
struct wakeup complete;
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 0
|
/* NOTE: the following structure is not used to EP0
|
||||||
static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS*2];
|
* and make the assumption that each endpoint is
|
||||||
#endif
|
* either IN or OUT but not bidirectional */
|
||||||
static struct usb_ctrlrequest ep0_setup_pkt __attribute__((aligned(16)));
|
static struct usb_endpoint endpoints[USB_NUM_ENDPOINTS];
|
||||||
|
static struct usb_ctrlrequest ep0_setup_pkt USB_DEVBSS_ATTR;
|
||||||
|
|
||||||
void usb_attach(void)
|
void usb_attach(void)
|
||||||
{
|
{
|
||||||
|
|
@ -175,10 +181,9 @@ static void reset_endpoints(void)
|
||||||
/* Setup EP0 OUT with the following parameters:
|
/* Setup EP0 OUT with the following parameters:
|
||||||
* packet count = 1
|
* packet count = 1
|
||||||
* setup packet count = 1
|
* setup packet count = 1
|
||||||
* transfer size = 64
|
* transfer size = 8 (setup packet)
|
||||||
* Setup EP0 IN/OUT with 64 byte maximum packet size and activate both. Enable transfer on EP0 OUT
|
* Setup EP0 IN/OUT with 64 byte maximum packet size and activate both. Enable transfer on EP0 OUT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp)
|
DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp)
|
||||||
| (1 << DEPTSIZ0_pkcnt_bitp)
|
| (1 << DEPTSIZ0_pkcnt_bitp)
|
||||||
| 8;
|
| 8;
|
||||||
|
|
@ -305,10 +310,8 @@ static void core_dev_init(void)
|
||||||
|
|
||||||
/* Setup interrupt masks for endpoints */
|
/* Setup interrupt masks for endpoints */
|
||||||
/* Setup interrupt masks */
|
/* Setup interrupt masks */
|
||||||
DOEPMSK = DOEPINT_setup | DOEPINT_xfercompl | DOEPINT_ahberr
|
DOEPMSK = DOEPINT_setup | DOEPINT_xfercompl | DOEPINT_ahberr;
|
||||||
| DOEPINT_epdisabled;
|
DIEPMSK = DIEPINT_xfercompl | DIEPINT_timeout | DIEPINT_ahberr;
|
||||||
DIEPMSK = DIEPINT_xfercompl | DIEPINT_timeout
|
|
||||||
| DIEPINT_epdisabled | DIEPINT_ahberr;
|
|
||||||
DAINTMSK = 0xffffffff;
|
DAINTMSK = 0xffffffff;
|
||||||
|
|
||||||
reset_endpoints();
|
reset_endpoints();
|
||||||
|
|
@ -381,80 +384,95 @@ void usb_drv_exit(void)
|
||||||
disable_global_interrupts();
|
disable_global_interrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_regs(void)
|
static void handle_ep_int(int ep, bool dir_in)
|
||||||
{
|
{
|
||||||
logf("DSTS: %lx", DSTS);
|
if(dir_in)
|
||||||
logf("DOEPCTL0=%lx", DOEPCTL(0));
|
|
||||||
logf("DOEPTSIZ=%lx", DOEPTSIZ(0));
|
|
||||||
logf("DIEPCTL0=%lx", DIEPCTL(0));
|
|
||||||
logf("DOEPMSK=%lx", DOEPMSK);
|
|
||||||
logf("DIEPMSK=%lx", DIEPMSK);
|
|
||||||
logf("DAINTMSK=%lx", DAINTMSK);
|
|
||||||
logf("DAINT=%lx", DAINT);
|
|
||||||
logf("GINTSTS=%lx", GINTSTS);
|
|
||||||
logf("GINTMSK=%lx", GINTMSK);
|
|
||||||
logf("DCTL=%lx", DCTL);
|
|
||||||
logf("GAHBCFG=%lx", GAHBCFG);
|
|
||||||
logf("GUSBCFG=%lx", GUSBCFG);
|
|
||||||
logf("DCFG=%lx", DCFG);
|
|
||||||
logf("DTHRCTL=%lx", DTHRCTL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool handle_reset(void)
|
|
||||||
{
|
|
||||||
logf("usb: bus reset");
|
|
||||||
|
|
||||||
dump_regs();
|
|
||||||
/* Clear the Remote Wakeup Signalling */
|
|
||||||
DCTL &= ~DCTL_rmtwkupsig;
|
|
||||||
|
|
||||||
/* Flush FIFOs */
|
|
||||||
flush_tx_fifos(0x10);
|
|
||||||
|
|
||||||
reset_endpoints();
|
|
||||||
|
|
||||||
/* Reset Device Address */
|
|
||||||
DCFG &= bitm(DCFG, devadr);
|
|
||||||
|
|
||||||
usb_core_bus_reset();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool handle_enum_done(void)
|
|
||||||
{
|
|
||||||
logf("usb: enum done");
|
|
||||||
|
|
||||||
/* read speed */
|
|
||||||
switch(extract(DSTS, enumspd))
|
|
||||||
{
|
{
|
||||||
case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
|
if(DIEPINT(ep) & DIEPINT_ahberr)
|
||||||
logf("usb: HS");
|
panicf("usb: ahb error on EP%d IN", ep);
|
||||||
break;
|
if(DIEPINT(ep) & DIEPINT_xfercompl)
|
||||||
case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
|
{
|
||||||
case DSTS_ENUMSPD_FS_PHY_48MHZ:
|
logf("usb: xfer complete on EP%d IN", ep);
|
||||||
logf("usb: FS");
|
if(endpoints[ep].busy)
|
||||||
break;
|
{
|
||||||
case DSTS_ENUMSPD_LS_PHY_6MHZ:
|
endpoints[ep].busy = false;
|
||||||
panicf("usb: LS is not supported");
|
endpoints[ep].status = 0;
|
||||||
|
endpoints[ep].done = true;
|
||||||
|
/* works even for PE0 */
|
||||||
|
int transfered = endpoints[ep].len - (DIEPTSIZ(ep) & DEPTSIZ_xfersize_bits);
|
||||||
|
clean_dcache_range((void *)DIEPDMA(ep), transfered);
|
||||||
|
usb_core_transfer_complete(ep, USB_DIR_IN, 0, transfered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(DIEPINT(ep) & DIEPINT_timeout)
|
||||||
|
{
|
||||||
|
logf("usb: timeout on EP%d IN", ep);
|
||||||
|
if(endpoints[ep].busy)
|
||||||
|
{
|
||||||
|
endpoints[ep].busy = false;
|
||||||
|
endpoints[ep].status = 1;
|
||||||
|
endpoints[ep].done = true;
|
||||||
|
/* for safety, act as if no bytes as been transfered */
|
||||||
|
endpoints[ep].len = 0;
|
||||||
|
usb_core_transfer_complete(ep, USB_DIR_IN, 1, 0);
|
||||||
|
wakeup_signal(&endpoints[ep].complete);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* clear interrupts */
|
||||||
|
DIEPINT(ep) = DIEPINT(ep);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(DOEPINT(ep) & DOEPINT_ahberr)
|
||||||
|
panicf("usb: ahb error on EP%d OUT", ep);
|
||||||
|
if(DOEPINT(ep) & DOEPINT_xfercompl)
|
||||||
|
{
|
||||||
|
logf("usb: xfer complete on EP%d OUT", ep);
|
||||||
|
if(endpoints[ep].busy)
|
||||||
|
{
|
||||||
|
endpoints[ep].busy = false;
|
||||||
|
endpoints[ep].status = 0;
|
||||||
|
endpoints[ep].done = true;
|
||||||
|
/* works even for PE0 */
|
||||||
|
int transfered = endpoints[ep].len - (DOEPTSIZ(ep) & DEPTSIZ_xfersize_bits);
|
||||||
|
clean_dcache_range((void *)DOEPDMA(ep), transfered);
|
||||||
|
usb_core_transfer_complete(ep, USB_DIR_OUT, 0, transfered);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(DOEPINT(ep) & DOEPINT_setup)
|
||||||
|
{
|
||||||
|
logf("usb: setup on EP%d OUT", ep);
|
||||||
|
if(ep != 0)
|
||||||
|
panicf("usb: setup not on EP0, this is impossible");
|
||||||
|
clean_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */
|
||||||
|
usb_core_control_request(&ep0_setup_pkt);
|
||||||
|
}
|
||||||
|
/* setup EP0 for the next transfer */
|
||||||
|
DOEPTSIZ(0) = (1 << DEPTSIZ0_supcnt_bitp) | (1 << DEPTSIZ0_pkcnt_bitp) | 8;
|
||||||
|
DOEPDMA(0) = (unsigned long)&ep0_setup_pkt; /* virtual address=physical address */
|
||||||
|
DOEPCTL(0) |= DEPCTL_epena | DEPCTL_cnak;
|
||||||
|
|
||||||
|
/* clear interrupts */
|
||||||
|
DOEPINT(ep) = DOEPINT(ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fixme: change EP0 mps here */
|
|
||||||
dump_regs();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool handle_in_ep_int(void)
|
static void handle_ep_ints(void)
|
||||||
{
|
{
|
||||||
panicf("usb: in ep int");
|
logf("usb: ep int");
|
||||||
return false;
|
/* we must read it */
|
||||||
}
|
unsigned long daint = DAINT;
|
||||||
|
unsigned i, ep;
|
||||||
|
|
||||||
static bool handle_out_ep_int(void)
|
FOR_EACH_IN_EP_AND_EP0(i, ep)
|
||||||
{
|
if(daint & DAINT_IN_EP(ep))
|
||||||
panicf("usb: out ep int");
|
handle_ep_int(ep, true);
|
||||||
return false;
|
FOR_EACH_OUT_EP_AND_EP0(i, ep)
|
||||||
|
if(daint & DAINT_OUT_EP(ep))
|
||||||
|
handle_ep_int(ep, false);
|
||||||
|
|
||||||
|
/* write back to clear status */
|
||||||
|
DAINT = daint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* interrupt service routine */
|
/* interrupt service routine */
|
||||||
|
|
@ -463,45 +481,59 @@ void INT_USB(void)
|
||||||
/* some bits in GINTSTS can be set even though we didn't enable the interrupt source
|
/* some bits in GINTSTS can be set even though we didn't enable the interrupt source
|
||||||
* so AND it with the actual mask */
|
* so AND it with the actual mask */
|
||||||
unsigned long sts = GINTSTS & GINTMSK;
|
unsigned long sts = GINTSTS & GINTMSK;
|
||||||
unsigned long handled_one = 0; /* mask of all listed one (either handled or not) */
|
|
||||||
|
|
||||||
#define HANDLED_CASE(bitmask, callfn) \
|
|
||||||
handled_one |= bitmask; \
|
|
||||||
if(sts & bitmask) \
|
|
||||||
{ \
|
|
||||||
if(!callfn()) \
|
|
||||||
goto Lerr; \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define UNHANDLED_CASE(bitmask) \
|
|
||||||
handled_one |= bitmask; \
|
|
||||||
if(sts & bitmask) \
|
|
||||||
goto Lunhandled;
|
|
||||||
|
|
||||||
/* device part */
|
/* device part */
|
||||||
HANDLED_CASE(GINTMSK_usbreset, handle_reset)
|
if(sts & GINTMSK_usbreset)
|
||||||
HANDLED_CASE(GINTMSK_enumdone, handle_enum_done)
|
{
|
||||||
HANDLED_CASE(GINTMSK_inepintr, handle_in_ep_int)
|
logf("usb: bus reset");
|
||||||
HANDLED_CASE(GINTMSK_outepintr, handle_out_ep_int)
|
|
||||||
|
/* Clear the Remote Wakeup Signalling */
|
||||||
|
DCTL &= ~DCTL_rmtwkupsig;
|
||||||
|
|
||||||
|
/* Flush FIFOs */
|
||||||
|
flush_tx_fifos(0x10);
|
||||||
|
|
||||||
|
reset_endpoints();
|
||||||
|
|
||||||
|
/* Reset Device Address */
|
||||||
|
DCFG &= bitm(DCFG, devadr);
|
||||||
|
|
||||||
|
usb_core_bus_reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sts & GINTMSK_enumdone)
|
||||||
|
{
|
||||||
|
logf("usb: enum done");
|
||||||
|
|
||||||
|
/* read speed */
|
||||||
|
switch(extract(DSTS, enumspd))
|
||||||
|
{
|
||||||
|
case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
|
||||||
|
logf("usb: HS");
|
||||||
|
break;
|
||||||
|
case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
|
||||||
|
case DSTS_ENUMSPD_FS_PHY_48MHZ:
|
||||||
|
logf("usb: FS");
|
||||||
|
break;
|
||||||
|
case DSTS_ENUMSPD_LS_PHY_6MHZ:
|
||||||
|
panicf("usb: LS is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fixme: change EP0 mps here */
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sts & (GINTMSK_outepintr | GINTMSK_inepintr))
|
||||||
|
{
|
||||||
|
handle_ep_ints();
|
||||||
|
}
|
||||||
|
|
||||||
/* common part */
|
/* common part */
|
||||||
UNHANDLED_CASE(GINTMSK_otgintr)
|
if(sts & GINTMSK_otgintr)
|
||||||
UNHANDLED_CASE(GINTMSK_conidstschng)
|
{
|
||||||
UNHANDLED_CASE(GINTMSK_disconnect)
|
panicf("usb: otg int");
|
||||||
|
}
|
||||||
/* unlisted ones */
|
|
||||||
if(sts & ~handled_one)
|
|
||||||
goto Lunhandled;
|
|
||||||
|
|
||||||
GINTSTS = GINTSTS;
|
GINTSTS = GINTSTS;
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
Lunhandled:
|
|
||||||
panicf("unhandled usb int: %lx", sts);
|
|
||||||
|
|
||||||
Lerr:
|
|
||||||
panicf("error in usb int: %lx", sts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_drv_port_speed(void)
|
int usb_drv_port_speed(void)
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,8 @@
|
||||||
#define DOEPTSIZ(ep) DEV_REG(0x300 + (ep) * 0x20 + 0x10)
|
#define DOEPTSIZ(ep) DEV_REG(0x300 + (ep) * 0x20 + 0x10)
|
||||||
|
|
||||||
/* valid for any D{I,O}EPTSIZi with 1<=i<=15, NOT for i=0 ! */
|
/* valid for any D{I,O}EPTSIZi with 1<=i<=15, NOT for i=0 ! */
|
||||||
#define DEPTSIZ_xfersize_bits 0x7ffff /** Transfer Size */
|
#define DEPTSIZ_xfersize_bitp 0 /** Transfer Size */
|
||||||
|
#define DEPTSIZ_xfersize_bits 0x7ffff
|
||||||
#define DEPTSIZ_pkcnt_bitp 19 /** Packet Count */
|
#define DEPTSIZ_pkcnt_bitp 19 /** Packet Count */
|
||||||
#define DEPTSIZ_pkcnt_bits 0x3ff
|
#define DEPTSIZ_pkcnt_bits 0x3ff
|
||||||
#define DEPTSIZ_mc_bitp 29 /** Multi Count - Periodic IN endpoints */
|
#define DEPTSIZ_mc_bitp 29 /** Multi Count - Periodic IN endpoints */
|
||||||
|
|
@ -452,7 +453,7 @@
|
||||||
/**
|
/**
|
||||||
* Parameters
|
* Parameters
|
||||||
*/
|
*/
|
||||||
#define USE_CUSTOM_FIFO_LAYOUT
|
/*#define USE_CUSTOM_FIFO_LAYOUT*/
|
||||||
|
|
||||||
#ifdef USE_CUSTOM_FIFO_LAYOUT
|
#ifdef USE_CUSTOM_FIFO_LAYOUT
|
||||||
/* Data fifo: includes RX fifo, non period TX fifo and periodic fifos
|
/* Data fifo: includes RX fifo, non period TX fifo and periodic fifos
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue