summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-08-24 22:16:09 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2012-08-24 22:16:09 +0000
commite1d2e02765b287c4a2966fa9e9e1cad7ea815bf8 (patch)
tree4504193e31c837a98e911a2bb7b8b121509179f9
parente55c8494b069f59b0c1380c50cf0993310085dae (diff)
downloadnuttx-e1d2e02765b287c4a2966fa9e9e1cad7ea815bf8.tar.gz
nuttx-e1d2e02765b287c4a2966fa9e9e1cad7ea815bf8.tar.bz2
nuttx-e1d2e02765b287c4a2966fa9e9e1cad7ea815bf8.zip
Update STM32 USB OTG FS host driver -- the driver is now marginally functional
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5051 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/ChangeLog4
-rw-r--r--nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c8
-rw-r--r--nuttx/arch/arm/src/stm32/stm32_otgfshost.c64
-rw-r--r--nuttx/drivers/usbhost/usbhost_storage.c113
-rw-r--r--nuttx/include/nuttx/usb/usbhost.h8
5 files changed, 120 insertions, 77 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 502c0e352..993719b11 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -3173,3 +3173,7 @@
* arch/arm/src/stm32/stm32_otgfshost.c: Renamed from stm32_usbhost.c.
This is nearly code complete and, with any luck, will be available
in NuttX-6.22.
+ * configs/*/defconfig: Update all defconfig files to remove syntax
+ that is incompatible with the mconf configuration tool.
+ * arch/arm/src/stm32/stm32_otgfshost.c: This driver now appears to be
+ functional (although more testing is necesary). \ No newline at end of file
diff --git a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c
index 154b953b7..de880cac1 100644
--- a/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c
+++ b/nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c
@@ -2194,7 +2194,13 @@ static int lpc17_ctrlout(FAR struct usbhost_driver_s *drvr,
*
* Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
+ * returned indicating the nature of the failure:
+ *
+ * EAGAIN - If devices NAKs the transfer (or NYET or other error where
+ * it may be appropriate to restart the entire transaction).
+ * EPERM - If the endpoint stalls
+ * EIO - On a TX or data toggle error
+ * EPIPE - Overrun errors
*
* Assumptions:
* - Only a single class bound to a single device is supported.
diff --git a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c
index 06d35a04a..d84ba6884 100644
--- a/nuttx/arch/arm/src/stm32/stm32_otgfshost.c
+++ b/nuttx/arch/arm/src/stm32/stm32_otgfshost.c
@@ -201,6 +201,7 @@ struct stm32_chan_s
uint8_t epno; /* Device endpoint number (0-127) */
uint8_t eptype; /* See OTGFS_EPTYPE_* definitions */
uint8_t pid; /* Data PID */
+ uint8_t npackets; /* Number of packets (for data toggle) */
bool inuse; /* True: This channel is "in use" */
volatile bool indata1; /* IN data toggle. True: DATA01 (Bulk and INTR only) */
volatile bool outdata1; /* OUT data toggle. True: DATA01 */
@@ -1057,6 +1058,13 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx)
}
#endif
+ /* Save the number of packets in the transfer. We will need this in
+ * order to set the next data toggle correctly when the transfer
+ * completes.
+ */
+
+ chan->npackets = (uint8_t)npackets;
+
/* Setup the HCTSIZn register */
regval = ((uint32_t)chan->buflen << OTGFS_HCTSIZ_XFRSIZ_SHIFT) |
@@ -1387,7 +1395,7 @@ static void stm32_gint_wrpacket(FAR struct stm32_usbhost_s *priv,
* OK - Transfer completed successfully
* EAGAIN - If devices NAKs the transfer or NYET occurs
* EPERM - If the endpoint stalls
- * EIO - On a TX or data error
+ * EIO - On a TX or data toggle error
* EPIPE - Frame overrun
*
* EBUSY in the result field indicates that the transfer has not completed.
@@ -1405,8 +1413,8 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
* HCINTMSK register to get the set of enabled HC interrupts.
*/
- pending = stm32_getreg(STM32_OTGFS_HCINT(chidx));
- regval = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx));
+ pending = stm32_getreg(STM32_OTGFS_HCINT(chidx));
+ regval = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx));
/* AND the two to get the set of enabled, pending HC interrupts */
@@ -1588,11 +1596,18 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
else if ((pending & OTGFS_HCINT_NAK) != 0)
{
+ /* For a BULK tranfer, the hardware is capable of retrying
+ * automatically on a NAK. However, this is not always
+ * what we need to do. So we always halt the transfer and
+ * return control to high level logic in the even of a NAK.
+ */
+
+#if 0
/* Halt the interrupt channel */
if (chan->eptype == OTGFS_EPTYPE_CTRL)
{
- /* Halt the channel -- the CHH interrrupt is expected next */
+ /* Halt the channel -- the CHH interrrupt is expected next */
stm32_chan_halt(priv, chidx, CHREASON_NAK);
}
@@ -1611,7 +1626,11 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
regval &= ~OTGFS_HCCHAR_CHDIS;
stm32_putreg(STM32_OTGFS_HCCHAR(chidx), regval);
}
+#else
+ /* Halt all transfers on the NAK -- the CHH interrrupt is expected next */
+ stm32_chan_halt(priv, chidx, CHREASON_NAK);
+#endif
/* Clear the NAK condition */
stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK);
@@ -1634,7 +1653,7 @@ static inline void stm32_gint_hcinisr(FAR struct stm32_usbhost_s *priv,
* OK - Transfer completed successfully
* EAGAIN - If devices NAKs the transfer or NYET occurs
* EPERM - If the endpoint stalls
- * EIO - On a TX or data error
+ * EIO - On a TX or data toggle error
* EPIPE - Frame overrun
*
* EBUSY in the result field indicates that the transfer has not completed.
@@ -1652,8 +1671,8 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
* HCINTMSK register to get the set of enabled HC interrupts.
*/
- pending = stm32_getreg(STM32_OTGFS_HCINT(chidx));
- regval = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx));
+ pending = stm32_getreg(STM32_OTGFS_HCINT(chidx));
+ regval = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx));
/* AND the two to get the set of enabled, pending HC interrupts */
@@ -1798,11 +1817,14 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv,
regval = stm32_getreg(STM32_OTGFS_HCCHAR(chidx));
- /* Is it a bulk endpoint */
+ /* Is it a bulk endpoint? Were an odd number of packets
+ * transferred?
+ */
- if ((regval & OTGFS_HCCHAR_EPTYP_MASK) == OTGFS_HCCHAR_EPTYP_BULK)
+ if ((regval & OTGFS_HCCHAR_EPTYP_MASK) == OTGFS_HCCHAR_EPTYP_BULK &&
+ (chan->npackets & 1) != 0)
{
- /* Yes... toggle the data out PID */
+ /* Yes to both... toggle the data out PID */
chan->outdata1 ^= true;
}
@@ -3405,7 +3427,13 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr,
*
* Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
+ * returned indicating the nature of the failure:
+ *
+ * EAGAIN - If devices NAKs the transfer (or NYET or other error where
+ * it may be appropriate to restart the entire transaction).
+ * EPERM - If the endpoint stalls
+ * EIO - On a TX or data toggle error
+ * EPIPE - Overrun errors
*
* Assumptions:
* - Only a single class bound to a single device is supported.
@@ -3528,22 +3556,14 @@ static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep,
ret = stm32_chan_wait(priv, chan);
- /* EGAIN indicates that the device NAKed the transfer and we need
+ /* EAGAIN indicates that the device NAKed the transfer and we need
* do try again. Anything else (success or other errors) will
* cause use to return
*/
- if (ret != -EAGAIN)
+ if (ret != OK)
{
- /* Output some debug info on an error */
-
- if (ret < 0)
- {
- udbg("Transfer failed: %d\n", ret);
- }
-
- /* Break out and return this result */
-
+ udbg("Transfer failed: %d\n", ret);
break;
}
}
diff --git a/nuttx/drivers/usbhost/usbhost_storage.c b/nuttx/drivers/usbhost/usbhost_storage.c
index 2817c2446..853287371 100644
--- a/nuttx/drivers/usbhost/usbhost_storage.c
+++ b/nuttx/drivers/usbhost/usbhost_storage.c
@@ -1,8 +1,8 @@
/****************************************************************************
* drivers/usbhost/usbhost_storage.c
*
- * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -123,7 +123,7 @@ struct usbhost_state_s
struct usbhost_driver_s *drvr;
/* The remainder of the fields are provide to the mass storage class */
-
+
char sdchar; /* Character identifying the /dev/sd[n] device */
volatile bool disconnected; /* TRUE: Device has been disconnected */
uint8_t ifno; /* Interface number */
@@ -217,7 +217,7 @@ static inline int usbhost_tfree(FAR struct usbhost_state_s *priv);
static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *priv);
/* struct usbhost_registry_s methods */
-
+
static struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *drvr,
FAR const struct usbhost_id_s *id);
@@ -248,7 +248,7 @@ static int usbhost_ioctl(FAR struct inode *inode, int cmd,
* Private Data
****************************************************************************/
-/* This structure provides the registry entry ID informatino that will be
+/* This structure provides the registry entry ID informatino that will be
* used to associate the USB host mass storage class to a connected USB
* device.
*/
@@ -416,7 +416,7 @@ static inline void usbhost_freeclass(FAR struct usbhost_state_s *class)
flags = irqsave();
class->class.flink = g_freelist;
g_freelist = class;
- irqrestore(flags);
+ irqrestore(flags);
}
#else
static inline void usbhost_freeclass(FAR struct usbhost_state_s *class)
@@ -700,16 +700,16 @@ static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv)
int result;
/* Initialize a CBW (re-using the allocated transfer buffer) */
-
+
cbw = usbhost_cbwalloc(priv);
if (!cbw)
{
udbg("ERROR: Failed to create CBW\n");
return -ENOMEM;
}
-
+
/* Construct and send the CBW */
-
+
usbhost_testunitreadycbw(cbw);
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
@@ -733,7 +733,7 @@ static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv)
int result;
/* Initialize a CBW (re-using the allocated transfer buffer) */
-
+
cbw = usbhost_cbwalloc(priv);
if (!cbw)
{
@@ -742,7 +742,7 @@ 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,
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
@@ -775,7 +775,7 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv)
int result;
/* Initialize a CBW (re-using the allocated transfer buffer) */
-
+
cbw = usbhost_cbwalloc(priv);
if (!cbw)
{
@@ -784,7 +784,7 @@ 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,
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
@@ -823,7 +823,7 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv)
int result;
/* Initialize a CBW (re-using the allocated transfer buffer) */
-
+
cbw = usbhost_cbwalloc(priv);
if (!cbw)
{
@@ -832,7 +832,7 @@ 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,
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
@@ -885,7 +885,7 @@ static void usbhost_destroy(FAR void *arg)
DEBUGASSERT(priv != NULL);
uvdbg("crefs: %d\n", priv->crefs);
-
+
/* Unregister the block driver */
usbhost_mkdevname(priv, devname);
@@ -965,10 +965,10 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
uint8_t found = 0;
int ret;
- DEBUGASSERT(priv != NULL &&
+ 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;
@@ -1004,7 +1004,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
case USB_DESC_TYPE_INTERFACE:
{
FAR struct usb_ifdesc_s *ifdesc = (FAR struct usb_ifdesc_s *)configdesc;
-
+
uvdbg("Interface descriptor\n");
DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
@@ -1078,7 +1078,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
found |= USBHOST_BINFOUND;
/* Save the bulk IN endpoint information */
-
+
bindesc.addr = epdesc->addr & USB_EP_ADDR_NUMBER_MASK;
bindesc.in = 1;
bindesc.funcaddr = funcaddr;
@@ -1108,7 +1108,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
}
/* Increment the address of the next descriptor */
-
+
configdesc += desc->len;
remaining -= desc->len;
}
@@ -1116,7 +1116,7 @@ static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
/* 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",
@@ -1202,7 +1202,7 @@ static inline int usbhost_initvolume(FAR struct usbhost_state_s *priv)
uvdbg("Test unit ready, retries=%d\n", retries);
/* Send TESTUNITREADY to see the unit is ready */
-
+
ret = usbhost_testunitready(priv);
if (ret == OK)
{
@@ -1585,7 +1585,7 @@ static FAR struct usbmsc_cbw_s *usbhost_cbwalloc(FAR struct usbhost_state_s *pri
* Name: usbhost_create
*
* Description:
- * This function implements the create() method of struct usbhost_registry_s.
+ * This function implements the create() method of struct usbhost_registry_s.
* The create() method is a callback into the class implementation. It is
* used to (1) create a new instance of the USB host class state and to (2)
* bind a USB host driver "session" to the class instance. Use of this
@@ -1644,9 +1644,9 @@ static FAR struct usbhost_class_s *usbhost_create(FAR struct usbhost_driver_s *d
priv->drvr = drvr;
/* NOTE: We do not yet know the geometry of the USB mass storage device */
-
+
/* Return the instance of the USB mass storage class */
-
+
return &priv->class;
}
}
@@ -1701,7 +1701,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *class,
FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)class;
int ret;
- DEBUGASSERT(priv != NULL &&
+ DEBUGASSERT(priv != NULL &&
configdesc != NULL &&
desclen >= sizeof(struct usb_cfgdesc_s));
@@ -1722,7 +1722,7 @@ static int usbhost_connect(FAR struct usbhost_class_s *class,
udbg("usbhost_initvolume() failed: %d\n", ret);
}
}
-
+
return ret;
}
@@ -1792,7 +1792,7 @@ static int usbhost_disconnected(struct usbhost_class_s *class)
}
}
- irqrestore(flags);
+ irqrestore(flags);
return OK;
}
@@ -1945,45 +1945,52 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
ret = -ENOMEM;
/* Initialize a CBW (re-using the allocated transfer buffer) */
-
+
cbw = usbhost_cbwalloc(priv);
if (cbw)
{
- /* Assume some device failure */
-
- ret = -ENODEV;
+ /* Loop in the event that EAGAIN is returned (mean that the
+ * transaction was NAKed and we should try again.
+ */
- /* Construct and send the CBW */
-
- usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw);
- result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
- (uint8_t*)cbw, USBMSC_CBW_SIZEOF);
- if (result == OK)
+ do
{
- /* Receive the user data */
+ /* Assume some device failure */
+
+ ret = -ENODEV;
- result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- buffer, priv->blocksize * nsectors);
+ /* Construct and send the CBW */
+
+ usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw);
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
+ (uint8_t*)cbw, USBMSC_CBW_SIZEOF);
if (result == OK)
{
- /* Receive the CSW */
+ /* Receive the user data */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
- priv->tbuffer, USBMSC_CSW_SIZEOF);
+ buffer, priv->blocksize * nsectors);
if (result == OK)
{
- FAR struct usbmsc_csw_s *csw;
-
- /* Check the CSW status */
+ /* Receive the CSW */
- csw = (FAR struct usbmsc_csw_s *)priv->tbuffer;
- if (csw->status == 0)
+ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
+ priv->tbuffer, USBMSC_CSW_SIZEOF);
+ if (result == OK)
{
- ret = nsectors;
+ FAR struct usbmsc_csw_s *csw;
+
+ /* Check the CSW status */
+
+ csw = (FAR struct usbmsc_csw_s *)priv->tbuffer;
+ if (csw->status == 0)
+ {
+ ret = nsectors;
+ }
}
}
}
- }
+ } while (result == -EAGAIN);
}
usbhost_givesem(&priv->exclsem);
@@ -2037,7 +2044,7 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe
ret = -ENOMEM;
/* Initialize a CBW (re-using the allocated transfer buffer) */
-
+
cbw = usbhost_cbwalloc(priv);
if (cbw)
{
@@ -2046,7 +2053,7 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe
ret = -ENODEV;
/* Construct and send the CBW */
-
+
usbhost_writecbw(startsector, priv->blocksize, nsectors, cbw);
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
diff --git a/nuttx/include/nuttx/usb/usbhost.h b/nuttx/include/nuttx/usb/usbhost.h
index b28db9551..acfe9a829 100644
--- a/nuttx/include/nuttx/usb/usbhost.h
+++ b/nuttx/include/nuttx/usb/usbhost.h
@@ -448,7 +448,13 @@
*
* Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is
- * returned indicating the nature of the failure
+ * returned indicating the nature of the failure:
+ *
+ * EAGAIN - If devices NAKs the transfer (or NYET or other error where
+ * it may be appropriate to restart the entire transaction).
+ * EPERM - If the endpoint stalls
+ * EIO - On a TX or data toggle error
+ * EPIPE - Overrun errors
*
* Assumptions:
* This function will *not* be called from an interrupt handler.