summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-01-11 01:41:06 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2011-01-11 01:41:06 +0000
commit042da0c84ccdc86ff3085f2a8f18fe33fa7b65c7 (patch)
treec80571a4de9598d4ce27ee418f19ec4e4aa1c1d2
parenta236d30ab4764c205dea249a82f790730902d62a (diff)
downloadnuttx-042da0c84ccdc86ff3085f2a8f18fe33fa7b65c7.tar.gz
nuttx-042da0c84ccdc86ff3085f2a8f18fe33fa7b65c7.tar.bz2
nuttx-042da0c84ccdc86ff3085f2a8f18fe33fa7b65c7.zip
Improve endpoint management
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3240 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/ChangeLog3
-rw-r--r--nuttx/Documentation/NuttX.html71
-rwxr-xr-xnuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h8
-rwxr-xr-xnuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c244
-rwxr-xr-xnuttx/configs/nucleus2g/README.txt4
-rwxr-xr-xnuttx/configs/olimex-lpc1766stk/README.txt4
-rw-r--r--nuttx/drivers/usbhost/usbhost_storage.c511
-rw-r--r--nuttx/include/nuttx/usb/usbhost.h90
8 files changed, 520 insertions, 415 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index d6a03b732..1d781751f 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -1405,7 +1405,7 @@
* include/nuttx/spi.h -- the SPI_SETBITS macro was calling the setmode method.
This is a very important bug-fix in some usages.
-5.16 2011-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
+5.16 2011-01-10 Gregory Nutt <spudmonkey@racsa.co.cr>
* include/nuttx/usb -- Created new directory. Moved all usb-related header
files to this new directory. Created a skeleton for a new USB host header
@@ -1418,3 +1418,4 @@
* drivers/usbhost -- Add a USB host class driver for the (Bulk-Only) USB
Mass Storage Class.
+5.17 2011-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html
index 34bdedec5..011f69b63 100644
--- a/nuttx/Documentation/NuttX.html
+++ b/nuttx/Documentation/NuttX.html
@@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
- <p>Last Updated: January 9, 2011</p>
+ <p>Last Updated: January 10, 2011</p>
</td>
</tr>
</table>
@@ -1969,50 +1969,18 @@ Other memory:
</table>
<ul><pre>
-5.15 2010-12-12 Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
-
- * net/uip/uip_tcpaddsend.c and net/send.c -- Another place where the TCP sequence
- number problem &quot;fixed&quot; in 5.14 might occur.
- * net/send.c -- Check if the destination IP address is in the ARP table. If
- not, then don't consider the packet sent. It won't be, an ARP packet will go
- out instead. This improves behavior, for example, on the first GET request
- from a browser.
- * arch/arm/src/lpc17xx/lpc17_emacram.h and lpc17_allocateheap.c -- The Ethernet
- logic was using all of AHB SRAM Bank0 for Ethernet packet buffers (16Kb). An
- option was added to limit the amount of SRAM used for packet buffering and to
- re-use any extra Bank0 memory for heap. configs/olimex-lpc1766stk/nettest
- now uses only 8Kb at the beginning of Bank0; the 8Kb at the end of Bank0 is
- included in the heap
- * arch/arm/src/lpc17xx/lpc17_ssp.c -- Fix compilation errors when SSP1 is
- selected.
- * configs/olimex-lpc1766stk/nsh -- Enable network and SD/MMC card support in
- NSH. Networking and telnetd interface as well as SPI-based microSD are
- now functional.
- * examples/nsh/nsh_netinit.c -- Fix NSH bug. If CONFIG_NET is selected, but
- CONFIG_EXAMPLES_NSH_TELNETD is not selected, then the network is never
- initialized and bad things happen if you try to ping.
- * drivers/lcd -- Add header files for the Phillips PCF8833 LCD controller and
- for the Epson S1D15G10 LCD controller. A driver for the Nokia 6100 LCD is
- coming.
- * include/nuttx/spi.h and almost all other SPI files -- Added an optional
- cmddata() method to the SPI interface. Some devices require an additional
- out-of-band bit to specify if the next word sent to the device is a command
- or data. This is typical, for example, in &quot;9-bit&quot; displays where the 9th bit
- is the CMD/DATA bit. The cmddata method provides selection of command or data.
- * drivers/lcd/p14201.c -- Now uses the cmddata() method of the SPI interface.
- * arch/arm/src/lpc17xx/lpc17_usbdev.c -- LPC17xx USB driver now appears to
- to be fully functional. examples/usbstorage configuration verified (the
- examples/usbserial configuration is untested).
- * drivers/usbdev/usbserial.c and usbstorage.c -- All USB class drivers need
- to call DEV_CONNECT() when they are ready to be enumerated. That is,
- (1) initially when bound to the USB driver, and (2) after a USB reset.
- * drivers/lcd/nokia6100.c -- A driver for the Nokia 6100 LCD. This driver
- has not be verified as of the initial check-in.
- * configs/olimex-lpc1766stk/nx -- A NX graphics configuration for the Olimex
- LPC1766-STK board using the Nokia 6100 LCD driver. This configuration has
- not been verified as of the initial check-in.
- * include/nuttx/spi.h -- the SPI_SETBITS macro was calling the setmode method.
- This is a very important bug-fix in some usages.
+nuttx-5.16 2011-01-10 Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
+
+ * include/nuttx/usb -- Created new directory. Moved all usb-related header
+ files to this new directory. Created a skeleton for a new USB host header
+ file
+ * drivers/usbhost -- Add USB host "registry" where connect devices can be
+ matched with the correct USB class driver.
+ * arc/arc/src/lpc17xx/lpc17_usbhost.c -- Add a simple USB host driver for
+ the NXP lpc17xx.
+ * drivers/usbhost -- Add generic USB device enumeration logic.
+ * drivers/usbhost -- Add a USB host class driver for the (Bulk-Only) USB
+ Mass Storage Class.
pascal-2.0 2009-12-21 Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
@@ -2042,18 +2010,7 @@ buildroot-1.8 2009-12-21 &lt;spudmonkey@racsa.co.cr&gt;
</table>
<ul><pre>
-nuttx-5.16 2011-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
-
- * include/nuttx/usb -- Created new directory. Moved all usb-related header
- files to this new directory. Created a skeleton for a new USB host header
- file
- * drivers/usbhost -- Add USB host "registry" where connect devices can be
- matched with the correct USB class driver.
- * arc/arc/src/lpc17xx/lpc17_usbhost.c -- Add a simple USB host driver for
- the NXP lpc17xx.
- * drivers/usbhost -- Add generic USB device enumeration logic.
- * drivers/usbhost -- Add a USB host class driver for the (Bulk-Only) USB
- Mass Storage Class.
+nuttx-5.17 2011-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
pascal-2.1 2010-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h b/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h
index d2fc11248..0e9f81ecb 100755
--- a/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h
+++ b/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h
@@ -214,10 +214,10 @@
/* Finally, use the remainder of the allocated OHCI for IO buffers */
-#define LPC17_IOBUFFERS ((LPC17_OHCIRAM_END - LPC17_IOFREE_BASE) / CONFIG_USBHOST_IOBUFSIZE)
-
-#if LPC17_IOBUFFERS < 1
-# warning "No IO buffers allocated"
+#if CONFIG_USBHOST_IOBUFSIZE > 0
+# define LPC17_IOBUFFERS ((LPC17_OHCIRAM_END - LPC17_IOFREE_BASE) / CONFIG_USBHOST_IOBUFSIZE)
+#else
+# define LPC17_IOBUFFERS 0
#endif
/************************************************************************************
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c
index 950a0ffe7..917ecd2e5 100755
--- a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c
+++ b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c
@@ -71,15 +71,13 @@
* 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.
+/* All I/O buffers must lie in AHB SRAM because of the OHCI DMA. It might be
+ * okay if no I/O buffers are used *IF* the application can guarantee that all
+ * end-user I/O buffers reside in AHB SRAM.
*/
-#define CONFIG_UBHOST_AHBIOBUFFERS 1
-
-#if defined(CONFIG_UBHOST_AHBIOBUFFERS) && LPC17_IOBUFFERS < 1
-# error "No IO buffers allocated"
+#if LPC17_IOBUFFERS < 1
+# warning "No IO buffers allocated"
#endif
/* Frame Interval / Periodic Start */
@@ -206,11 +204,9 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val);
/* Descriptor helper functions *************************************************/
-static struct ohci_ed_s *lpc17_edalloc(struct lpc17_usbhost_s *priv);
-static void lpc17_edfree(struct lpc17_usbhost_s *priv, struct ohci_ed_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
+#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
@@ -230,6 +226,9 @@ static int lpc17_wait(FAR struct usbhost_driver_s *drvr, bool connected);
static int lpc17_enumerate(FAR struct usbhost_driver_s *drvr);
static int lpc17_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
uint16_t maxpacketsize);
+static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr,
+ const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep);
+static int lpc17_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep);
static int lpc17_alloc(FAR struct usbhost_driver_s *drvr,
FAR uint8_t **buffer, FAR size_t *maxlen);
static int lpc17_free(FAR struct usbhost_driver_s *drvr, FAR uint8_t *buffer);
@@ -239,8 +238,7 @@ static int lpc17_ctrlin(FAR struct usbhost_driver_s *drvr,
static int lpc17_ctrlout(FAR struct usbhost_driver_s *drvr,
FAR const struct usb_ctrlreq_s *req,
FAR const uint8_t *buffer);
-static int lpc17_transfer(FAR struct usbhost_driver_s *drvr,
- FAR struct usbhost_epdesc_s *ed,
+static int lpc17_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
FAR uint8_t *buffer, size_t buflen);
static void lpc17_disconnect(FAR struct usbhost_driver_s *drvr);
@@ -266,6 +264,8 @@ static struct lpc17_usbhost_s g_usbhost =
.wait = lpc17_wait,
.enumerate = lpc17_enumerate,
.ep0configure = lpc17_ep0configure,
+ .epalloc = lpc17_epalloc,
+ .epfree = lpc17_epfree,
.alloc = lpc17_alloc,
.free = lpc17_free,
.ctrlin = lpc17_ctrlin,
@@ -280,7 +280,7 @@ static struct lpc17_usbhost_s g_usbhost =
static struct lpc17_edlist_s *g_edfree;
static struct lpc17_buflist_s *g_tdfree;
-#ifdef CONFIG_UBHOST_AHBIOBUFFERS
+#if LPC17_IOBUFFERS > 0
static struct lpc17_buflist_s *g_iofree;
#endif
@@ -465,39 +465,6 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val)
}
/*******************************************************************************
- * Name: lpc17_edalloc
- *
- * Description:
- * Allocate an ED from the free list
- *
- *******************************************************************************/
-
-static struct ohci_ed_s *lpc17_edalloc(struct lpc17_usbhost_s *priv)
-{
- struct ohci_ed_s *ret = (struct ohci_ed_s *)g_edfree;
- if (ret)
- {
- g_edfree = ((struct lpc17_edlist_s*)ret)->flink;
- }
- return ret;
-}
-
-/*******************************************************************************
- * Name: lpc17_edfree
- *
- * Description:
- * Return an ED to the free list
- *
- *******************************************************************************/
-
-static void lpc17_edfree(struct lpc17_usbhost_s *priv, struct ohci_ed_s *ed)
-{
- struct lpc17_edlist_s *edfree = (struct lpc17_edlist_s *)ed;
- edfree->flink = g_edfree;
- g_edfree = edfree;
-}
-
-/*******************************************************************************
* Name: lpc17_tdalloc
*
* Description:
@@ -550,7 +517,7 @@ static void lpc17_tdfree(struct lpc17_usbhost_s *priv, uint8_t *buffer)
*
*******************************************************************************/
-#ifdef CONFIG_UBHOST_AHBIOBUFFERS
+#if LPC17_IOBUFFERS > 0
static uint8_t *lpc17_ioalloc(struct lpc17_usbhost_s *priv)
{
uint8_t *ret = (uint8_t *)g_iofree;
@@ -570,7 +537,7 @@ static uint8_t *lpc17_ioalloc(struct lpc17_usbhost_s *priv)
*
*******************************************************************************/
-#ifdef CONFIG_UBHOST_AHBIOBUFFERS
+#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;
@@ -1067,6 +1034,104 @@ static int lpc17_ep0configure(FAR struct usbhost_driver_s *drvr, uint8_t funcadd
return OK;
}
+/************************************************************************************
+ * Name: lpc17_epalloc
+ *
+ * Description:
+ * Allocate and configure one endpoint.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * epdesc - Describes the endpoint to be allocated.
+ * ep - A memory location provided by the caller in which to receive the
+ * allocated endpoint desciptor.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int lpc17_epalloc(FAR struct usbhost_driver_s *drvr,
+ const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep)
+{
+ struct ohci_ed_s *ed;
+ int ret = -ENOMEM;
+
+ DEBUGASSERT(epdesc && ep);
+
+ /* Take the next ED from the beginning of the free list */
+
+ ed = (struct ohci_ed_s *)g_edfree;
+ if (ed)
+ {
+ /* Remove the ED from the freelist */
+
+ g_edfree = ((struct lpc17_edlist_s*)ed)->flink;
+
+ /* Configure the endpoint descriptor. */
+
+ lpc17_edinit(ed);
+ ed->ctrl = (uint32_t)(epdesc->funcaddr) << ED_CONTROL_FA_SHIFT |
+ (uint32_t)(epdesc->addr) << ED_CONTROL_EN_SHIFT |
+ (uint32_t)(epdesc->mxpacketsize) << ED_CONTROL_MPS_SHIFT;
+
+ /* Get the direction of the endpoint */
+
+ if (epdesc->in != 0)
+ {
+ ed->ctrl |= ED_CONTROL_D_IN;
+ }
+ else
+ {
+ ed->ctrl |= ED_CONTROL_D_OUT;
+ }
+
+ /* Return an opaque reference to the ED */
+
+ *ep = (usbhost_ep_t)ed;
+ ret = OK;
+ }
+ return ret;
+}
+
+/************************************************************************************
+ * Name: lpc17_epfree
+ *
+ * Description:
+ * Free and endpoint previously allocated by DRVR_EPALLOC.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * ep - The endpint to be freed.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+static int lpc17_epfree(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
+{
+ struct lpc17_edlist_s *ed = (struct lpc17_edlist_s *)ep;
+
+ DEBUGASSERT(ed);
+
+ /* Put the ED back into the free list */
+
+ ed->flink = g_edfree;
+ g_edfree = ed;
+ return OK;
+}
+
/*******************************************************************************
* Name: lpc17_alloc
*
@@ -1251,7 +1316,7 @@ static int lpc17_ctrlout(FAR struct usbhost_driver_s *drvr,
* Input Parameters:
* drvr - The USB host driver instance obtained as a parameter from the call to
* the class create() method.
- * ed - The IN or OUT endpoint descriptor for the device endpoint on which to
+ * ep - The IN or OUT endpoint descriptor for the device endpoint on which to
* perform the transfer.
* buffer - A buffer containing the data to be sent (OUT endpoint) or received
* (IN endpoint). buffer must have been allocated using DRVR_ALLOC
@@ -1268,26 +1333,32 @@ static int lpc17_ctrlout(FAR struct usbhost_driver_s *drvr,
*
*******************************************************************************/
-static int lpc17_transfer(FAR struct usbhost_driver_s *drvr,
- FAR struct usbhost_epdesc_s *ep,
+static int lpc17_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
FAR uint8_t *buffer, size_t buflen)
{
struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr;
- struct ohci_ed_s *ed = NULL;
+ struct ohci_ed_s *ed = (struct ohci_ed_s *)ep;
uint32_t dirpid;
uint32_t regval;
-#ifdef CONFIG_UBHOST_AHBIOBUFFERS
+#if LPC17_IOBUFFERS > 0
uint8_t *origbuf = NULL;
#endif
+ bool in;
int ret;
- DEBUGASSERT(drvr && ep && buffer && buflen > 0);
+ DEBUGASSERT(priv && ed && buffer && buflen > 0);
+
+ in = (ed->ctrl & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN;
uvdbg("EP%d %s toggle:%d maxpacket:%d buflen:%d\n",
- ep->addr, ep->in ? "IN" : "OUT", ep->toggle, ep->mxpacketsize, buflen);
+ (ed->ctrl & ED_CONTROL_EN_MASK) >> ED_CONTROL_EN_SHIFT,
+ in ? "IN" : "OUT",
+ (ed->headp & ED_HEADP_C) != 0 ? 1 : 0,
+ (ed->ctrl & ED_CONTROL_MPS_MASK) >> ED_CONTROL_MPS_SHIFT,
+ buflen);
/* Allocate an IO buffer if the user buffer does not lie in AHB SRAM */
-#ifdef CONFIG_UBHOST_AHBIOBUFFERS
+#if LPC17_IOBUFFERS > 0
if ((uintptr_t)buffer < LPC17_SRAM_BANK0 ||
(uintptr_t)buffer >= (LPC17_SRAM_BANK0 + LPC17_BANK0_SIZE + LPC17_BANK1_SIZE))
{
@@ -1318,7 +1389,7 @@ static int lpc17_transfer(FAR struct usbhost_driver_s *drvr,
* way around this copy.
*/
- if (ep->in == 0)
+ if (!in)
{
memcpy(buffer, origbuf, buflen);
}
@@ -1336,45 +1407,17 @@ static int lpc17_transfer(FAR struct usbhost_driver_s *drvr,
goto errout;
}
- /* Allocate an ED */
-
- ed = lpc17_edalloc(priv);
- if (!ed)
- {
- udbg("ED allocation failed\n");
- ret = -ENOMEM;
- goto errout;
- }
-
- /* Format the endpoint descriptor. This could be a lot simpler if
- * the OHCI ED structure were exposed outside of the driver.
- */
-
- lpc17_edinit(ed);
- ed->ctrl = (uint32_t)(ep->funcaddr) << ED_CONTROL_FA_SHIFT |
- (uint32_t)(ep->addr) << ED_CONTROL_EN_SHIFT |
- (uint32_t)(ep->mxpacketsize) << ED_CONTROL_MPS_SHIFT;
-
/* Get the direction of the endpoint */
- if (ep->in != 0)
+ if (in)
{
- ed->ctrl |= ED_CONTROL_D_IN;
dirpid = GTD_STATUS_DP_IN;
}
else
{
- ed->ctrl |= ED_CONTROL_D_OUT;
dirpid = GTD_STATUS_DP_OUT;
}
- /* Set/restore the toggle carry bit */
-
- if (ep->toggle)
- {
- ed->headp = ED_HEADP_C;
- }
-
/* Then enqueue the transfer */
priv->tdstatus = TD_CC_NOERROR;
@@ -1420,24 +1463,10 @@ static int lpc17_transfer(FAR struct usbhost_driver_s *drvr,
ret = -EIO;
}
- /* Save the toggle carry bit. This bit is updated each time that an
- * ED is retired. This could be a lot simpler if the OHCI ED structure
- * were exposed outside of the driver.
- */
-
- if ((ed->headp & ED_HEADP_C) != 0)
- {
- ep->toggle = 1;
- }
- else
- {
- ep->toggle = 0;
- }
-
errout:
/* Free any temporary IO buffers */
-#ifdef CONFIG_UBHOST_AHBIOBUFFERS
+#if LPC17_IOBUFFERS > 0
if (buffer && origbuf)
{
/* If this is an IN transaction, get the user data from the AHB
@@ -1446,7 +1475,7 @@ errout:
* way around this copy.
*/
- if (ep->in != 0 && ret == OK)
+ if (in && ret == OK)
{
memcpy(origbuf, buffer, buflen);
}
@@ -1457,13 +1486,6 @@ errout:
}
#endif
- /* Free the endpoint descriptor */
-
- if (ed)
- {
- lpc17_edfree(priv, ed);
- }
-
return ret;
}
@@ -1644,7 +1666,7 @@ FAR struct usbhost_driver_s *usbhost_initialize(int controller)
{
/* Put the ED in a free list */
- lpc17_edfree(priv, &EDFREE[i]);
+ lpc17_epfree(&priv->drvr, (usbhost_ep_t)&EDFREE[i]);
}
/* Initialize user-configurable TD buffers */
@@ -1658,7 +1680,7 @@ FAR struct usbhost_driver_s *usbhost_initialize(int controller)
buffer += CONFIG_USBHOST_TDBUFSIZE;
}
-#ifdef CONFIG_UBHOST_AHBIOBUFFERS
+#if LPC17_IOBUFFERS > 0
/* Initialize user-configurable IO buffers */
buffer = IOFREE;
diff --git a/nuttx/configs/nucleus2g/README.txt b/nuttx/configs/nucleus2g/README.txt
index 21b04a08f..4d88654c5 100755
--- a/nuttx/configs/nucleus2g/README.txt
+++ b/nuttx/configs/nucleus2g/README.txt
@@ -443,7 +443,9 @@ Nucleus 2G Configuration Options
CONFIG_USBHOST_TDBUFSIZE
Size of one transfer descriptor buffer
CONFIG_USBHOST_IOBUFSIZE
- Size of one end-user I/O buffer
+ Size of one end-user I/O buffer. This can be zero if the
+ application can guarantee that all end-user I/O buffers
+ reside in AHB SRAM.
USB Host Configuration
^^^^^^^^^^^^^^^^^^^^^^
diff --git a/nuttx/configs/olimex-lpc1766stk/README.txt b/nuttx/configs/olimex-lpc1766stk/README.txt
index cd7a1ca49..eae9685ea 100755
--- a/nuttx/configs/olimex-lpc1766stk/README.txt
+++ b/nuttx/configs/olimex-lpc1766stk/README.txt
@@ -689,7 +689,9 @@ Olimex LPC1766-STK Configuration Options
CONFIG_USBHOST_TDBUFSIZE
Size of one transfer descriptor buffer
CONFIG_USBHOST_IOBUFSIZE
- Size of one end-user I/O buffer
+ Size of one end-user I/O buffer. This can be zero if the
+ application can guarantee that all end-user I/O buffers
+ reside in AHB SRAM.
USB Host Configuration
^^^^^^^^^^^^^^^^^^^^^^
diff --git a/nuttx/drivers/usbhost/usbhost_storage.c b/nuttx/drivers/usbhost/usbhost_storage.c
index c13e32bb8..e0f4dc4ad 100644
--- a/nuttx/drivers/usbhost/usbhost_storage.c
+++ b/nuttx/drivers/usbhost/usbhost_storage.c
@@ -129,8 +129,8 @@ struct usbhost_state_s
struct work_s work; /* For interacting with the worker thread */
FAR uint8_t *tdbuffer; /* The allocated transfer descriptor buffer */
size_t tdbuflen; /* Size of the allocated transfer buffer */
- struct usbhost_epdesc_s bulkin; /* Bulk IN endpoint */
- struct usbhost_epdesc_s bulkout; /* Bulk OUT endpoint */
+ usbhost_ep_t bulkin; /* Bulk IN endpoint */
+ usbhost_ep_t bulkout; /* Bulk OUT endpoint */
};
/****************************************************************************
@@ -186,8 +186,10 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv);
/* Worker thread actions */
static void usbhost_destroy(FAR void *arg);
-static void usbhost_initvolume(FAR void *arg);
-static void usbhost_work(FAR struct usbhost_state_s *priv, worker_t worker);
+static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
+ FAR const uint8_t *configdesc, int desclen,
+ uint8_t funcaddr);
+static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv);
/* (Little Endian) Data helpers */
@@ -690,13 +692,13 @@ static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv)
/* Construct and send the CBW */
usbhost_testunitreadycbw(cbw);
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
if (result == OK)
{
/* Receive the CSW */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
@@ -723,19 +725,19 @@ static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv)
/* Construct and send the CBW */
usbhost_requestsensecbw(cbw);
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
if (result == OK)
{
/* Receive the sense data response */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF);
if (result == OK)
{
/* Receive the CSW */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
@@ -765,13 +767,13 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv)
/* Construct and send the CBW */
usbhost_readcapacitycbw(cbw);
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
if (result == OK)
{
/* Receive the read capacity CBW IN response */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, SCSIRESP_READCAPACITY10_SIZEOF);
if (result == OK)
{
@@ -783,7 +785,7 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv)
/* Receive the CSW */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
@@ -813,13 +815,13 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
/* Construct and send the CBW */
usbhost_inquirycbw(cbw);
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
if (result == OK)
{
/* Receive the CBW IN response */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, SCSIRESP_INQUIRY_SIZEOF);
if (result == OK)
{
@@ -829,7 +831,7 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
/* Receive the CSW */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
@@ -874,6 +876,18 @@ static void usbhost_destroy(FAR void *arg)
usbhost_freedevno(priv);
+ /* Free the bulk endpoints */
+
+ if (priv->bulkout)
+ {
+ DRVR_EPFREE(priv->drvr, priv->bulkout);
+ }
+
+ if (priv->bulkin)
+ {
+ DRVR_EPFREE(priv->drvr, priv->bulkin);
+ }
+
/* Free any transfer buffers */
usbhost_tdfree(priv);
@@ -896,6 +910,198 @@ static void usbhost_destroy(FAR void *arg)
}
/****************************************************************************
+ * Name: usbhost_cfgdesc
+ *
+ * Description:
+ * This function implements the connect() method of struct
+ * usbhost_class_s. This method is a callback into the class
+ * implementation. It is used to provide the device's configuration
+ * descriptor to the class so that the class may initialize properly
+ *
+ * Input Parameters:
+ * priv - The USB host class instance.
+ * configdesc - A pointer to a uint8_t buffer container the configuration descripor.
+ * desclen - The length in bytes of the configuration descriptor.
+ * funcaddr - The USB address of the function containing the endpoint that EP0
+ * controls
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ****************************************************************************/
+
+static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
+ FAR const uint8_t *configdesc, int desclen,
+ uint8_t funcaddr)
+{
+ FAR struct usb_cfgdesc_s *cfgdesc;
+ FAR struct usb_desc_s *desc;
+ FAR struct usbhost_epdesc_s bindesc;
+ FAR struct usbhost_epdesc_s boutdesc;
+ int remaining;
+ uint8_t found = 0;
+ int ret;
+
+ DEBUGASSERT(priv != NULL &&
+ configdesc != NULL &&
+ desclen >= sizeof(struct usb_cfgdesc_s));
+
+ /* Verify that we were passed a configuration descriptor */
+
+ cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
+ if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
+ {
+ return -EINVAL;
+ }
+
+ /* Get the total length of the configuration descriptor (little endian).
+ * It might be a good check to get the number of interfaces here too.
+ */
+
+ remaining = (int)usbhost_getle16(cfgdesc->totallen);
+
+ /* Skip to the next entry descriptor */
+
+ configdesc += cfgdesc->len;
+ remaining -= cfgdesc->len;
+
+ /* Loop where there are more dscriptors to examine */
+
+ while (remaining >= sizeof(struct usb_desc_s))
+ {
+ /* What is the next descriptor? */
+
+ desc = (FAR struct usb_desc_s *)configdesc;
+ switch (desc->type)
+ {
+ /* Interface descriptor. We really should get the number of endpoints
+ * from this descriptor too.
+ */
+
+ case USB_DESC_TYPE_INTERFACE:
+ {
+ DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
+ if ((found & USBHOST_IFFOUND) != 0)
+ {
+ /* Oops.. more than one interface. We don't know what to do with this. */
+
+ return -ENOSYS;
+ }
+ found |= USBHOST_IFFOUND;
+ }
+ break;
+
+ /* Endpoint descriptor. We expect two bulk endpoints, an IN and an OUT */
+ case USB_DESC_TYPE_ENDPOINT:
+ {
+ FAR struct usb_epdesc_s *epdesc = (FAR struct usb_epdesc_s *)configdesc;
+ DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);
+
+ /* Check for a bulk endpoint. We only support the bulk-only
+ * protocol so I suppose anything else should really be an error.
+ */
+
+ if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_BULK)
+ {
+ /* Yes.. it is a bulk endpoint. IN or OUT? */
+
+ if (USB_ISEPOUT(epdesc->addr))
+ {
+ /* It is an OUT bulk endpoint. There should be only one bulk OUT endpoint. */
+
+ if ((found & USBHOST_BOUTFOUND) != 0)
+ {
+ /* Oops.. more than one interface. We don't know what to do with this. */
+
+ return -EINVAL;
+ }
+ found |= USBHOST_BOUTFOUND;
+
+ /* Save the bulk OUT endpoint information */
+
+ boutdesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
+ boutdesc.in = false;
+ boutdesc.funcaddr = funcaddr;
+ boutdesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
+ uvdbg("Bulk OUT EP addr:%d mxpacketsize:%d\n",
+ boutdesc.addr, boutdesc.mxpacketsize);
+ }
+ else
+ {
+ /* It is an IN bulk endpoint. There should be only one bulk IN endpoint. */
+
+ if ((found & USBHOST_BINFOUND) != 0)
+ {
+ /* Oops.. more than one interface. We don't know what to do with this. */
+
+ return -EINVAL;
+ }
+ found |= USBHOST_BINFOUND;
+
+ /* Save the bulk IN endpoint information */
+
+ bindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
+ bindesc.in = 1;
+ bindesc.funcaddr = funcaddr;
+ bindesc.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
+ uvdbg("Bulk IN EP addr:%d mxpacketsize:%d\n",
+ bindesc.addr, bindesc.mxpacketsize);
+ }
+ }
+ }
+ break;
+
+ /* Other descriptors are just ignored for now */
+
+ default:
+ break;
+ }
+
+ /* Increment the address of the next descriptor */
+
+ configdesc += desc->len;
+ remaining -= desc->len;
+ }
+
+ /* Sanity checking... did we find all of things that we need? Hmmm.. I wonder..
+ * can we work read-only or write-only if only one bulk endpoint found?
+ */
+
+ if (found != USBHOST_ALLFOUND)
+ {
+ ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n",
+ (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO",
+ (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO",
+ (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO");
+ return -EINVAL;
+ }
+
+ /* We are good... Allocate the endpoints */
+
+ ret = DRVR_EPALLOC(priv->drvr, &boutdesc, &priv->bulkout);
+ if (ret != OK)
+ {
+ udbg("ERROR: Failed to allocated Bulk OUT endpoint\n");
+ return ret;
+ }
+
+ ret = DRVR_EPALLOC(priv->drvr, &bindesc, &priv->bulkin);
+ if (ret != OK)
+ {
+ udbg("ERROR: Failed to allocated Bulk IN endpoint\n");
+ (void)DRVR_EPFREE(priv->drvr, priv->bulkout);
+ return ret;
+ }
+
+ ullvdbg("Endpoints allocated\n");
+ return OK;
+}
+
+/****************************************************************************
* Name: usbhost_initvolume
*
* Description:
@@ -908,29 +1114,28 @@ static void usbhost_destroy(FAR void *arg)
* connect() was called from an interrupt handler, on the worker thread.
*
* Input Parameters:
- * arg - A reference to the class instance.
+ * priv - A reference to the class instance.
*
* Returned Values:
* None
*
****************************************************************************/
-static void usbhost_initvolume(FAR void *arg)
+static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv)
{
- FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
FAR struct usbstrg_csw_s *csw;
unsigned int retries;
- int result = OK;
+ int ret = OK;
DEBUGASSERT(priv != NULL);
/* Set aside a transfer buffer for exclusive use by the mass storage driver */
- result = usbhost_tdalloc(priv);
- if (result != OK)
+ ret = usbhost_tdalloc(priv);
+ if (ret != OK)
{
udbg("ERROR: Failed to allocate transfer buffer\n");
- return;
+ return ret;
}
/* Increment the reference count. This will prevent usbhost_destroy() from
@@ -943,18 +1148,18 @@ static void usbhost_initvolume(FAR void *arg)
/* Request the maximum logical unit number */
uvdbg("Get max LUN\n");
- result = usbhost_maxlunreq(priv);
+ ret = usbhost_maxlunreq(priv);
/* Wait for the unit to be ready */
- for (retries = 0; retries < USBHOST_MAX_RETRIES && result == OK; retries++)
+ for (retries = 0; retries < USBHOST_MAX_RETRIES && ret == OK; retries++)
{
uvdbg("Test unit ready, retries=%d\n", retries);
/* Send TESTUNITREADY to see the unit is ready */
- result = usbhost_testunitready(priv);
- if (result == OK)
+ ret = usbhost_testunitready(priv);
+ if (ret == OK)
{
/* Is the unit is ready */
@@ -972,7 +1177,7 @@ static void usbhost_initvolume(FAR void *arg)
*/
uvdbg("Request sense\n");
- result = usbhost_requestsense(priv);
+ ret = usbhost_requestsense(priv);
}
}
@@ -981,16 +1186,16 @@ static void usbhost_initvolume(FAR void *arg)
if (retries >= USBHOST_MAX_RETRIES)
{
udbg("ERROR: Timeout!\n");
- result = -ETIMEDOUT;
+ ret = -ETIMEDOUT;
}
- if (result == OK)
+ if (ret == OK)
{
/* Get the capacity of the volume */
uvdbg("Read capacity\n");
- result = usbhost_readcapacity(priv);
- if (result == OK)
+ ret = usbhost_readcapacity(priv);
+ if (ret == OK)
{
/* Check the CSW for errors */
@@ -998,20 +1203,20 @@ static void usbhost_initvolume(FAR void *arg)
if (csw->status != 0)
{
udbg("ERROR: CSW status error: %d\n", csw->status);
- result = -ENODEV;
+ ret = -ENODEV;
}
}
}
/* Get information about the volume */
- if (result == OK)
+ if (ret == OK)
{
/* Inquiry */
uvdbg("Inquiry\n");
- result = usbhost_inquiry(priv);
- if (result == OK)
+ ret = usbhost_inquiry(priv);
+ if (ret == OK)
{
/* Check the CSW for errors */
@@ -1019,20 +1224,20 @@ static void usbhost_initvolume(FAR void *arg)
if (csw->status != 0)
{
udbg("ERROR: CSW status error: %d\n", csw->status);
- result = -ENODEV;
+ ret = -ENODEV;
}
}
}
/* Register the block driver */
- if (result == OK)
+ if (ret == OK)
{
char devname[DEV_NAMELEN];
uvdbg("Register block driver\n");
usbhost_mkdevname(priv, devname);
- result = register_blockdriver(devname, &g_bops, 0, priv);
+ ret = register_blockdriver(devname, &g_bops, 0, priv);
}
/* Check if we successfully initialized. We now have to be concerned
@@ -1040,7 +1245,7 @@ static void usbhost_initvolume(FAR void *arg)
* driver has been registerd.
*/
- if (result == OK)
+ if (ret == OK)
{
usbhost_takesem(&priv->exclsem);
DEBUGASSERT(priv->crefs >= 2);
@@ -1057,7 +1262,7 @@ static void usbhost_initvolume(FAR void *arg)
* destroyed when usb_destroy is called.
*/
- result = -ENODEV;
+ ret = -ENODEV;
}
else
{
@@ -1071,50 +1276,13 @@ static void usbhost_initvolume(FAR void *arg)
/* Disconnect on any errors detected during volume initialization */
- if (result != OK)
+ if (ret != OK)
{
- udbg("ERROR! Aborting: %d\n", result);
+ udbg("ERROR! Aborting: %d\n", ret);
usbhost_destroy(priv);
}
-}
-/****************************************************************************
- * Name: usbhost_work
- *
- * Description:
- * Perform work, depending on context: If we are executing from an
- * interrupt handler, then defer the work to the worker thread. Otherwise,
- * just execute the work now.
- *
- * Input Parameters:
- * priv - A reference to the class instance.
- * worker - A reference to the worker function to be executed
- *
- * Returned Values:
- * None
- *
- ****************************************************************************/
-
-static void usbhost_work(FAR struct usbhost_state_s *priv, worker_t worker)
-{
- /* Are we in an interrupt handler? */
-
- if (up_interrupt_context())
- {
- /* Yes.. do the work on the worker thread. Higher level logic should
- * prevent us from over-running the work structure.
- */
-
- uvdbg("Queuing work: worker %p->%p\n", priv->work.worker, worker);
- DEBUGASSERT(priv->work.worker == NULL);
- (void)work_queue(&priv->work, worker, priv, 0);
- }
- else
- {
- /* No.. do the work now */
-
- worker(priv);
- }
+ return ret;
}
/****************************************************************************
@@ -1474,9 +1642,7 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
* returned indicating the nature of the failure
*
* Assumptions:
- * This function is probably called on the same thread that called the driver
- * enumerate() method. However, this function may also be called from an
- * interrupt handler.
+ * This function will *not* be called from an interrupt handler.
*
****************************************************************************/
@@ -1485,151 +1651,31 @@ static int usbhost_connect(FAR struct usbhost_class_s *class,
uint8_t funcaddr)
{
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
- FAR struct usb_cfgdesc_s *cfgdesc;
- FAR struct usb_desc_s *desc;
- int remaining;
- uint8_t found = 0;
+ int ret;
DEBUGASSERT(priv != NULL &&
configdesc != NULL &&
desclen >= sizeof(struct usb_cfgdesc_s));
-
- /* Verify that we were passed a configuration descriptor */
- cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
- if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
+ /* Parse the configuration descriptor to get the bulk I/O endpoints */
+
+ ret = usbhost_cfgdesc(priv, configdesc, desclen, funcaddr);
+ if (ret != OK)
{
- return -EINVAL;
+ udbg("usbhost_cfgdesc() failed: %d\n", ret);
}
-
- /* Get the total length of the configuration descriptor (little endian).
- * It might be a good check to get the number of interfaces here too.
- */
-
- remaining = (int)usbhost_getle16(cfgdesc->totallen);
-
- /* Skip to the next entry descriptor */
-
- configdesc += cfgdesc->len;
- remaining -= cfgdesc->len;
-
- /* Loop where there are more dscriptors to examine */
-
- while (remaining >= sizeof(struct usb_desc_s))
+ else
{
- /* What is the next descriptor? */
+ /* Now configure the LUNs and register the block driver(s) */
- desc = (FAR struct usb_desc_s *)configdesc;
- switch (desc->type)
+ ret = usbhost_initvolume(priv);
+ if (ret != OK)
{
- /* Interface descriptor. We really should get the number of endpoints
- * from this descriptor too.
- */
-
- case USB_DESC_TYPE_INTERFACE:
- {
- DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
- if ((found & USBHOST_IFFOUND) != 0)
- {
- /* Oops.. more than one interface. We don't know what to do with this. */
-
- return -ENOSYS;
- }
- found |= USBHOST_IFFOUND;
- }
- break;
-
- /* Endpoint descriptor. We expect two bulk endpoints, an IN and an OUT */
- case USB_DESC_TYPE_ENDPOINT:
- {
- FAR struct usb_epdesc_s *epdesc = (FAR struct usb_epdesc_s *)configdesc;
- DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);
-
- /* Check for a bulk endpoint. We only support the bulk-only
- * protocol so I suppose anything else should really be an error.
- */
-
- if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) == USB_EP_ATTR_XFER_BULK)
- {
- /* Yes.. it is a bulk endpoint. IN or OUT? */
-
- if (USB_ISEPOUT(epdesc->addr))
- {
- /* It is an OUT bulk endpoint. There should be only one bulk OUT endpoint. */
-
- if ((found & USBHOST_BOUTFOUND) != 0)
- {
- /* Oops.. more than one interface. We don't know what to do with this. */
-
- return -EINVAL;
- }
- found |= USBHOST_BOUTFOUND;
-
- /* Save the bulk OUT endpoint information */
-
- priv->bulkout.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
- priv->bulkout.in = 0;
- priv->bulkout.funcaddr = funcaddr;
- priv->bulkout.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
- uvdbg("Bulk OUT EP addr:%d mxpacketsize:%d\n",
- priv->bulkout.addr, priv->bulkout.mxpacketsize);
- }
- else
- {
- /* It is an IN bulk endpoint. There should be only one bulk IN endpoint. */
-
- if ((found & USBHOST_BINFOUND) != 0)
- {
- /* Oops.. more than one interface. We don't know what to do with this. */
-
- return -EINVAL;
- }
- found |= USBHOST_BINFOUND;
-
- /* Save the bulk IN endpoint information */
-
- priv->bulkin.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
- priv->bulkin.in = 1;
- priv->bulkin.funcaddr = funcaddr;
- priv->bulkin.mxpacketsize = usbhost_getle16(epdesc->mxpacketsize);
- uvdbg("Bulk IN EP addr:%d mxpacketsize:%d\n",
- priv->bulkin.addr, priv->bulkin.mxpacketsize);
- }
- }
- }
- break;
-
- /* Other descriptors are just ignored for now */
-
- default:
- break;
+ udbg("usbhost_initvolume() failed: %d\n", ret);
}
-
- /* Increment the address of the next descriptor */
-
- configdesc += desc->len;
- remaining -= desc->len;
- }
-
- /* Sanity checking... did we find all of things that we need? Hmmm.. I wonder..
- * can we work read-only or write-only if only one bulk endpoint found?
- */
-
- if (found != USBHOST_ALLFOUND)
- {
- ulldbg("ERROR: Found IF:%s BIN:%s BOUT:%s\n",
- (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO",
- (found & USBHOST_BINFOUND) != 0 ? "YES" : "NO",
- (found & USBHOST_BOUTFOUND) != 0 ? "YES" : "NO");
- return -EINVAL;
}
-
- ullvdbg("Mass Storage device connected\n");
-
- /* Now configure the LUNs and register the block driver(s) */
-
- usbhost_work(priv, usbhost_initvolume);
- return OK;
+
+ return ret;
}
/****************************************************************************
@@ -1677,10 +1723,27 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
ullvdbg("crefs: %d\n", priv->crefs);
if (priv->crefs == 1)
{
- /* Destroy the class instance */
+ /* Destroy the class instance. If we are executing from an interrupt
+ * handler, then defer the destruction to the worker thread.
+ * Otherwise, destroy the instance now.
+ */
+
+ if (up_interrupt_context())
+ {
+ /* Destroy the instance on the worker thread. */
- usbhost_work(priv, usbhost_destroy);
+ uvdbg("Queuing destruction: worker %p->%p\n", priv->work.worker, usbhost_destroy);
+ DEBUGASSERT(priv->work.worker == NULL);
+ (void)work_queue(&priv->work, usbhost_destroy, priv, 0);
+ }
+ else
+ {
+ /* Do the work now */
+
+ usbhost_destroy(priv);
+ }
}
+
irqrestore(flags);
return OK;
}
@@ -1845,19 +1908,19 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
/* Construct and send the CBW */
usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw);
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
if (result == OK)
{
/* Receive the user data */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
buffer, priv->blocksize * nsectors);
if (result == OK)
{
/* Receive the CSW */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
@@ -1937,19 +2000,19 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe
/* Construct and send the CBW */
usbhost_writecbw(startsector, priv->blocksize, nsectors, cbw);
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBSTRG_CBW_SIZEOF);
if (result == OK)
{
/* Send the user data */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkout,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)buffer, priv->blocksize * nsectors);
if (result == OK)
{
/* Receive the CSW */
- result = DRVR_TRANSFER(priv->drvr, &priv->bulkin,
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tdbuffer, USBSTRG_CSW_SIZEOF);
if (result == OK)
{
diff --git a/nuttx/include/nuttx/usb/usbhost.h b/nuttx/include/nuttx/usb/usbhost.h
index a83048f68..e69f1814a 100644
--- a/nuttx/include/nuttx/usb/usbhost.h
+++ b/nuttx/include/nuttx/usb/usbhost.h
@@ -139,7 +139,7 @@
* returned indicating the nature of the failure
*
* Assumptions:
- * This function may be called from an interrupt handler.
+ * This function will *not* be called from an interrupt handler.
*
************************************************************************************/
@@ -226,6 +226,52 @@
#define DRVR_EP0CONFIGURE(drvr,funcaddr,mps) ((drvr)->ep0configure(drvr,funcaddr,mps))
/************************************************************************************
+ * Name: DRVR_EPALLOC
+ *
+ * Description:
+ * Allocate and configure one endpoint.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * epdesc - Describes the endpoint to be allocated.
+ * ep - A memory location provided by the caller in which to receive the
+ * allocated endpoint desciptor.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+#define DRVR_EPALLOC(drvr,epdesc,ep) ((drvr)->epalloc(drvr,epdesc,ep))
+
+/************************************************************************************
+ * Name: DRVR_EPFREE
+ *
+ * Description:
+ * Free and endpoint previously allocated by DRVR_EPALLOC.
+ *
+ * Input Parameters:
+ * drvr - The USB host driver instance obtained as a parameter from the call to
+ * the class create() method.
+ * ep - The endpint to be freed.
+ *
+ * Returned Values:
+ * On success, zero (OK) is returned. On a failure, a negated errno value is
+ * returned indicating the nature of the failure
+ *
+ * Assumptions:
+ * This function will *not* be called from an interrupt handler.
+ *
+ ************************************************************************************/
+
+#define DRVR_EPFREE(drvr,ep) ((drvr)->epfree(drvr,ep))
+
+/************************************************************************************
* Name: DRVR_ALLOC
*
* Description:
@@ -441,11 +487,30 @@ struct usbhost_class_s
int (*disconnected)(FAR struct usbhost_class_s *class);
};
+/* This structure describes one endpoint. It is used as an input to the
+ * allocep() method.
+ */
+
+struct usbhost_epdesc_s
+{
+ uint8_t addr; /* Endpoint address */
+ bool in; /* Direction: true->IN */
+ uint8_t funcaddr; /* USB address of function containing endpoint */
+ uint16_t mxpacketsize; /* Max packetsize */
+};
+
+/* This type represents one endpoint configured by the allocep() method.
+ * The actual form is know only internally to the USB host controller
+ * (for example, for an OHCI driver, this would probably be a pointer
+ * to an endpoint descriptor).
+ */
+
+typedef FAR void *usbhost_ep_t;
+
/* struct usbhost_driver_s provides access to the USB host driver from the
* USB host class implementation.
*/
-struct usbhost_epdesc_s;
struct usbhost_driver_s
{
/* Wait for a device to connect or disconnect. */
@@ -472,6 +537,12 @@ struct usbhost_driver_s
int (*ep0configure)(FAR struct usbhost_driver_s *drvr, uint8_t funcaddr,
uint16_t maxpacketsize);
+ /* Allocate and configure an endpoint. */
+
+ int (*epalloc)(FAR struct usbhost_driver_s *drvr,
+ const FAR struct usbhost_epdesc_s *epdesc, usbhost_ep_t *ep);
+ int (*epfree)(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep);
+
/* Some hardware supports special memory in which transfer descriptors can
* be accessed more efficiently. The following methods provide a mechanism
* to allocate and free the transfer descriptor memory. If the underlying
@@ -508,8 +579,7 @@ struct usbhost_driver_s
* transfer has completed.
*/
- int (*transfer)(FAR struct usbhost_driver_s *drvr,
- FAR struct usbhost_epdesc_s *ep,
+ int (*transfer)(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
FAR uint8_t *buffer, size_t buflen);
/* Called by the class when an error occurs and driver has been disconnected.
@@ -521,18 +591,6 @@ struct usbhost_driver_s
void (*disconnect)(FAR struct usbhost_driver_s *drvr);
};
-/* This structure describes one endpoint */
-
-struct usbhost_epdesc_s
-{
- uint8_t addr : 4; /* Endpoint address */
- uint8_t pad : 3;
- uint8_t in : 1; /* Direction: 1->IN */
- uint8_t funcaddr : 7; /* USB address of function containing endpoint */
- uint8_t toggle : 1; /* Last toggle (modified by the driver) */
- uint16_t mxpacketsize; /* Max packetsize */
-};
-
/************************************************************************************
* Public Data
************************************************************************************/