From 664abdf0fcc8e3b16397014c5fa127a24b870bc5 Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 21 Dec 2010 01:10:29 +0000 Subject: Final cleanup before testing git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3203 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c | 237 +++++++++++++++++++++-------- 1 file changed, 177 insertions(+), 60 deletions(-) (limited to 'nuttx/arch/arm/src/lpc17xx') diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c index fb2b4f9bf..454fd7b98 100755 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c @@ -53,7 +53,6 @@ #include #include #include -#include #include #include @@ -71,6 +70,17 @@ * Definitions *******************************************************************************/ +/* I think it is the case that all I/O buffers must lie in AHB SRAM because of + * the OHCI DMA. But this definition has here so that I can experiment later + * to see if this really required. + */ + +#define CONFIG_UBHOST_AHBIOBUFFERS 1 + +#if defined(CONFIG_UBHOST_AHBIOBUFFERS) && LPC17_IOBUFFERS < 1 +# error "No IO buffers allocated" +#endif + /* Frame Interval */ #define FI (12000-1) /* 12000 bits per frame (-1) */ @@ -178,9 +188,9 @@ struct lpc17_edlist_s uint32_t pad[3]; /* To make the same size as struct lpc17_hced_s */ }; -struct lpc17_tdlist_s +struct lpc17_buflist_s { - struct lpc17_tdlist_s *flink; /* Link to next TD buffer in the list */ + struct lpc17_buflist_s *flink; /* Link to next buffer in the list */ /* Variable length buffer data follows */ }; @@ -214,6 +224,12 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val); static struct lpc17_hced_s *lpc17_edalloc(struct lpc17_usbhost_s *priv); static void lpc17_edfree(struct lpc17_usbhost_s *priv, struct lpc17_hced_s *ed); +static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv); +static void lpc17_tdfree(struct lpc17_usbhost_s *priv, uint8_t *buffer); +#ifdef CONFIG_UBHOST_AHBIOBUFFERS +static uint8_t *lpc17_ioalloc(struct lpc17_usbhost_s *priv); +static void lpc17_iofree(struct lpc17_usbhost_s *priv, uint8_t *buffer); +#endif static void lpc17_enqueuetd(volatile struct lpc17_hced_s *ed, uint32_t dirpid, uint32_t toggle, volatile uint8_t *buffer, size_t buflen); @@ -281,8 +297,11 @@ static struct lpc17_usbhost_s g_usbhost = /* This is a free list of EDs and TD buffers */ -static struct lpc17_edlist_s *g_edfree; -static struct lpc17_tdlist_s *g_tdfree; +static struct lpc17_edlist_s *g_edfree; +static struct lpc17_buflist_s *g_tdfree; +#ifdef CONFIG_UBHOST_AHBIOBUFFERS +static struct lpc17_buflist_s *g_iofree; +#endif /******************************************************************************* * Public Data @@ -503,6 +522,10 @@ static void lpc17_edfree(struct lpc17_usbhost_s *priv, struct lpc17_hced_s *ed) * Description: * Allocate an TD buffer from the free list * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * *******************************************************************************/ static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv) @@ -510,7 +533,7 @@ static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv) uint8_t *ret = (uint8_t *)g_tdfree; if (ret) { - g_tdfree = ((struct lpc17_tdlist_s*)ret)->flink; + g_tdfree = ((struct lpc17_buflist_s*)ret)->flink; } return ret; } @@ -525,11 +548,52 @@ static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv) static void lpc17_tdfree(struct lpc17_usbhost_s *priv, uint8_t *buffer) { - struct lpc17_tdlist_s *tdfree = (struct lpc17_tdlist_s *)buffer; - tdfree->flink = g_tdfree; - g_tdfree = tdfree; + struct lpc17_buflist_s *tdfree = (struct lpc17_buflist_s *)buffer; + tdfree->flink = g_tdfree; + g_tdfree = tdfree; } +/******************************************************************************* + * Name: lpc17_ioalloc + * + * Description: + * Allocate an IO buffer from the free list + * + * Assumptions: + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. + * + *******************************************************************************/ + +#ifdef CONFIG_UBHOST_AHBIOBUFFERS +static uint8_t *lpc17_ioalloc(struct lpc17_usbhost_s *priv) +{ + uint8_t *ret = (uint8_t *)g_iofree; + if (ret) + { + g_iofree = ((struct lpc17_buflist_s*)ret)->flink; + } + return ret; +} +#endif + +/******************************************************************************* + * Name: lpc17_tdfree + * + * Description: + * Return an TD buffer to the free list + * + *******************************************************************************/ + +#ifdef CONFIG_UBHOST_AHBIOBUFFERS +static void lpc17_iofree(struct lpc17_usbhost_s *priv, uint8_t *buffer) +{ + struct lpc17_buflist_s *iofree = (struct lpc17_buflist_s *)buffer; + iofree->flink = g_iofree; + g_iofree = iofree; +} +#endif + /******************************************************************************* * Name: lpc17_enqueuetd * @@ -758,7 +822,6 @@ static int lpc17_usbinterrupt(int irq, FAR void *context) /* Read the device interrupt status register */ - usbtrace(TRACE_INTENTRY(LPC17_TRACEINTID_USB), 0xbeef); uint32_t intstatus; uint32_t intenable; @@ -775,12 +838,12 @@ static int lpc17_usbinterrupt(int irq, FAR void *context) if ((intstatus & OHCI_INT_RHSC) != 0) { uint32_t rhportst1 = lpc17_getreg(LPC17_USBHOST_RHPORTST1); - ullvdbg("Root Hub Status Change, RHPORTST: %08x\n", portstatus); + ullvdbg("Root Hub Status Change, RHPORTST: %08x\n", rhportst1); if ((rhportst1 & OHCI_RHPORTST_CSC) != 0) { uint32_t rhstatus = lpc17_getreg(LPC17_USBHOST_RHSTATUS); - ullvdbg("Connect Status Change, RHSTATUS: %08x\n", portstatus); + ullvdbg("Connect Status Change, RHSTATUS: %08x\n", rhportst1); /* If DRWE is set, Connect Status Change indicates a remote wake-up event */ @@ -867,7 +930,7 @@ static int lpc17_usbinterrupt(int irq, FAR void *context) lpc17_putreg(intstatus, LPC17_USBHOST_INTST); } - usbtrace(TRACE_INTEXIT(LPC17_TRACEINTID_USB), 0); + return OK; } @@ -898,7 +961,9 @@ static int lpc17_usbinterrupt(int irq, FAR void *context) * returned indicating the nature of the failure * * Assumptions: - * This function will *not* be called from an interrupt handler. + * - Only a single class bound to a single device is supported. + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. * *******************************************************************************/ @@ -1081,7 +1146,8 @@ errout: * returned indicating the nature of the failure * * Assumptions: - * This function will *not* be called from an interrupt handler. + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. * *******************************************************************************/ @@ -1119,7 +1185,8 @@ static int lpc17_alloc(FAR struct usbhost_driver_s *drvr, * returned indicating the nature of the failure * * Assumptions: - * This function will *not* be called from an interrupt handler. + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. * *******************************************************************************/ @@ -1158,7 +1225,9 @@ static int lpc17_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) * returned indicating the nature of the failure * * Assumptions: - * This function will *not* be called from an interrupt handler. + * - Only a single class bound to a single device is supported. + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. * *******************************************************************************/ @@ -1238,7 +1307,9 @@ static int lpc17_ctrlout(FAR struct usbhost_driver_s *drvr, * returned indicating the nature of the failure * * Assumptions: - * This function will *not* be called from an interrupt handler. + * - Only a single class bound to a single device is supported. + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. * *******************************************************************************/ @@ -1247,64 +1318,111 @@ static int lpc17_transfer(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer, size_t buflen) { struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr; - struct lpc17_hced_s *ed; + struct lpc17_hced_s *ed = NULL; uint32_t dirpid; uint32_t regval; +#ifdef CONFIG_UBHOST_AHBIOBUFFERS + uint8_t *origbuf = NULL; +#endif int ret = -ENOMEM; + /* Allocate an IO buffer if the user buffer does not lie in AHB SRAM */ + +#ifdef CONFIG_UBHOST_AHBIOBUFFERS + if ((uintptr_t)buffer >= LPC17_SRAM_BANK0 && + (uintptr_t)buffer < (LPC17_SRAM_BANK0 + LPC17_SRAM_BANK0 + LPC17_SRAM_BANK0)) + { + /* Allocate an IO buffer in AHB SRAM */ + + origbuf = buffer; + buffer = lpc17_ioalloc(priv); + if (!buffer) + { + goto errout; + } + + /* Copy the user data into the AHB SRAM IO buffer. Sad... so + * inefficient. But without exposing the AHB SRAM to the final, + * end-user client I don't know of any way around this copy. + */ + + memcpy(buffer, origbuf, buflen); + } +#endif + /* Allocate an ED */ ed = lpc17_edalloc(priv); - if (ed) + if (!ed) { - /* Format the endpoint descriptor */ + goto errout; + } + + /* Format the endpoint descriptor */ - lpc17_edinit(ed); - ed->ctrl = (uint32_t)(ep->addr) << ED_CONTROL_EN_SHIFT | - (uint32_t)(ep->mxpacketsize) << ED_CONTROL_MPS_SHIFT; + lpc17_edinit(ed); + ed->ctrl = (uint32_t)(ep->addr) << ED_CONTROL_EN_SHIFT | + (uint32_t)(ep->mxpacketsize) << ED_CONTROL_MPS_SHIFT; - /* Get the direction of the endpoint */ + /* Get the direction of the endpoint */ - if (ep->in) - { - ed->ctrl |= ED_CONTROL_D_IN; - dirpid = GTD_STATUS_DP_IN; - } - else - { - ed->ctrl |= ED_CONTROL_D_OUT; - dirpid = GTD_STATUS_DP_OUT; - } + if (ep->in) + { + ed->ctrl |= ED_CONTROL_D_IN; + dirpid = GTD_STATUS_DP_IN; + } + else + { + ed->ctrl |= ED_CONTROL_D_OUT; + dirpid = GTD_STATUS_DP_OUT; + } - /* Then enqueue the transfer */ + /* Then enqueue the transfer */ - lpc17_enqueuetd(ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen); + lpc17_enqueuetd(ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen); - lpc17_putreg((uint32_t)ed, LPC17_USBHOST_BULKHEADED); + lpc17_putreg((uint32_t)ed, LPC17_USBHOST_BULKHEADED); - regval = lpc17_getreg(LPC17_USBHOST_CMDST); - regval |= OHCI_CMDST_BLF; - lpc17_putreg(regval, LPC17_USBHOST_CMDST); + regval = lpc17_getreg(LPC17_USBHOST_CMDST); + regval |= OHCI_CMDST_BLF; + lpc17_putreg(regval, LPC17_USBHOST_CMDST); - regval = lpc17_getreg(LPC17_USBHOST_CTRL); - regval |= OHCI_CTRL_BLE; - lpc17_putreg(regval, LPC17_USBHOST_CTRL); + regval = lpc17_getreg(LPC17_USBHOST_CTRL); + regval |= OHCI_CTRL_BLE; + lpc17_putreg(regval, LPC17_USBHOST_CTRL); + + /* Wait for the Writeback Done Head interrupt */ - /* Wait for the Writeback Done Head interrupt */ + lpc17_takesem(&priv->wdhsem); - lpc17_takesem(&priv->wdhsem); + /* Check the TDHEAD completion status bits */ - /* Check the TDHEAD completion status bits */ + if (priv->tdstatus == 0) + { + ret = OK; + } + else + { + ret = -EIO; + } - if (priv->tdstatus == 0) - { - ret = OK; - } - else - { - ret = -EIO; - } +errout: + /* Free any temporary IO buffers */ + +#ifdef CONFIG_UBHOST_AHBIOBUFFERS + if (buffer && origbuf) + { + lpc17_iofree(priv, buffer); } +#endif + + /* Free the endpoint descriptor */ + + if (ed) + { + lpc17_edfree(priv, ed); + } + return ret; } @@ -1326,7 +1444,9 @@ static int lpc17_transfer(FAR struct usbhost_driver_s *drvr, * None * * Assumptions: - * This function will *not* be called from an interrupt handler. + * - Only a single class bound to a single device is supported. + * - Called from a single thread so no mutual exclusion is required. + * - Never called from an interrupt handler. * *******************************************************************************/ @@ -1393,8 +1513,6 @@ void up_usbhostinitialize(void) irqstate_t flags; int i; - usbtrace(TRACE_DEVINIT, 0); - /* Initialize the state data structure */ sem_init(&priv->rhssem, 0, 0); @@ -1508,8 +1626,7 @@ void up_usbhostinitialize(void) if (irq_attach(LPC17_IRQ_USB, lpc17_usbinterrupt) != 0) { - usbtrace(TRACE_DEVERROR(LPC17_TRACEERR_IRQREGISTRATION), - (uint16_t)LPC17_IRQ_USB); + udbg("Failed to attach IRQ\n"); return; } -- cgit v1.2.3