diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-01-15 17:46:55 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-01-15 17:46:55 +0000 |
commit | 3f0f70063b9aa18280083f32cae2d1b01849d838 (patch) | |
tree | a6d105515a2418cc41a5e8cce349fae06aaf5615 | |
parent | e9a92fa715e5c58295066b6a9e8d8033cabaadd8 (diff) | |
download | nuttx-3f0f70063b9aa18280083f32cae2d1b01849d838.tar.gz nuttx-3f0f70063b9aa18280083f32cae2d1b01849d838.tar.bz2 nuttx-3f0f70063b9aa18280083f32cae2d1b01849d838.zip |
TD's no longer hard allocated
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3252 42af7a65-404d-4744-a932-0658087f49c3
-rwxr-xr-x | nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h | 70 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c | 456 | ||||
-rwxr-xr-x | nuttx/configs/mbed/README.txt | 2 | ||||
-rwxr-xr-x | nuttx/configs/nucleus2g/README.txt | 2 | ||||
-rwxr-xr-x | nuttx/configs/nucleus2g/nsh/defconfig | 5 | ||||
-rwxr-xr-x | nuttx/configs/olimex-lpc1766stk/README.txt | 2 | ||||
-rwxr-xr-x | nuttx/configs/olimex-lpc1766stk/nsh/defconfig | 5 | ||||
-rw-r--r-- | nuttx/include/nuttx/usb/usbhost.h | 8 |
8 files changed, 368 insertions, 182 deletions
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h b/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h index 9cc76b2b4..efdd87c3f 100755 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h @@ -112,10 +112,6 @@ #define LPC17_HCCA_SIZE 256
-/* Fixed transfer descriptor size */
-
-#define LPC17_TD_SIZE 16
-
/* Fixed endpoint descriptor size. The actual size required by the hardware is only
* 16 bytes, however, we set aside an additional 16 bytes for for internal use by
* the OHCI host driver. 16-bytes is set aside because the EDs must still be
@@ -136,7 +132,29 @@ #define LPC17_EDFREE_SIZE (CONFIG_USBHOST_NEDS * LPC17_ED_SIZE)
-/* Configurable number of descriptor buffer (TDBUFFER) */
+/* Fixed transfer descriptor size. The actual size required by the hardware is only
+ * 16 bytes, however, we set aside an additional 16 bytes for for internal use by
+ * the OHCI host driver. 16-bytes is set aside because the TDs must still be
+ * aligned to 16-byte boundaries.
+ */
+
+#define LPC17_TD_SIZE 32
+
+/* Configurable number of user transfer descriptors (TDs). */
+
+#ifndef CONFIG_USBHOST_NTDS
+# define CONFIG_USBHOST_NTDS 3
+#endif
+
+#if CONFIG_USBHOST_NTDS < 2
+# error "Insufficent TDs"
+#endif
+
+/* Derived size of user trasnfer descriptor (TD) memory. */
+
+#define LPC17_TDFREE_SIZE (CONFIG_USBHOST_NTDS * LPC17_TD_SIZE)
+
+/* Configurable number of request/descriptor buffers (TDBUFFER) */
#ifndef CONFIG_USBHOST_TDBUFFERS
# define CONFIG_USBHOST_TDBUFFERS 2
@@ -156,7 +174,7 @@ # error "TD buffer size must be an even number of 32-bit words"
#endif
-#define LPC17_TDFREE_SIZE (CONFIG_USBHOST_TDBUFFERS * CONFIG_USBHOST_TDBUFSIZE)
+#define LPC17_TBFREE_SIZE (CONFIG_USBHOST_TDBUFFERS * CONFIG_USBHOST_TDBUFSIZE)
/* Configurable size of an IO buffer. The number of IO buffers will be determined
* by what is left at the end of the BANK1 memory setup aside of OHCI RAM.
@@ -177,43 +195,45 @@ * LPC17_BANK1_SIZE 16384
*
* Configuration:
- * CONFIG_USBHOST_OHCIRAM_SIZE 1280
+ * CONFIG_USBHOST_OHCIRAM_SIZE 1536
* CONFIG_USBHOST_NEDS 2
- * CONFIG_USBHOST_TDBUFFERS 2
+ * CONFIG_USBHOST_NEDS 3
+ * CONFIG_USBHOST_TDBUFFERS 3
* CONFIG_USBHOST_TDBUFSIZE 128
* CONFIG_USBHOST_IOBUFSIZE 512
*
* Sizes of things
- * LPC17_EDFREE_SIZE 96 (including EP0)
- * LPC17_TDFREE_SIZE 256
- * LPC17_IOFREE_SIZE 512
+ * LPC17_EDFREE_SIZE 64 0x00000040
+ * LPC17_TDFREE_SIZE 96 0x00000060
+ * LPC17_TBFREE_SIZE 384 0x00000100
+ * LPC17_IOFREE_SIZE 512 0x00000200
*
* Memory Layout
- * LPC17_OHCIRAM_END (0x20008000 + 16384) = 0x2000c000
- * LPC17_OHCIRAM_BASE (0x2000c000 - 1280) = 0x2000bb00
+ * LPC17_OHCIRAM_END (0x20008000 + 16384) = 0x20084000
+ * LPC17_OHCIRAM_BASE (0x2000c000 - 1536) = 0x2000ba00
* LPC17_OHCIRAM_SIZE 1280
* LPC17_BANK1_HEAPBASE 0x20008000
* LPC17_BANK1_HEAPSIZE (16384 - 1280) = 15104
*
- * LPC17_HCCA_BASE 0x2000bb00
- * LPC17_TDHEAD_ADDR 0x2000bc00
- * LPC17_TDTAIL_ADDR 0x2000bc10
- * LPC17_EDCTRL_ADDR 0x2000bc20
- * LPC17_EDFREE_BASE 0x2000bc40
- * LPC17_TDFREE_BASE 0x2000bc80
- * LPC17_IOFREE_BASE 0x2000bd80
- * LPC17_IOBUFFERS (0x2000c000 - 0x2000bd80) / 512 = 640/512 = 1
+ * LPC17_HCCA_BASE 0x20083a00 -- Communications area
+ * LPC17_TDTAIL_ADDR 0x20083b00 -- Common. pre-allocated tail TD
+ * LPC17_EDCTRL_ADDR 0x20083b20 -- Pre-allocated ED for EP0
+ * LPC17_EDFREE_BASE 0x20083b40 -- Free EDs
+ * LPC17_TDFREE_BASE 0x20083b80 -- Free TDs
+ * LPC17_TBFREE_BASE 0x20083be0 -- Free request/descriptor buffers
+ * LPC17_IOFREE_BASE 0x20083d60 -- Free large I/O buffers
+ * LPC17_IOBUFFERS (0x20084000 - 0x20083d60) / 512 = 672/512 = 1
*
- * Wasted memory: 640-512 = 128 bytes
+ * Wasted memory: 672-512 = 160 bytes
*/
#define LPC17_HCCA_BASE (LPC17_OHCIRAM_BASE)
-#define LPC17_TDHEAD_ADDR (LPC17_OHCIRAM_BASE + LPC17_HCCA_SIZE)
-#define LPC17_TDTAIL_ADDR (LPC17_TDHEAD_ADDR + LPC17_TD_SIZE)
+#define LPC17_TDTAIL_ADDR (LPC17_HCCA_BASE + LPC17_HCCA_SIZE)
#define LPC17_EDCTRL_ADDR (LPC17_TDTAIL_ADDR + LPC17_TD_SIZE)
#define LPC17_EDFREE_BASE (LPC17_EDCTRL_ADDR + LPC17_ED_SIZE)
#define LPC17_TDFREE_BASE (LPC17_EDFREE_BASE + LPC17_EDFREE_SIZE)
-#define LPC17_IOFREE_BASE (LPC17_TDFREE_BASE + LPC17_TDFREE_SIZE)
+#define LPC17_TBFREE_BASE (LPC17_TDFREE_BASE + LPC17_TDFREE_SIZE)
+#define LPC17_IOFREE_BASE (LPC17_TBFREE_BASE + LPC17_TBFREE_SIZE)
#if LPC17_IOFREE_BASE > LPC17_OHCIRAM_END
# error "Insufficient OHCI RAM allocated"
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c index fa99f097e..5954a927d 100755 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c +++ b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c @@ -118,13 +118,13 @@ /* Helper definitions */ -#define HCCA ((volatile struct ohci_hcca_s *)LPC17_HCCA_BASE) -#define TDHEAD ((volatile struct ohci_gtd_s *)LPC17_TDHEAD_ADDR) -#define TDTAIL ((volatile struct ohci_gtd_s *)LPC17_TDTAIL_ADDR) -#define EDCTRL ((volatile struct lpc17_ed_s *)LPC17_EDCTRL_ADDR) +#define HCCA ((struct ohci_hcca_s *)LPC17_HCCA_BASE) +#define TDTAIL ((struct lpc17_gtd_s *)LPC17_TDTAIL_ADDR) +#define EDCTRL ((struct lpc17_ed_s *)LPC17_EDCTRL_ADDR) #define EDFREE ((struct lpc17_ed_s *)LPC17_EDFREE_BASE) -#define TDFREE ((uint8_t *)LPC17_TDFREE_BASE) +#define TDFREE ((struct lpc17_gtd_s *)LPC17_TDFREE_BASE) +#define TBFREE ((uint8_t *)LPC17_TBFREE_BASE) #define IOFREE ((uint8_t *)LPC17_IOFREE_BASE) /* Descriptors *****************************************************************/ @@ -181,18 +181,30 @@ struct lpc17_ed_s uint8_t pad[15]; }; -/* The following are used to manage lists of free EDs and TD buffers*/ +/* The OCHI expects the size of an transfer descriptor to be 16 bytes. + * However, the size allocated for an endpoint descriptor is 32 bytes in + * lpc17_ohciram.h. This extra 16-bytes is used by the OHCI host driver in + * order to maintain additional endpoint-specific data. + */ -struct lpc17_edlist_s +struct lpc17_gtd_s { - struct lpc17_edlist_s *flink; /* Link to next ED in the list */ - uint32_t pad[7]; /* To make the same size as struct lpc17_ed_s */ + /* Hardware specific fields */ + + struct ohci_gtd_s hw; + + /* Software specific fields */ + + struct lpc17_ed_s *ed; /* Pointer to parent ED */ + uint8_t pad[12]; }; -struct lpc17_buflist_s +/* The following is used to manage lists of free EDs, TDs, and TD buffers */ + +struct lpc17_list_s { - struct lpc17_buflist_s *flink; /* Link to next buffer in the list */ - /* Variable length buffer data follows */ + struct lpc17_list_s *flink; /* Link to next buffer in the list */ + /* Variable length buffer data follows */ }; /******************************************************************************* @@ -223,15 +235,18 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val); /* Descriptor helper functions *************************************************/ -static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv); -static void lpc17_tdfree(struct lpc17_usbhost_s *priv, uint8_t *buffer); +static struct lpc17_gtd_s *lpc17_tdalloc(struct lpc17_usbhost_s *priv); +static void lpc17_tdfree(struct lpc17_usbhost_s *priv, struct lpc17_gtd_s *buffer); +static uint8_t *lpc17_tballoc(struct lpc17_usbhost_s *priv); +static void lpc17_tbfree(struct lpc17_usbhost_s *priv, uint8_t *buffer); #if LPC17_IOBUFFERS > 0 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 ohci_ed_s *ed, uint32_t dirpid, - uint32_t toggle, volatile uint8_t *buffer, - size_t buflen); +static int lpc17_enqueuetd(struct lpc17_usbhost_s *priv, + struct lpc17_ed_s *ed, uint32_t dirpid, + uint32_t toggle, volatile uint8_t *buffer, + size_t buflen); static int lpc17_ctrltd(struct lpc17_usbhost_s *priv, uint32_t dirpid, uint8_t *buffer, size_t buflen); @@ -291,10 +306,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_buflist_s *g_tdfree; +static struct lpc17_list_s *g_edfree; /* List of unused EDs */ +static struct lpc17_list_s *g_tdfree; /* List of unused TDs */ +static struct lpc17_list_s *g_tbfree; /* List of unused transfer buffers */ #if LPC17_IOBUFFERS > 0 -static struct lpc17_buflist_s *g_iofree; +static struct lpc17_list_s *g_iofree; /* List of unused I/O buffers */ #endif /******************************************************************************* @@ -481,7 +497,7 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val) * Name: lpc17_tdalloc * * Description: - * Allocate an TD buffer from the free list + * Allocate an transfer descriptor from the free list * * Assumptions: * - Called from a single thread so no mutual exclusion is required. @@ -489,13 +505,23 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val) * *******************************************************************************/ -static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv) +static struct lpc17_gtd_s *lpc17_tdalloc(struct lpc17_usbhost_s *priv) { - uint8_t *ret = (uint8_t *)g_tdfree; + struct lpc17_gtd_s *ret; + irqstate_t flags; + + /* Disable interrupts momentarily so that lpc17_tdfree is not called from the + * interrupt handler. + */ + + flags = irqsave(); + ret = (struct lpc17_gtd_s *)g_tdfree; if (ret) { - g_tdfree = ((struct lpc17_buflist_s*)ret)->flink; + g_tdfree = ((struct lpc17_list_s*)ret)->flink; } + + irqrestore(flags); return ret; } @@ -503,18 +529,67 @@ static uint8_t *lpc17_tdalloc(struct lpc17_usbhost_s *priv) * Name: lpc17_tdfree * * Description: - * Return an TD buffer to the free list + * Return an transfer descriptor to the free list + * + * Assumptions: + * - Only called from the WDH interrupt handler (and during initialization). + * - Interrupts are disabled in any case. + * + *******************************************************************************/ + +static void lpc17_tdfree(struct lpc17_usbhost_s *priv, struct lpc17_gtd_s *td) +{ + struct lpc17_list_s *tdfree = (struct lpc17_list_s *)td; + + /* This should not happen but just to be safe, don't free the common, pre- + * allocated tail TD. + */ + + if (tdfree != NULL && td != TDTAIL) + { + tdfree->flink = g_tdfree; + g_tdfree = tdfree; + } +} + +/******************************************************************************* + * Name: lpc17_tballoc + * + * Description: + * Allocate an request/descriptor transfer 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_tballoc(struct lpc17_usbhost_s *priv) +{ + uint8_t *ret = (uint8_t *)g_tbfree; + if (ret) + { + g_tbfree = ((struct lpc17_list_s*)ret)->flink; + } + return ret; +} + +/******************************************************************************* + * Name: lpc17_tbfree + * + * Description: + * Return an request/descriptor transfer buffer to the free list * *******************************************************************************/ -static void lpc17_tdfree(struct lpc17_usbhost_s *priv, uint8_t *buffer) +static void lpc17_tbfree(struct lpc17_usbhost_s *priv, uint8_t *buffer) { - struct lpc17_buflist_s *tdfree = (struct lpc17_buflist_s *)buffer; + struct lpc17_list_s *tbfree = (struct lpc17_list_s *)buffer; - if (tdfree) + if (tbfree) { - tdfree->flink = g_tdfree; - g_tdfree = tdfree; + tbfree->flink = g_tbfree; + g_tbfree = tbfree; } } @@ -536,7 +611,7 @@ 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; + g_iofree = ((struct lpc17_list_s*)ret)->flink; } return ret; } @@ -553,9 +628,9 @@ static uint8_t *lpc17_ioalloc(struct lpc17_usbhost_s *priv) #if LPC17_IOBUFFERS > 0 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; + struct lpc17_list_s *iofree = (struct lpc17_list_s *)buffer; + iofree->flink = g_iofree; + g_iofree = iofree; } #endif @@ -563,25 +638,48 @@ static void lpc17_iofree(struct lpc17_usbhost_s *priv, uint8_t *buffer) * Name: lpc17_enqueuetd * * Description: - * Enqueue a transfer descriptor + * Enqueue a transfer descriptor. Notice that this function only supports + * queue on TD per ED. * *******************************************************************************/ -static void lpc17_enqueuetd(volatile struct ohci_ed_s *ed, uint32_t dirpid, - uint32_t toggle, volatile uint8_t *buffer, size_t buflen) +static int lpc17_enqueuetd(struct lpc17_usbhost_s *priv, + struct lpc17_ed_s *ed, uint32_t dirpid, + uint32_t toggle, volatile uint8_t *buffer, size_t buflen) { - TDHEAD->ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | GTD_STATUS_CC_MASK); - TDTAIL->ctrl = 0; - TDHEAD->cbp = (uint32_t)buffer; - TDTAIL->cbp = 0; - TDHEAD->nexttd = (uint32_t)TDTAIL; - TDTAIL->nexttd = 0; - TDHEAD->be = (uint32_t)(buffer + (buflen - 1)); - TDTAIL->be = 0; - - ed->headp = (uint32_t)TDHEAD | ((ed->headp) & ED_HEADP_C); - ed->tailp = (uint32_t)TDTAIL; - ed->nexted = 0; + struct lpc17_gtd_s *td; + int ret = -ENOMEM; + + /* Allocate a TD from the free list */ + + td = lpc17_tdalloc(priv); + if (td != NULL) + { + /* Initialize the allocated TD and link it before the common tail TD. */ + + td->hw.ctrl = (GTD_STATUS_R | dirpid | TD_DELAY(0) | toggle | GTD_STATUS_CC_MASK); + TDTAIL->hw.ctrl = 0; + td->hw.cbp = (uint32_t)buffer; + TDTAIL->hw.cbp = 0; + td->hw.nexttd = (uint32_t)TDTAIL; + TDTAIL->hw.nexttd = 0; + td->hw.be = (uint32_t)(buffer + (buflen - 1)); + TDTAIL->hw.be = 0; + + /* Configure driver-only fields in the extended TD structure */ + + td->ed = ed; + + /* Link the td to the head of the ED's TD list */ + + ed->hw.headp = (uint32_t)td | ((ed->hw.headp) & ED_HEADP_C); + ed->hw.tailp = (uint32_t)TDTAIL; + ed->hw.nexted = 0; + + ret = OK; + } + + return ret; } /******************************************************************************* @@ -662,47 +760,54 @@ static int lpc17_ctrltd(struct lpc17_usbhost_s *priv, uint32_t dirpid, /* Then enqueue the transfer */ priv->tdstatus = TD_CC_NOERROR; - lpc17_enqueuetd(&EDCTRL->hw, dirpid, toggle, buffer, buflen); - - /* Set the head of the control list to the EP0 EDCTRL (this would have to - * change if we want more than on control EP queued at a time). - */ + ret = lpc17_enqueuetd(priv, EDCTRL, dirpid, toggle, buffer, buflen); + if (ret == OK) + { + /* Set the head of the control list to the EP0 EDCTRL (this would have to + * change if we want more than on control EP queued at a time). + */ - lpc17_putreg(LPC17_EDCTRL_ADDR, LPC17_USBHOST_CTRLHEADED); + lpc17_putreg(LPC17_EDCTRL_ADDR, LPC17_USBHOST_CTRLHEADED); - /* Set ControlListFilled. This bit is used to indicate whether there are - * TDs on the Control list. - */ + /* Set ControlListFilled. This bit is used to indicate whether there are + * TDs on the Control list. + */ - regval = lpc17_getreg(LPC17_USBHOST_CMDST); - regval |= OHCI_CMDST_CLF; - lpc17_putreg(regval, LPC17_USBHOST_CMDST); + regval = lpc17_getreg(LPC17_USBHOST_CMDST); + regval |= OHCI_CMDST_CLF; + lpc17_putreg(regval, LPC17_USBHOST_CMDST); - /* ControlListEnable. This bit is set to enable the processing of the - * Control list. Note: once enabled, it remains enabled and we may even - * complete list processing before we get the bit set. We really - * should never modify the control list while CLE is set. - */ + /* ControlListEnable. This bit is set to enable the processing of the + * Control list. Note: once enabled, it remains enabled and we may even + * complete list processing before we get the bit set. We really + * should never modify the control list while CLE is set. + */ - regval = lpc17_getreg(LPC17_USBHOST_CTRL); - regval |= OHCI_CTRL_CLE; - lpc17_putreg(regval, LPC17_USBHOST_CTRL); + regval = lpc17_getreg(LPC17_USBHOST_CTRL); + regval |= OHCI_CTRL_CLE; + 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 TD completion status bits */ - if (priv->tdstatus == TD_CC_NOERROR) - { - return OK; - } - else - { - uvdbg("Bad TD completion status: %d\n", priv->tdstatus); - return -EIO; + if (priv->tdstatus == TD_CC_NOERROR) + { + ret = OK; + } + else + { + uvdbg("Bad TD completion status: %d\n", priv->tdstatus); + ret = -EIO; + } } + + /* Make sure that there is no outstanding request on this endpoint */ + + priv->wdhwait = false; + return ret; } /******************************************************************************* @@ -814,19 +919,6 @@ static int lpc17_usbinterrupt(int irq, FAR void *context) lpc17_givesem(&priv->rhssem); priv->rhswait = false; } - - /* Wake up the thread waiting for the WDH event. In my - * experience, the WHD event will occur later after the - * disconnection, but it is safer to make sure that - * there are no waiters. - */ - - if (priv->wdhwait) - { - priv->tdstatus = TD_CC_DEVNOTRESPONDING; - lpc17_givesem(&priv->wdhsem); - priv->wdhwait = false; - } } else { @@ -853,34 +945,57 @@ static int lpc17_usbinterrupt(int irq, FAR void *context) if ((pending & OHCI_INT_WDH) != 0) { + struct lpc17_gtd_s *td; + struct lpc17_gtd_s *next; + /* The host controller just wrote the list of finished TDs into the HCCA * done head. Here we assume that only a single packet is "in flight" - * at any given time and we use only the TD at TDHEAD. So not much needs - * to be done here. In a more complex implementation we would need to - * recover these completed TDs in some meaningful way. + * at any given time. */ /* Since there is only one TD, we can disable further TD processing. */ - +#warning "This logic needs to be removed" regval = lpc17_getreg(LPC17_USBHOST_CTRL); regval &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE|OHCI_CTRL_CLE|OHCI_CTRL_BLE); lpc17_putreg(regval, LPC17_USBHOST_CTRL); - /* Get the condition code from the (single) TDHEAD TD status/control word */ + /* Remove the TD(s) from the Writeback Done Head in the HCCA and return + * them to the free list. Note that this is safe because the hardware + * will not modify the writeback done head again until the WDH bit is + * cleared in the interrupt status register. + */ - priv->tdstatus = (TDHEAD->ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT; + td = (struct lpc17_gtd_s *)HCCA->donehead; + HCCA->donehead = 0; -#ifdef CONFIG_DEBUG_USB - if (priv->tdstatus != TD_CC_NOERROR) + /* Process each TD in the write done list */ + + for (; td; td = next) { - /* The transfer failed for some reason... dump some diagnostic info. */ + /* Get the condition code from the (single) TD status/control + * word. This obviously will not work if/when there are more + * one TD in the done list. + */ - ulldbg("ERROR: TD CTRL:%08x/CC:%d RHPORTST1:%08x\n", - TDHEAD->ctrl, priv->tdstatus, - lpc17_getreg(LPC17_USBHOST_RHPORTST1)); - } + priv->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT; + +#ifdef CONFIG_DEBUG_USB + if (priv->tdstatus != TD_CC_NOERROR) + { + /* The transfer failed for some reason... dump some diagnostic info. */ + + ulldbg("ERROR: TD CTRL:%08x/CC:%d RHPORTST1:%08x\n", + td->hw.ctrl, priv->tdstatus, + lpc17_getreg(LPC17_USBHOST_RHPORTST1)); + } #endif + /* Return the TD to the free list */ + + next = (struct lpc17_gtd_s *)td->hw.nexttd; + lpc17_tdfree(priv, td); + } + /* And wake up the thread waiting for the WDH event */ if (priv->wdhwait) @@ -1115,7 +1230,7 @@ static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr, { /* Remove the ED from the freelist */ - g_edfree = ((struct lpc17_edlist_s*)ed)->flink; + g_edfree = ((struct lpc17_list_s*)ed)->flink; /* Configure the endpoint descriptor. */ @@ -1141,12 +1256,24 @@ static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr, { ed->hw.ctrl |= ED_CONTROL_S; } - uvdbg("EP%d CTRL:%08x\n", epdesc->addr, ed->hw.ctrl); /* Set the transfer type */ ed->xfrtype = epdesc->xfrtype; + /* Special Case isochronous transfer types */ + +#if 0 /* Isochronous transfers not yet supported */ + if (ed->xfrtype == USB_EP_ATTR_XFER_ISOC) + { + ed->hw.ctrl |= ED_CONTROL_F; + } +#endif + uvdbg("EP%d CTRL:%08x\n", epdesc->addr, ed->hw.ctrl); + + /* Now add the endpoint descriptor to the appropriate list */ +#warning "Missing logic" + /* Return an opaque reference to the ED */ *ep = (usbhost_ep_t)ed; @@ -1177,7 +1304,7 @@ static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr, static int lpc17_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { - struct lpc17_edlist_s *ed = (struct lpc17_edlist_s *)ep; + struct lpc17_list_s *ed = (struct lpc17_list_s *)ep; DEBUGASSERT(ed); @@ -1192,9 +1319,9 @@ static int lpc17_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * Name: lpc17_alloc * * Description: - * Some hardware supports special memory in which transfer descriptors can + * Some hardware supports special memory in which request and descriptor data can * be accessed more efficiently. This method provides a mechanism to allocate - * the transfer descriptor memory. If the underlying hardware does not support + * the request/descriptor memory. If the underlying hardware does not support * such "special" memory, this functions may simply map to malloc. * * Input Parameters: @@ -1221,7 +1348,7 @@ static int lpc17_alloc(FAR struct usbhost_driver_s *drvr, struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr; DEBUGASSERT(priv && buffer && maxlen); - *buffer = lpc17_tdalloc(priv); + *buffer = lpc17_tballoc(priv); if (*buffer) { *maxlen = CONFIG_USBHOST_TDBUFSIZE; @@ -1234,9 +1361,9 @@ static int lpc17_alloc(FAR struct usbhost_driver_s *drvr, * Name: lpc17_free * * Description: - * Some hardware supports special memory in which transfer descriptors can + * Some hardware supports special memory in which request and descriptor data can * be accessed more efficiently. This method provides a mechanism to free that - * transfer descriptor memory. If the underlying hardware does not support + * request/descriptor memory. If the underlying hardware does not support * such "special" memory, this functions may simply map to free(). * * Input Parameters: @@ -1258,7 +1385,7 @@ static int lpc17_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer) { struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr; DEBUGASSERT(priv && buffer); - lpc17_tdfree(priv, buffer); + lpc17_tbfree(priv, buffer); return OK; } @@ -1477,49 +1604,55 @@ static int lpc17_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* Then enqueue the transfer */ priv->tdstatus = TD_CC_NOERROR; - lpc17_enqueuetd(&ed->hw, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen); - - /* Set the head of the bulk list to the EP descriptor (this would have to - * change if we want more than on bulk EP queued at a time). - */ + ret = lpc17_enqueuetd(priv, ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen); + if (ret == OK) + { + /* Set the head of the bulk list to the EP descriptor (this would have to + * change if we want more than on bulk EP queued at a time). + */ - lpc17_putreg((uint32_t)ed, LPC17_USBHOST_BULKHEADED); + lpc17_putreg((uint32_t)ed, LPC17_USBHOST_BULKHEADED); - /* BulkListFilled. This bit is used to indicate whether there are any - * TDs on the Bulk list. - */ + /* BulkListFilled. This bit is used to indicate whether there are any + * TDs on the Bulk list. + */ - regval = lpc17_getreg(LPC17_USBHOST_CMDST); - regval |= OHCI_CMDST_BLF; - lpc17_putreg(regval, LPC17_USBHOST_CMDST); - - /* BulkListEnable. This bit is set to enable the processing of the Bulk - * list. Note: once enabled, it remains enabled and we may even - * complete list processing before we get the bit set. We really - * should never modify the bulk list while BLE is set. - */ + regval = lpc17_getreg(LPC17_USBHOST_CMDST); + regval |= OHCI_CMDST_BLF; + lpc17_putreg(regval, LPC17_USBHOST_CMDST); + + /* BulkListEnable. This bit is set to enable the processing of the Bulk + * list. Note: once enabled, it remains enabled and we may even + * complete list processing before we get the bit set. We really + * should never modify the bulk list while BLE is set. + */ - 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 TD completion status bits */ - if (priv->tdstatus == TD_CC_NOERROR) - { - ret = OK; - } - else - { - uvdbg("Bad TD completion status: %d\n", priv->tdstatus); - ret = -EIO; + if (priv->tdstatus == TD_CC_NOERROR) + { + ret = OK; + } + else + { + uvdbg("Bad TD completion status: %d\n", priv->tdstatus); + ret = -EIO; + } } errout: + /* Make sure that there is no outstanding request on this endpoint */ + + priv->wdhwait = false; + /* Free any temporary IO buffers */ #if LPC17_IOBUFFERS > 0 @@ -1676,10 +1809,22 @@ FAR struct usbhost_driver_s *usbhost_initialize(int controller) udbg("Initializing Host Stack\n"); + /* Show AHB SRAM memory map */ + +#if 0 /* Useful if you have doubts about the layout */ + uvdbg("AHB SRAM:\n"); + uvdbg(" HCCA: %08x %d\n", LPC17_HCCA_BASE, LPC17_HCCA_SIZE); + uvdbg(" TDTAIL: %08x %d\n", LPC17_TDTAIL_ADDR, LPC17_TD_SIZE); + uvdbg(" EDCTRL: %08x %d\n", LPC17_EDCTRL_ADDR, LPC17_ED_SIZE); + uvdbg(" EDFREE: %08x %d\n", LPC17_EDFREE_BASE, LPC17_ED_SIZE); + uvdbg(" TDFREE: %08x %d\n", LPC17_TDFREE_BASE, LPC17_EDFREE_SIZE); + uvdbg(" TBFREE: %08x %d\n", LPC17_TBFREE_BASE, LPC17_TBFREE_SIZE); + uvdbg(" IOFREE: %08x %d\n", LPC17_IOFREE_BASE, LPC17_IOBUFFERS * CONFIG_USBHOST_IOBUFSIZE); +#endif + /* Initialize all the TDs, EDs and HCCA to 0 */ memset((void*)HCCA, 0, sizeof(struct ohci_hcca_s)); - memset((void*)TDHEAD, 0, sizeof(struct ohci_gtd_s)); memset((void*)TDTAIL, 0, sizeof(struct ohci_gtd_s)); memset((void*)EDCTRL, 0, sizeof(struct lpc17_ed_s)); @@ -1692,14 +1837,23 @@ FAR struct usbhost_driver_s *usbhost_initialize(int controller) lpc17_epfree(&priv->drvr, (usbhost_ep_t)&EDFREE[i]); } - /* Initialize user-configurable TD buffers */ + /* Initialize user-configurable TDs */ + + for (i = 0; i < CONFIG_USBHOST_NTDS; i++) + { + /* Put the ED in a free list */ + + lpc17_tdfree(priv, &TDFREE[i]); + } + + /* Initialize user-configurable request/descriptor transfer buffers */ - buffer = TDFREE; + buffer = TBFREE; for (i = 0; i < CONFIG_USBHOST_NEDS; i++) { /* Put the TD buffer in a free list */ - lpc17_tdfree(priv, buffer); + lpc17_tbfree(priv, buffer); buffer += CONFIG_USBHOST_TDBUFSIZE; } diff --git a/nuttx/configs/mbed/README.txt b/nuttx/configs/mbed/README.txt index c4122a6f6..14ebc2309 100755 --- a/nuttx/configs/mbed/README.txt +++ b/nuttx/configs/mbed/README.txt @@ -327,6 +327,8 @@ mbed Configuration Options Total size of OHCI RAM (in AHB SRAM Bank 1)
CONFIG_USBHOST_NEDS
Number of endpoint descriptors
+ CONFIG_USBHOST_NTDS
+ Number of transfer descriptors
CONFIG_USBHOST_TDBUFFERS
Number of transfer descriptor buffers
CONFIG_USBHOST_TDBUFSIZE
diff --git a/nuttx/configs/nucleus2g/README.txt b/nuttx/configs/nucleus2g/README.txt index 42be0f1bf..8752078fc 100755 --- a/nuttx/configs/nucleus2g/README.txt +++ b/nuttx/configs/nucleus2g/README.txt @@ -439,6 +439,8 @@ Nucleus 2G Configuration Options Total size of OHCI RAM (in AHB SRAM Bank 1)
CONFIG_USBHOST_NEDS
Number of endpoint descriptors
+ CONFIG_USBHOST_NTDS
+ Number of transfer descriptors
CONFIG_USBHOST_TDBUFFERS
Number of transfer descriptor buffers
CONFIG_USBHOST_TDBUFSIZE
diff --git a/nuttx/configs/nucleus2g/nsh/defconfig b/nuttx/configs/nucleus2g/nsh/defconfig index 408fdbc1f..70a183452 100755 --- a/nuttx/configs/nucleus2g/nsh/defconfig +++ b/nuttx/configs/nucleus2g/nsh/defconfig @@ -627,6 +627,8 @@ CONFIG_LPC17_USBDEV_DMAINTMASK=0 # Total size of OHCI RAM (in AHB SRAM Bank 1) # CONFIG_USBHOST_NEDS # Number of endpoint descriptors +# CONFIG_USBHOST_NTDS +# Number of transfer descriptors # CONFIG_USBHOST_TDBUFFERS # Number of transfer descriptor buffers # CONFIG_USBHOST_TDBUFSIZE @@ -634,8 +636,9 @@ CONFIG_LPC17_USBDEV_DMAINTMASK=0 # CONFIG_USBHOST_IOBUFSIZE # Size of one end-user I/O buffer # -CONFIG_USBHOST_OHCIRAM_SIZE=1280 +CONFIG_USBHOST_OHCIRAM_SIZE=1536 CONFIG_USBHOST_NEDS=2 +CONFIG_USBHOST_NTDS=2 CONFIG_USBHOST_TDBUFFERS=3 CONFIG_USBHOST_TDBUFSIZE=128 CONFIG_USBHOST_IOBUFSIZE=512 diff --git a/nuttx/configs/olimex-lpc1766stk/README.txt b/nuttx/configs/olimex-lpc1766stk/README.txt index eae9685ea..bf0e7b592 100755 --- a/nuttx/configs/olimex-lpc1766stk/README.txt +++ b/nuttx/configs/olimex-lpc1766stk/README.txt @@ -684,6 +684,8 @@ Olimex LPC1766-STK Configuration Options Total size of OHCI RAM (in AHB SRAM Bank 1)
CONFIG_USBHOST_NEDS
Number of endpoint descriptors
+ CONFIG_USBHOST_NTDS
+ Number of transfer descriptors
CONFIG_USBHOST_TDBUFFERS
Number of transfer descriptor buffers
CONFIG_USBHOST_TDBUFSIZE
diff --git a/nuttx/configs/olimex-lpc1766stk/nsh/defconfig b/nuttx/configs/olimex-lpc1766stk/nsh/defconfig index 12a751cec..ffbda051f 100755 --- a/nuttx/configs/olimex-lpc1766stk/nsh/defconfig +++ b/nuttx/configs/olimex-lpc1766stk/nsh/defconfig @@ -633,6 +633,8 @@ CONFIG_LPC17_USBDEV_DMAINTMASK=0 # Total size of OHCI RAM (in AHB SRAM Bank 1) # CONFIG_USBHOST_NEDS # Number of endpoint descriptors +# CONFIG_USBHOST_NTDS +# Number of transfer descriptors # CONFIG_USBHOST_TDBUFFERS # Number of transfer descriptor buffers # CONFIG_USBHOST_TDBUFSIZE @@ -640,8 +642,9 @@ CONFIG_LPC17_USBDEV_DMAINTMASK=0 # CONFIG_USBHOST_IOBUFSIZE # Size of one end-user I/O buffer # -CONFIG_USBHOST_OHCIRAM_SIZE=1280 +CONFIG_USBHOST_OHCIRAM_SIZE=1536 CONFIG_USBHOST_NEDS=2 +CONFIG_USBHOST_NTDS=3 CONFIG_USBHOST_TDBUFFERS=3 CONFIG_USBHOST_TDBUFSIZE=128 CONFIG_USBHOST_IOBUFSIZE=512 diff --git a/nuttx/include/nuttx/usb/usbhost.h b/nuttx/include/nuttx/usb/usbhost.h index 6e2bff3e0..3e1f642c8 100644 --- a/nuttx/include/nuttx/usb/usbhost.h +++ b/nuttx/include/nuttx/usb/usbhost.h @@ -275,9 +275,9 @@ * Name: DRVR_ALLOC * * Description: - * Some hardware supports special memory in which transfer descriptors can + * Some hardware supports special memory in which request and descriptor data can * be accessed more efficiently. This method provides a mechanism to allocate - * the transfer descriptor memory. If the underlying hardware does not support + * the request/descriptor memory. If the underlying hardware does not support * such "special" memory, this functions may simply map to malloc. * * Input Parameters: @@ -303,9 +303,9 @@ * Name: DRVR_FREE * * Description: - * Some hardware supports special memory in which transfer descriptors can + * Some hardware supports special memory in which request and descriptor data can * be accessed more efficiently. This method provides a mechanism to free that - * transfer descriptor memory. If the underlying hardware does not support + * request/descriptor memory. If the underlying hardware does not support * such "special" memory, this functions may simply map to free(). * * Input Parameters: |