diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-01-11 01:41:06 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2011-01-11 01:41:06 +0000 |
commit | 042da0c84ccdc86ff3085f2a8f18fe33fa7b65c7 (patch) | |
tree | c80571a4de9598d4ce27ee418f19ec4e4aa1c1d2 | |
parent | a236d30ab4764c205dea249a82f790730902d62a (diff) |
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/ChangeLog | 3 | ||||
-rw-r--r-- | nuttx/Documentation/NuttX.html | 71 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h | 8 | ||||
-rwxr-xr-x | nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c | 244 | ||||
-rwxr-xr-x | nuttx/configs/nucleus2g/README.txt | 4 | ||||
-rwxr-xr-x | nuttx/configs/olimex-lpc1766stk/README.txt | 4 | ||||
-rw-r--r-- | nuttx/drivers/usbhost/usbhost_storage.c | 511 | ||||
-rw-r--r-- | nuttx/include/nuttx/usb/usbhost.h | 90 |
8 files changed, 520 insertions, 415 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index d6a03b7320..1d781751f6 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 34bdedec56..011f69b638 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 <spudmonkey@racsa.co.cr> - - * net/uip/uip_tcpaddsend.c and net/send.c -- Another place where the TCP sequence - number problem "fixed" 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 "9-bit" 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 <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 + 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 <spudmonkey@racsa.co.cr> @@ -2042,18 +2010,7 @@ buildroot-1.8 2009-12-21 <spudmonkey@racsa.co.cr> </table> <ul><pre> -nuttx-5.16 2011-xx-xx 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 - 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 <spudmonkey@racsa.co.cr> pascal-2.1 2010-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h b/nuttx/arch/arm/src/lpc17xx/lpc17_ohciram.h index d2fc11248d..0e9f81ecbc 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 950a0ffe77..917ecd2e5d 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 21b04a08fb..4d88654c5d 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 cd7a1ca493..eae9685eaa 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 c13e32bb85..e0f4dc4adb 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 a83048f687..e69f1814aa 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 ************************************************************************************/ |