Improve endpoint management
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@3240 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
parent
7298b8c7b6
commit
95a19a9312
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
nuttx-5.16 2011-01-10 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.
|
||||
* 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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
/************************************************************************************
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -464,39 +464,6 @@ static void lpc17_putle16(uint8_t *dest, uint16_t val)
|
|||
dest[1] = val >> 8;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 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
|
||||
*
|
||||
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -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
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
@ -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);
|
||||
|
@ -895,6 +909,198 @@ static void usbhost_destroy(FAR void *arg)
|
|||
usbhost_freeclass(priv);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
|
@ -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.
|
||||
*/
|
||||
|
||||
usbhost_work(priv, usbhost_destroy);
|
||||
if (up_interrupt_context())
|
||||
{
|
||||
/* Destroy the instance on the worker thread. */
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
|
@ -225,6 +225,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
|
||||
*
|
||||
|
@ -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
|
||||
************************************************************************************/
|
||||
|
|
Loading…
Reference in New Issue