Browse Source

Update STM32 USB OTG FS host driver -- the driver is now marginally functional

git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@5051 7fd9a85b-ad96-42d3-883c-3090e2eb8679
sbg
patacongo 13 years ago
parent
commit
20c7cf9db9
  1. 4
      nuttx/ChangeLog
  2. 8
      nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c
  3. 64
      nuttx/arch/arm/src/stm32/stm32_otgfshost.c
  4. 51
      nuttx/drivers/usbhost/usbhost_storage.c
  5. 8
      nuttx/include/nuttx/usb/usbhost.h

4
nuttx/ChangeLog

@ -3173,3 +3173,7 @@
* arch/arm/src/stm32/stm32_otgfshost.c: Renamed from stm32_usbhost.c. * arch/arm/src/stm32/stm32_otgfshost.c: Renamed from stm32_usbhost.c.
This is nearly code complete and, with any luck, will be available This is nearly code complete and, with any luck, will be available
in NuttX-6.22. 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).

8
nuttx/arch/arm/src/lpc17xx/lpc17_usbhost.c

@ -2194,7 +2194,13 @@ static int lpc17_ctrlout(FAR struct usbhost_driver_s *drvr,
* *
* Returned Values: * Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is * 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: * Assumptions:
* - Only a single class bound to a single device is supported. * - Only a single class bound to a single device is supported.

64
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 epno; /* Device endpoint number (0-127) */
uint8_t eptype; /* See OTGFS_EPTYPE_* definitions */ uint8_t eptype; /* See OTGFS_EPTYPE_* definitions */
uint8_t pid; /* Data PID */ uint8_t pid; /* Data PID */
uint8_t npackets; /* Number of packets (for data toggle) */
bool inuse; /* True: This channel is "in use" */ bool inuse; /* True: This channel is "in use" */
volatile bool indata1; /* IN data toggle. True: DATA01 (Bulk and INTR only) */ volatile bool indata1; /* IN data toggle. True: DATA01 (Bulk and INTR only) */
volatile bool outdata1; /* OUT data toggle. True: DATA01 */ 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 #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 */ /* Setup the HCTSIZn register */
regval = ((uint32_t)chan->buflen << OTGFS_HCTSIZ_XFRSIZ_SHIFT) | 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 * OK - Transfer completed successfully
* EAGAIN - If devices NAKs the transfer or NYET occurs * EAGAIN - If devices NAKs the transfer or NYET occurs
* EPERM - If the endpoint stalls * EPERM - If the endpoint stalls
* EIO - On a TX or data error * EIO - On a TX or data toggle error
* EPIPE - Frame overrun * EPIPE - Frame overrun
* *
* EBUSY in the result field indicates that the transfer has not completed. * 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. * HCINTMSK register to get the set of enabled HC interrupts.
*/ */
pending = stm32_getreg(STM32_OTGFS_HCINT(chidx)); pending = stm32_getreg(STM32_OTGFS_HCINT(chidx));
regval = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx)); regval = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx));
/* AND the two to get the set of enabled, pending HC interrupts */ /* 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) 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 */ /* Halt the interrupt channel */
if (chan->eptype == OTGFS_EPTYPE_CTRL) 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); 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; regval &= ~OTGFS_HCCHAR_CHDIS;
stm32_putreg(STM32_OTGFS_HCCHAR(chidx), regval); 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 */ /* Clear the NAK condition */
stm32_putreg(STM32_OTGFS_HCINT(chidx), OTGFS_HCINT_NAK); 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 * OK - Transfer completed successfully
* EAGAIN - If devices NAKs the transfer or NYET occurs * EAGAIN - If devices NAKs the transfer or NYET occurs
* EPERM - If the endpoint stalls * EPERM - If the endpoint stalls
* EIO - On a TX or data error * EIO - On a TX or data toggle error
* EPIPE - Frame overrun * EPIPE - Frame overrun
* *
* EBUSY in the result field indicates that the transfer has not completed. * 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. * HCINTMSK register to get the set of enabled HC interrupts.
*/ */
pending = stm32_getreg(STM32_OTGFS_HCINT(chidx)); pending = stm32_getreg(STM32_OTGFS_HCINT(chidx));
regval = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx)); regval = stm32_getreg(STM32_OTGFS_HCINTMSK(chidx));
/* AND the two to get the set of enabled, pending HC interrupts */ /* 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)); 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; chan->outdata1 ^= true;
} }
@ -3405,7 +3427,13 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr,
* *
* Returned Values: * Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is * 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: * Assumptions:
* - Only a single class bound to a single device is supported. * - 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); 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 * do try again. Anything else (success or other errors) will
* cause use to return * cause use to return
*/ */
if (ret != -EAGAIN) if (ret != OK)
{ {
/* Output some debug info on an error */ udbg("Transfer failed: %d\n", ret);
if (ret < 0)
{
udbg("Transfer failed: %d\n", ret);
}
/* Break out and return this result */
break; break;
} }
} }

51
nuttx/drivers/usbhost/usbhost_storage.c

@ -1,8 +1,8 @@
/**************************************************************************** /****************************************************************************
* drivers/usbhost/usbhost_storage.c * drivers/usbhost/usbhost_storage.c
* *
* Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. * Copyright (C) 2010-2012 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr> * Author: Gregory Nutt <gnutt@nuttx.org>
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@ -1949,41 +1949,48 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer,
cbw = usbhost_cbwalloc(priv); cbw = usbhost_cbwalloc(priv);
if (cbw) if (cbw)
{ {
/* Assume some device failure */ /* Loop in the event that EAGAIN is returned (mean that the
* transaction was NAKed and we should try again.
*/
ret = -ENODEV; do
{
/* Assume some device failure */
/* Construct and send the CBW */ ret = -ENODEV;
usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw); /* Construct and send the CBW */
result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
if (result == OK)
{
/* Receive the user data */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin, usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw);
buffer, priv->blocksize * nsectors); result = DRVR_TRANSFER(priv->drvr, priv->bulkout,
(uint8_t*)cbw, USBMSC_CBW_SIZEOF);
if (result == OK) if (result == OK)
{ {
/* Receive the CSW */ /* Receive the user data */
result = DRVR_TRANSFER(priv->drvr, priv->bulkin, result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tbuffer, USBMSC_CSW_SIZEOF); buffer, priv->blocksize * nsectors);
if (result == OK) if (result == OK)
{ {
FAR struct usbmsc_csw_s *csw; /* Receive the CSW */
/* Check the CSW status */ result = DRVR_TRANSFER(priv->drvr, priv->bulkin,
priv->tbuffer, USBMSC_CSW_SIZEOF);
csw = (FAR struct usbmsc_csw_s *)priv->tbuffer; if (result == OK)
if (csw->status == 0)
{ {
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); usbhost_givesem(&priv->exclsem);

8
nuttx/include/nuttx/usb/usbhost.h

@ -448,7 +448,13 @@
* *
* Returned Values: * Returned Values:
* On success, zero (OK) is returned. On a failure, a negated errno value is * 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: * Assumptions:
* This function will *not* be called from an interrupt handler. * This function will *not* be called from an interrupt handler.

Loading…
Cancel
Save