Separate SAMA5 OHCI interrupt handling into separate functions

This commit is contained in:
Gregory Nutt 2013-08-13 13:34:35 -06:00
parent ad258cb3b7
commit b575450a04
2 changed files with 233 additions and 174 deletions

View File

@ -345,6 +345,8 @@ static int sam_ctrltd(struct sam_ohci_s *priv, uint32_t dirpid,
/* Interrupt handling **********************************************************/ /* Interrupt handling **********************************************************/
static void sam_rhsc_interrupt(struct sam_ohci_s *priv);
static void sam_wdh_interrupt(struct sam_ohci_s *priv);
static int sam_ohci_interrupt(int irq, FAR void *context); static int sam_ohci_interrupt(int irq, FAR void *context);
/* USB host controller operations **********************************************/ /* USB host controller operations **********************************************/
@ -1188,7 +1190,8 @@ static inline int sam_remisoced(struct sam_ohci_s *priv,
static int sam_enqueuetd(struct sam_ohci_s *priv, static int sam_enqueuetd(struct sam_ohci_s *priv,
struct sam_ed_s *ed, uint32_t dirpid, struct sam_ed_s *ed, uint32_t dirpid,
uint32_t toggle, volatile uint8_t *buffer, size_t buflen) uint32_t toggle, volatile uint8_t *buffer,
size_t buflen)
{ {
struct sam_gtd_s *td; struct sam_gtd_s *td;
int ret = -ENOMEM; int ret = -ENOMEM;
@ -1339,42 +1342,25 @@ static int sam_ctrltd(struct sam_ohci_s *priv, uint32_t dirpid, uint8_t *buffer,
} }
/******************************************************************************* /*******************************************************************************
* Name: sam_ohci_interrupt * Name: sam_rhsc_interrupt
* *
* Description: * Description:
* USB interrupt handler * OHCI root hub status change interrupt handler
* *
*******************************************************************************/ *******************************************************************************/
static int sam_ohci_interrupt(int irq, FAR void *context) static void sam_rhsc_interrupt(struct sam_ohci_s *priv)
{ {
struct sam_ohci_s *priv = &g_usbhost; struct sam_rhport_s *rhport;
uint32_t intst;
uint32_t pending;
uint32_t regval;
uint32_t regaddr; uint32_t regaddr;
uint32_t rhportst;
int rhpndx; int rhpndx;
/* Read Interrupt Status and mask out interrupts that are not enabled. */ /* Handle root hub status change on each root port */
intst = sam_getreg(SAM_USBHOST_INTST);
regval = sam_getreg(SAM_USBHOST_INTEN);
ullvdbg("INST: %08x INTEN: %08x\n", intst, regval);
pending = intst & regval;
if (pending != 0)
{
/* Root hub status change interrupt */
if ((pending & OHCI_INT_RHSC) != 0)
{
/* Hand root hub status change on each root port */
ullvdbg("Root Hub Status Change\n");
for (rhpndx = 0; rhpndx < SAM_USBHOST_NRHPORT; rhpndx++) for (rhpndx = 0; rhpndx < SAM_USBHOST_NRHPORT; rhpndx++)
{ {
struct sam_rhport_s *rhport = &priv->rhport[rhpndx]; rhport = &priv->rhport[rhpndx];
uint32_t rhportst;
regaddr = SAM_USBHOST_RHPORTST(rhpndx+1); regaddr = SAM_USBHOST_RHPORTST(rhpndx+1);
rhportst = sam_getreg(regaddr); rhportst = sam_getreg(regaddr);
@ -1431,11 +1417,8 @@ static int sam_ohci_interrupt(int irq, FAR void *context)
* when CCS == 1. * when CCS == 1.
*/ */
rhport->lowspeed = rhport->lowspeed = (rhportst & OHCI_RHPORTST_LSDA) != 0;
(rhportst & OHCI_RHPORTST_LSDA) != 0; ullvdbg("Speed: %s\n", rhport->lowspeed ? "LOW" : "FULL");
ullvdbg("Speed: %s\n",
rhport->lowspeed ? "LOW" : "FULL");
} }
/* Check if we are now disconnected */ /* Check if we are now disconnected */
@ -1490,9 +1473,15 @@ static int sam_ohci_interrupt(int irq, FAR void *context)
} }
} }
/* Writeback Done Head interrupt */ /*******************************************************************************
* Name: sam_wdh_interrupt
*
* Description:
* OHCI write done head interrupt handler
*
*******************************************************************************/
if ((pending & OHCI_INT_WDH) != 0) static void sam_wdh_interrupt(struct sam_ohci_s *priv)
{ {
struct sam_gtd_s *td; struct sam_gtd_s *td;
struct sam_gtd_s *next; struct sam_gtd_s *next;
@ -1550,11 +1539,76 @@ static int sam_ohci_interrupt(int irq, FAR void *context)
} }
} }
/*******************************************************************************
* Name: sam_ohci_interrupt
*
* Description:
* OHCI interrupt handler
*
*******************************************************************************/
static int sam_ohci_interrupt(int irq, FAR void *context)
{
struct sam_ohci_s *priv = &g_usbhost;
uint32_t intst;
uint32_t pending;
uint32_t regval;
/* Read Interrupt Status and mask out interrupts that are not enabled. */
intst = sam_getreg(SAM_USBHOST_INTST);
regval = sam_getreg(SAM_USBHOST_INTEN);
ullvdbg("INST: %08x INTEN: %08x\n", intst, regval);
pending = intst & regval;
if (pending != 0)
{
/* Root hub status change interrupt */
if ((pending & OHCI_INT_RHSC) != 0)
{
/* Handle root hub status change on each root port */
ullvdbg("Root Hub Status Change\n");
sam_rhsc_interrupt(priv);
}
/* Writeback Done Head interrupt */
if ((pending & OHCI_INT_WDH) != 0)
{
/* The host controller just wrote the list of finished TDs into the HCCA
* done head. This may include multiple packets that were transferred
* in the preceding frame.
*/
ullvdbg("Writeback Done Head interrupt\n");
sam_wdh_interrupt(priv);
}
#ifdef CONFIG_DEBUG_USB #ifdef CONFIG_DEBUG_USB
if ((pending & SAM_DEBUG_INTS) != 0) if ((pending & SAM_DEBUG_INTS) != 0)
{
if ((pending & OHCI_INT_UE) != 0)
{
/* An unrecoverable error occurred. Unrecoverable errors
* are usually the consequence of bad descriptor contents
* or DMA errors.
*
* Treat this like a normal write done head interrupt. We
* just want to see if there is any status information writen
* to the descriptors (and the normal write done head
* interrupt will not be occurring).
*/
ulldbg("ERROR: Unrecoverable error. INTST: %08x\n", intst);
sam_wdh_interrupt(priv);
}
else
{ {
ulldbg("ERROR: Unhandled interrupts INTST: %08x\n", intst); ulldbg("ERROR: Unhandled interrupts INTST: %08x\n", intst);
} }
}
#endif #endif
/* Clear interrupt status register */ /* Clear interrupt status register */
@ -1727,7 +1781,8 @@ static int sam_enumerate(FAR struct usbhost_driver_s *drvr, int rhpndx)
* drvr - The USB host driver instance obtained as a parameter from the call to * drvr - The USB host driver instance obtained as a parameter from the call to
* the class create() method. * the class create() method.
* funcaddr - The USB address of the function containing the endpoint that EP0 * funcaddr - The USB address of the function containing the endpoint that EP0
* controls * controls. A funcaddr of zero will be received if no address is yet assigned
* to the device.
* maxpacketsize - The maximum number of bytes that can be sent to or * maxpacketsize - The maximum number of bytes that can be sent to or
* received from the endpoint in a single data packet * received from the endpoint in a single data packet
* *
@ -1746,8 +1801,10 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr; struct sam_ohci_s *priv = (struct sam_ohci_s *)drvr;
struct sam_rhport_s *rhport; struct sam_rhport_s *rhport;
DEBUGASSERT(priv && funcaddr > 0 && funcaddr <= SAM_USBHOST_NRHPORT && DEBUGASSERT(priv &&
funcaddr >= 0 && funcaddr <= SAM_USBHOST_NRHPORT &&
maxpacketsize < 2048); maxpacketsize < 2048);
rhport = &priv->rhport[funcaddr - 1]; rhport = &priv->rhport[funcaddr - 1];
/* We must have exclusive access to EP0 and the control list */ /* We must have exclusive access to EP0 and the control list */

View File

@ -401,6 +401,7 @@ int usbhost_enumerate(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
udbg("ERROR: SETADDRESS DRVR_CTRLOUT returned %d\n", ret); udbg("ERROR: SETADDRESS DRVR_CTRLOUT returned %d\n", ret);
goto errout; goto errout;
} }
usleep(2*1000); usleep(2*1000);
/* Modify control pipe with the provided USB device address */ /* Modify control pipe with the provided USB device address */
@ -514,5 +515,6 @@ errout:
{ {
DRVR_FREE(drvr, (uint8_t*)ctrlreq); DRVR_FREE(drvr, (uint8_t*)ctrlreq);
} }
return ret; return ret;
} }