9
0
Fork 0

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:
patacongo 2011-01-11 01:41:06 +00:00
parent 7298b8c7b6
commit 95a19a9312
8 changed files with 519 additions and 414 deletions

View File

@ -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>

View File

@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
<p>Last Updated: January 9, 2011</p>
<p>Last Updated: January 10, 2011</p>
</td>
</tr>
</table>
@ -1969,50 +1969,18 @@ Other memory:
</table>
<ul><pre>
5.15 2010-12-12 Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
nuttx-5.16 2011-01-10 Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
* net/uip/uip_tcpaddsend.c and net/send.c -- Another place where the TCP sequence
number problem &quot;fixed&quot; in 5.14 might occur.
* net/send.c -- Check if the destination IP address is in the ARP table. If
not, then don't consider the packet sent. It won't be, an ARP packet will go
out instead. This improves behavior, for example, on the first GET request
from a browser.
* arch/arm/src/lpc17xx/lpc17_emacram.h and lpc17_allocateheap.c -- The Ethernet
logic was using all of AHB SRAM Bank0 for Ethernet packet buffers (16Kb). An
option was added to limit the amount of SRAM used for packet buffering and to
re-use any extra Bank0 memory for heap. configs/olimex-lpc1766stk/nettest
now uses only 8Kb at the beginning of Bank0; the 8Kb at the end of Bank0 is
included in the heap
* arch/arm/src/lpc17xx/lpc17_ssp.c -- Fix compilation errors when SSP1 is
selected.
* configs/olimex-lpc1766stk/nsh -- Enable network and SD/MMC card support in
NSH. Networking and telnetd interface as well as SPI-based microSD are
now functional.
* examples/nsh/nsh_netinit.c -- Fix NSH bug. If CONFIG_NET is selected, but
CONFIG_EXAMPLES_NSH_TELNETD is not selected, then the network is never
initialized and bad things happen if you try to ping.
* drivers/lcd -- Add header files for the Phillips PCF8833 LCD controller and
for the Epson S1D15G10 LCD controller. A driver for the Nokia 6100 LCD is
coming.
* include/nuttx/spi.h and almost all other SPI files -- Added an optional
cmddata() method to the SPI interface. Some devices require an additional
out-of-band bit to specify if the next word sent to the device is a command
or data. This is typical, for example, in &quot;9-bit&quot; displays where the 9th bit
is the CMD/DATA bit. The cmddata method provides selection of command or data.
* drivers/lcd/p14201.c -- Now uses the cmddata() method of the SPI interface.
* arch/arm/src/lpc17xx/lpc17_usbdev.c -- LPC17xx USB driver now appears to
to be fully functional. examples/usbstorage configuration verified (the
examples/usbserial configuration is untested).
* drivers/usbdev/usbserial.c and usbstorage.c -- All USB class drivers need
to call DEV_CONNECT() when they are ready to be enumerated. That is,
(1) initially when bound to the USB driver, and (2) after a USB reset.
* drivers/lcd/nokia6100.c -- A driver for the Nokia 6100 LCD. This driver
has not be verified as of the initial check-in.
* configs/olimex-lpc1766stk/nx -- A NX graphics configuration for the Olimex
LPC1766-STK board using the Nokia 6100 LCD driver. This configuration has
not been verified as of the initial check-in.
* include/nuttx/spi.h -- the SPI_SETBITS macro was calling the setmode method.
This is a very important bug-fix in some usages.
* include/nuttx/usb -- Created new directory. Moved all usb-related header
files to this new directory. Created a skeleton for a new USB host header
file
* drivers/usbhost -- Add USB host "registry" where connect devices can be
matched with the correct USB class driver.
* arc/arc/src/lpc17xx/lpc17_usbhost.c -- Add a simple USB host driver for
the NXP lpc17xx.
* drivers/usbhost -- Add generic USB device enumeration logic.
* drivers/usbhost -- Add a USB host class driver for the (Bulk-Only) USB
Mass Storage Class.
pascal-2.0 2009-12-21 Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
@ -2042,18 +2010,7 @@ buildroot-1.8 2009-12-21 &lt;spudmonkey@racsa.co.cr&gt;
</table>
<ul><pre>
nuttx-5.16 2011-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
* include/nuttx/usb -- Created new directory. Moved all usb-related header
files to this new directory. Created a skeleton for a new USB host header
file
* drivers/usbhost -- Add USB host "registry" where connect devices can be
matched with the correct USB class driver.
* arc/arc/src/lpc17xx/lpc17_usbhost.c -- Add a simple USB host driver for
the NXP lpc17xx.
* drivers/usbhost -- Add generic USB device enumeration logic.
* drivers/usbhost -- Add a USB host class driver for the (Bulk-Only) USB
Mass Storage Class.
nuttx-5.17 2011-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
pascal-2.1 2010-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;

View File

@ -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
/************************************************************************************

View File

@ -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;

View File

@ -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
^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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
^^^^^^^^^^^^^^^^^^^^^^

View File

@ -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)
{

View File

@ -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
************************************************************************************/