diff --git a/ChangeLog b/ChangeLog index 9c3c4a9ac5f..63642f9f4b2 100755 --- a/ChangeLog +++ b/ChangeLog @@ -10306,3 +10306,7 @@ (2015-05-03). * fs/vfs/fs_poll.c: Fix resource leak and memory corruption on poll failure. From Jussi Kivilinna (2015-05-04). + * All USB host drivers in arch/ and all USB class drivers in drivers/usbhost: + Modify the transfer() and asynch() methods so that the actual size of + the transfer is returned. Unverified on initial commit (2015-05-05). + diff --git a/arch/arm/src/efm32/efm32_usbhost.c b/arch/arm/src/efm32/efm32_usbhost.c index bbe69d78a2a..53f47ea7c1d 100644 --- a/arch/arm/src/efm32/efm32_usbhost.c +++ b/arch/arm/src/efm32/efm32_usbhost.c @@ -220,7 +220,8 @@ struct efm32_chan_s bool in; /* True: IN endpoint */ volatile bool waiter; /* True: Thread is waiting for a channel event */ uint16_t maxpacket; /* Max packet size */ - volatile uint16_t buflen; /* Buffer length (remaining) */ + uint16_t buflen; /* Buffer length (at start of transfer) */ + volatile uint16_t xfrd; /* Bytes transferred (at end of transfer) */ volatile uint16_t inflight; /* Number of Tx bytes "in-flight" */ FAR uint8_t *buffer; /* Transfer buffer pointer */ #ifdef CONFIG_USBHOST_ASYNCH @@ -280,7 +281,7 @@ struct efm32_usbhost_s #ifdef HAVE_USBHOST_TRACE /* Format of one trace entry */ -struct stm32_usbhost_trace_s +struct efm32_usbhost_trace_s { #if 0 uint16_t id; @@ -369,8 +370,8 @@ static int efm32_ctrl_recvdata(FAR struct efm32_usbhost_s *priv, FAR struct efm32_ctrlinfo_s *ep0, FAR uint8_t *buffer, unsigned int buflen); static int efm32_in_setup(FAR struct efm32_usbhost_s *priv, int chidx); -static int efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void efm32_in_next(FAR struct efm32_usbhost_s *priv, FAR struct efm32_chan_s *chan); @@ -379,8 +380,8 @@ static int efm32_in_asynch(FAR struct efm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif static int efm32_out_setup(FAR struct efm32_usbhost_s *priv, int chidx); -static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void efm32_out_next(FAR struct efm32_usbhost_s *priv, FAR struct efm32_chan_s *chan); @@ -454,8 +455,8 @@ static int efm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, static int efm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static int efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, + FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int efm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, @@ -503,7 +504,7 @@ static struct usbhost_connection_s g_usbconn = #ifdef HAVE_USBHOST_TRACE /* Trace strings */ -static const struct stm32_usbhost_trace_s g_trace1[TRACE1_NSTRINGS] = +static const struct efm32_usbhost_trace_s g_trace1[TRACE1_NSTRINGS] = { TRENTRY(USBHOST_TRACE1_DEVDISCONN, TR_FMT1, "OTGFS ERROR: Host Port %d. Device disconnected\n"), TRENTRY(USBHOST_TRACE1_IRQATTACH, TR_FMT1, "OTGFS ERROR: Failed to attach IRQ\n"), @@ -534,7 +535,7 @@ static const struct stm32_usbhost_trace_s g_trace1[TRACE1_NSTRINGS] = #endif }; -static const struct stm32_usbhost_trace_s g_trace2[TRACE2_NSTRINGS] = +static const struct efm32_usbhost_trace_s g_trace2[TRACE2_NSTRINGS] = { TRENTRY(USBHOST_TRACE2_CLIP, TR_FMT2, "OTGFS CLIP: chidx: %d buflen: %d\n"), @@ -1182,7 +1183,7 @@ static int efm32_chan_wait(FAR struct efm32_usbhost_s *priv, ret = sem_wait(&chan->waitsem); - /* sem_wait should succeeed. But it is possible that we could be + /* sem_wait should succeed. But it is possible that we could be * awakened by a signal too. */ @@ -1480,6 +1481,7 @@ static void efm32_transfer_start(FAR struct efm32_usbhost_s *priv, int chidx) chan->result = EBUSY; chan->inflight = 0; + chan->xfrd = 0; priv->chidx = chidx; /* Compute the expected number of packets associated to the transfer. @@ -1689,11 +1691,12 @@ static int efm32_ctrl_sendsetup(FAR struct efm32_usbhost_s *priv, chan->pid = EFM32_USB_PID_SETUP; chan->buffer = (FAR uint8_t *)req; chan->buflen = USB_SIZEOF_CTRLREQ; + chan->xfrd = 0; /* Set up for the wait BEFORE starting the transfer */ ret = efm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(USBHOST_TRACE1_DEVDISCONN, 0); return ret; @@ -1755,6 +1758,7 @@ static int efm32_ctrl_senddata(FAR struct efm32_usbhost_s *priv, chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; /* Set the DATA PID */ @@ -1772,7 +1776,7 @@ static int efm32_ctrl_senddata(FAR struct efm32_usbhost_s *priv, /* Set up for the wait BEFORE starting the transfer */ ret = efm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(USBHOST_TRACE1_DEVDISCONN, 0); return ret; @@ -1808,11 +1812,12 @@ static int efm32_ctrl_recvdata(FAR struct efm32_usbhost_s *priv, chan->pid = EFM32_USB_PID_DATA1; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; /* Set up for the wait BEFORE starting the transfer */ ret = efm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(USBHOST_TRACE1_DEVDISCONN, 0); return ret; @@ -1896,13 +1901,13 @@ static int efm32_in_setup(FAR struct efm32_usbhost_s *priv, int chidx) * *******************************************************************************/ -static int efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen) { FAR struct efm32_chan_s *chan; uint32_t start; uint32_t elapsed; - int ret = OK; + int ret; /* Loop until the transfer completes (i.e., buflen is decremented to zero) * or a fatal error occurs (any error other than a simple NAK) @@ -1911,17 +1916,18 @@ static int efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; start = clock_systimer(); - while (chan->buflen > 0) + while ((chan->xfrd < chan->buflen > 0) { /* Set up for the wait BEFORE starting the transfer */ ret = efm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(USBHOST_TRACE1_DEVDISCONN, 0); - return ret; + return (ssize_t)ret; } /* Set up for the transfer based on the direction and the endpoint type */ @@ -1930,7 +1936,7 @@ static int efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx, if (ret < 0) { udbg("ERROR: efm32_in_setup failed: %d\n", ret); - return ret; + return (ssize_t)ret; } /* Wait for the transfer to complete and get the result */ @@ -1942,7 +1948,7 @@ static int efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx, * cause use to return */ - if (ret != OK) + if (ret < 0) { usbhost_trace1(USBHOST_TRACE1_TRNSFRFAILED,ret); @@ -1956,16 +1962,17 @@ static int efm32_in_transfer(FAR struct efm32_usbhost_s *priv, int chidx, elapsed = clock_systimer() - start; if (ret != -EAGAIN || /* Not a NAK condition OR */ elapsed >= EFM32_DATANAK_DELAY || /* Timeout has elapsed OR */ - chan->buflen != buflen) /* Data has been partially transferred */ + chan->xfrd > 0) /* Data has been partially transferred */ { /* Break out and return the error */ - break; + udbg("ERROR: efm32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; } } } - return ret; + return (ssize_t)chan->xfrd; } /******************************************************************************* @@ -1985,13 +1992,14 @@ static void efm32_in_next(FAR struct efm32_usbhost_s *priv, { usbhost_asynch_t callback; FAR void *arg; + ssize_t nbytes; int result; int ret; - /* Is the full transfer complete? Did the last chunk transfer complete OK?*/ + /* Is the full transfer complete? Did the last chunk transfer complete OK? */ - result = chan->result; - if (chan->buflen > 0 && result == OK) + result = -(int)chan->result; + if (chan->xfrd < chan->buflen && result == OK) { /* Yes.. Set up for the next transfer based on the direction and the * endpoint type @@ -2015,12 +2023,20 @@ static void efm32_in_next(FAR struct efm32_usbhost_s *priv, callback = chan->callback; arg = chan->arg; + nbytes = chan->xfrd; + chan->callback = NULL; chan->arg = NULL; + chan->xfrd = 0; /* Then perform the callback */ - callback(arg, chan->result); + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); } #endif @@ -2048,6 +2064,7 @@ static int efm32_in_asynch(FAR struct efm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; ret = efm32_chan_asynchsetup(priv, chan, callback, arg); if (ret < 0) @@ -2143,14 +2160,15 @@ static int efm32_out_setup(FAR struct efm32_usbhost_s *priv, int chidx) * *******************************************************************************/ -static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen) { FAR struct efm32_chan_s *chan; uint32_t start; uint32_t elapsed; size_t xfrlen; - int ret = OK; + ssize_t xfrd; + int ret; /* Loop until the transfer completes (i.e., buflen is decremented to zero) * or a fatal error occurs (any error other than a simple NAK) @@ -2158,6 +2176,7 @@ static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; start = clock_systimer(); + xfrd = 0; while (buflen > 0) { @@ -2169,14 +2188,15 @@ static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, xfrlen = MIN(chan->maxpacket, buflen); chan->buffer = buffer; chan->buflen = xfrlen; + chan->xfrd = 0; /* Set up for the wait BEFORE starting the transfer */ ret = efm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(USBHOST_TRACE1_DEVDISCONN,0); - return ret; + return (ssize_t)ret; } /* Set up for the transfer based on the direction and the endpoint type */ @@ -2185,7 +2205,7 @@ static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, if (ret < 0) { udbg("ERROR: efm32_out_setup failed: %d\n", ret); - return ret; + return (ssize_t)ret; } /* Wait for the transfer to complete and get the result */ @@ -2194,7 +2214,7 @@ static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, /* Handle transfer failures */ - if (ret != OK) + if (ret < 0) { usbhost_trace1(USBHOST_TRACE1_TRNSFRFAILED,ret); @@ -2206,13 +2226,14 @@ static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, */ elapsed = clock_systimer() - start; - if (ret != -EAGAIN || /* Not a NAK condition OR */ - elapsed >= EFM32_DATANAK_DELAY || /* Timeout has elapsed OR */ - chan->buflen != xfrlen) /* Data has been partially transferred */ + if (ret != -EAGAIN || /* Not a NAK condition OR */ + elapsed >= EFM32_DATANAK_DELAY || /* Timeout has elapsed OR */ + chan->xfrd != xfrlen) /* Data has been partially transferred */ { /* Break out and return the error */ - break; + udbg("ERROR: efm32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; } /* Is this flush really necessary? What does the hardware do with the @@ -2233,10 +2254,11 @@ static int efm32_out_transfer(FAR struct efm32_usbhost_s *priv, int chidx, buffer += xfrlen; buflen -= xfrlen; + xfrd += chan->xfrd; } } - return ret; + return xfrd; } /******************************************************************************* @@ -2256,13 +2278,14 @@ static void efm32_out_next(FAR struct efm32_usbhost_s *priv, { usbhost_asynch_t callback; FAR void *arg; + ssize_t nbytes; int result; int ret; /* Is the full transfer complete? Did the last chunk transfer complete OK?*/ - result = chan->result; - if (chan->buflen > 0 && result == OK) + result = -(int)chan->result; + if (chan->xfrd < chan->buflen && result == OK) { /* Yes.. Set up for the next transfer based on the direction and the * endpoint type @@ -2286,12 +2309,20 @@ static void efm32_out_next(FAR struct efm32_usbhost_s *priv, callback = chan->callback; arg = chan->arg; + nbytes = chan->xfrd; + chan->callback = NULL; chan->arg = NULL; + chan->xfrd = 0; /* Then perform the callback */ - callback(arg, chan->result); + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); } #endif @@ -2319,6 +2350,7 @@ static int efm32_out_asynch(FAR struct efm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; ret = efm32_chan_asynchsetup(priv, chan, callback, arg); if (ret < 0) @@ -2709,7 +2741,7 @@ static inline void efm32_gint_hcoutisr(FAR struct efm32_usbhost_s *priv, */ priv->chan[chidx].buffer += priv->chan[chidx].inflight; - priv->chan[chidx].buflen -= priv->chan[chidx].inflight; + priv->chan[chidx].xfrd += priv->chan[chidx].inflight; priv->chan[chidx].inflight = 0; /* Halt the channel -- the CHH interrupt is expected next */ @@ -3020,7 +3052,7 @@ static inline void efm32_gint_rxflvlisr(FAR struct efm32_usbhost_s *priv) /* Manage multiple packet transfers */ priv->chan[chidx].buffer += bcnt; - priv->chan[chidx].buflen -= bcnt; + priv->chan[chidx].xfrd += bcnt; /* Check if more packets are expected */ @@ -3078,15 +3110,15 @@ static inline void efm32_gint_nptxfeisr(FAR struct efm32_usbhost_s *priv) */ chan->buffer += chan->inflight; - chan->buflen -= chan->inflight; + chan->xfrd += chan->inflight; chan->inflight = 0; - /* If we have now transfered the entire buffer, then this transfer is + /* If we have now transferred the entire buffer, then this transfer is * complete (this case really should never happen because we disable * the NPTXFE interrupt on the final packet). */ - if (chan->buflen <= 0) + if (chan->xfrd >= chan->buflen) { /* Disable further Tx FIFO empty interrupts and bail. */ @@ -3100,18 +3132,18 @@ static inline void efm32_gint_nptxfeisr(FAR struct efm32_usbhost_s *priv) /* Extract the number of bytes available in the non-periodic Tx FIFO. */ - avail = ((regval & _USB_GNPTXSTS_NPTXFSPCAVAIL_MASK) >> _USB_GNPTXSTS_NPTXFSPCAVAIL_SHIFT) << 2; + avail = ((regval & _USB_GNPTXSTS_NPTXFSPCAVAIL_MASK) >> + _USB_GNPTXSTS_NPTXFSPCAVAIL_SHIFT) << 2; + + /* Get the size to put in the Tx FIFO now */ + + wrsize = chan->buflen - chan->xfrd; /* Get minimal size packet that can be sent. Something is seriously * configured wrong if one packet will not fit into the empty Tx FIFO. */ - DEBUGASSERT(chan->buflen > 0 && - avail >= MIN(chan->buflen, chan->maxpacket)); - - /* Get the size to put in the Tx FIFO now */ - - wrsize = chan->buflen; + DEBUGASSERT(wrsize > 0 && avail >= MIN(wrsize, chan->maxpacket)); if (wrsize > avail) { /* Clip the write size to the number of full, max sized packets @@ -3133,8 +3165,8 @@ static inline void efm32_gint_nptxfeisr(FAR struct efm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - ullvdbg("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, wrsize); + ullvdbg("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); efm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -3167,7 +3199,7 @@ static inline void efm32_gint_ptxfeisr(FAR struct efm32_usbhost_s *priv) */ chan->buffer += chan->inflight; - chan->buflen -= chan->inflight; + chan->xfrd += chan->inflight; chan->inflight = 0; /* If we have now transfered the entire buffer, then this transfer is @@ -3175,7 +3207,7 @@ static inline void efm32_gint_ptxfeisr(FAR struct efm32_usbhost_s *priv) * the PTXFE interrupt on the final packet). */ - if (chan->buflen <= 0) + if (chan->xfrd >= chan->buflen) { /* Disable further Tx FIFO empty interrupts and bail. */ @@ -3191,16 +3223,15 @@ static inline void efm32_gint_ptxfeisr(FAR struct efm32_usbhost_s *priv) avail = ((regval & _USB_HPTXSTS_PTXFSPCAVAIL_MASK) >> _USB_HPTXSTS_PTXFSPCAVAIL_SHIFT) << 2; + /* Get the size to put in the Tx FIFO now */ + + wrsize = chan->buflen - chan->xfrd; + /* Get minimal size packet that can be sent. Something is seriously * configured wrong if one packet will not fit into the empty Tx FIFO. */ - DEBUGASSERT(chan->buflen > 0 && - avail >= MIN(chan->buflen, chan->maxpacket)); - - /* Get the size to put in the Tx FIFO now */ - - wrsize = chan->buflen; + DEBUGASSERT(wrsize && avail >= MIN(wrsize, chan->maxpacket)); if (wrsize > avail) { /* Clip the write size to the number of full, max sized packets @@ -3222,8 +3253,8 @@ static inline void efm32_gint_ptxfeisr(FAR struct efm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - ullvdbg("HPTXSTS: %08x chidx: %d avail: %d buflen: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, wrsize); + ullvdbg("HPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); efm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -4529,8 +4560,9 @@ static int efm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * buflen - The length of the data to be sent or received. * * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure: + * On success, a non-negative value is returned that indicates the number + * of bytes successfully transferred. On a failure, a negated errno value is + * returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4544,12 +4576,12 @@ static int efm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * *******************************************************************************/ -static int efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, + FAR uint8_t *buffer, size_t buflen) { FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr; unsigned int chidx = (unsigned int)ep; - int ret; + ssize_t nbytes; uvdbg("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); @@ -4563,15 +4595,15 @@ static int efm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, if (priv->chan[chidx].in) { - ret = efm32_in_transfer(priv, chidx, buffer, buflen); + nbytes = efm32_in_transfer(priv, chidx, buffer, buflen); } else { - ret = efm32_out_transfer(priv, chidx, buffer, buflen); + nbytes = efm32_out_transfer(priv, chidx, buffer, buflen); } efm32_givesem(&priv->exclsem); - return ret; + return nbytes; } /******************************************************************************* @@ -4765,9 +4797,7 @@ static int efm32_connect(FAR struct usbhost_driver_s *drvr, static void efm32_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport) { - FAR struct efm32_usbhost_s *priv = (FAR struct efm32_usbhost_s *)drvr; - DEBUGASSERT(priv != NULL && hport != NULL); - + DEBUGASSERT(hport != NULL); hport->devclass = NULL; } diff --git a/arch/arm/src/lpc17xx/Kconfig b/arch/arm/src/lpc17xx/Kconfig index 3f0180281aa..b64a0047f60 100644 --- a/arch/arm/src/lpc17xx/Kconfig +++ b/arch/arm/src/lpc17xx/Kconfig @@ -961,16 +961,14 @@ config USBHOST_IOBUFSIZE 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. -config LPC17_USBHOST_NASYNCH - int "Number asynch transfers" +config LPC17_USBHOST_NPREALLOC + int "Max concurrent transfers" default 8 if USBHOST_HUB default 4 if !USBHOST_HUB - depends on USBHOST_ASYNCH ---help--- This number represents a number of pre-allocated structures to support - asynchronous IN data transfers. This number effective determines that - number of concurrent asynchronous IN endpoint transfer that can be - supported. + concurrent data transfers. This number limits that number of concurrent + asynchronous IN endpoint transfer that can be supported. config USBHOST_BULK_DISABLE bool "Disable bulk EPs" diff --git a/arch/arm/src/lpc17xx/lpc17_usbhost.c b/arch/arm/src/lpc17xx/lpc17_usbhost.c index 491be114f08..713b35bb98a 100644 --- a/arch/arm/src/lpc17xx/lpc17_usbhost.c +++ b/arch/arm/src/lpc17xx/lpc17_usbhost.c @@ -84,8 +84,8 @@ # warning "No IO buffers allocated" #endif -#ifndef CONFIG_LPC17_USBHOST_NASYNCH -# define CONFIG_LPC17_USBHOST_NASYNCH 8 +#ifndef CONFIG_LPC17_USBHOST_NPREALLOC +# define CONFIG_LPC17_USBHOST_NPREALLOC 8 #endif /* OHCI Setup ******************************************************************/ @@ -183,20 +183,33 @@ struct lpc17_usbhost_s #endif }; -#ifdef CONFIG_USBHOST_ASYNCH /* This structure describes one asynchronous transfer */ -struct lpc17_asynch_s +struct lpc17_xfrinfo_s { - uint16_t buflen; /* Buffer length */ - uint8_t *user; /* User buffer */ + volatile bool wdhwait; /* Thread is waiting for WDH interrupt */ + volatile uint8_t tdstatus; /* TD control status bits from last Writeback Done Head event */ + uint8_t *buffer; /* Transfer buffer start */ + uint16_t xfrd; /* Number of bytes transferred */ + +#ifdef CONFIG_USBHOST_ASYNCH #if LPC17_IOBUFFERS > 0 + /* Remember buffer related information for when the asynchronous transfer + * completes. + */ + + uint16_t buflen; /* Buffer length */ uint8_t *alloc; /* Allocated buffer */ #endif + + /* Retain the callback information for the asynchronous transfer + * completion. + */ + usbhost_asynch_t callback; /* Transfer complete callback */ void *arg; /* Argument that accompanies the callback */ -}; #endif +}; /* The OCHI expects the size of an endpoint descriptor to be 16 bytes. * However, the size allocated for an endpoint descriptor is 32 bytes in @@ -208,21 +221,17 @@ struct lpc17_ed_s { /* Hardware specific fields */ - struct ohci_ed_s hw; + struct ohci_ed_s hw; /* 0-15 */ /* Software specific fields */ - uint8_t xfrtype; /* 0: Transfer type. See SB_EP_ATTR_XFER_* in usb.h */ - uint8_t interval; /* 1: Periodic EP polling interval: 2, 4, 6, 16, or 32 */ - volatile uint8_t tdstatus; /* 2: TD control status bits from last Writeback Done Head event */ - volatile bool wdhwait; /* 3: TRUE: Thread is waiting for WDH interrupt */ - sem_t wdhsem; /* 4: Semaphore used to wait for Writeback Done Head event */ - /* Unused bytes may follow, depending on the size of sem_t */ -#ifdef CONFIG_USBHOST_ASYNCH + uint8_t xfrtype; /* 16: Transfer type. See SB_EP_ATTR_XFER_* in usb.h */ + uint8_t interval; /* 17: Periodic EP polling interval: 2, 4, 6, 16, or 32 */ + sem_t wdhsem; /* 18: Semaphore used to wait for Writeback Done Head event */ + /* Unused bytes may follow, depending on the size of sem_t */ /* Pointer to structure that manages asynchronous transfers on this pipe */ - struct lpc17_asynch_s *asynch; -#endif + struct lpc17_xfrinfo_s *xfrinfo; }; /* The OCHI expects the size of an transfer descriptor to be 16 bytes. @@ -290,10 +299,8 @@ static void lpc17_tbfree(uint8_t *buffer); static uint8_t *lpc17_allocio(void); static void lpc17_freeio(uint8_t *buffer); #endif -#ifdef CONFIG_USBHOST_ASYNCH -static struct lpc17_asynch_s *lpc17_allocasynch(void); -static void lpc17_freeasynch(struct lpc17_asynch_s *asynch); -#endif +static struct lpc17_xfrinfo_s *lpc17_alloc_xfrinfo(void); +static void lpc17_free_xfrinfo(struct lpc17_xfrinfo_s *xfrinfo); /* ED list helper functions ****************************************************/ @@ -375,8 +382,8 @@ static void lpc17_dma_free(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed, uint8_t *userbuffer, size_t buflen, uint8_t *alloc); #endif -static int lpc17_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, - uint8_t *buffer, size_t buflen); +static ssize_t lpc17_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, + uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void lpc17_asynch_completion(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed); @@ -425,12 +432,10 @@ static struct lpc17_list_s *g_tbfree; /* List of unused transfer buffers */ static struct lpc17_list_s *g_iofree; /* List of unused I/O buffers */ #endif -#ifdef CONFIG_USBHOST_ASYNCH -/* Pool and freelist of asynchronous transfer structures */ +/* Pool and freelist of transfer structures */ -static struct lpc17_list_s *g_asynchfree; -static struct lpc17_asynch_s g_asynchbuffers[CONFIG_LPC17_USBHOST_NASYNCH]; -#endif +static struct lpc17_list_s *g_xfrfree; +static struct lpc17_xfrinfo_s g_xfrbuffers[CONFIG_LPC17_USBHOST_NPREALLOC]; /******************************************************************************* * Public Data @@ -791,7 +796,7 @@ static void lpc17_freeio(uint8_t *buffer) #endif /******************************************************************************* - * Name: lpc17_allocasynch + * Name: lpc17_alloc_xfrinfo * * Description: * Allocate an asynchronous data structure from the free list @@ -802,25 +807,23 @@ static void lpc17_freeio(uint8_t *buffer) * *******************************************************************************/ -#ifdef CONFIG_USBHOST_ASYNCH -static struct lpc17_asynch_s *lpc17_allocasynch(void) +static struct lpc17_xfrinfo_s *lpc17_alloc_xfrinfo(void) { - struct lpc17_asynch_s *ret; + struct lpc17_xfrinfo_s *ret; irqstate_t flags; - /* lpc17_freeasynch() may be called from the interrupt level */ + /* lpc17_free_xfrinfo() may be called from the interrupt level */ flags = irqsave(); - ret = (struct lpc17_asynch_s *)g_asynchfree; + ret = (struct lpc17_xfrinfo_s *)g_xfrfree; if (ret) { - g_asynchfree = ((struct lpc17_list_s*)ret)->flink; + g_xfrfree = ((struct lpc17_list_s*)ret)->flink; } irqrestore(flags); return ret; } -#endif /******************************************************************************* * Name: lpc17_freeio @@ -830,8 +833,7 @@ static struct lpc17_asynch_s *lpc17_allocasynch(void) * *******************************************************************************/ -#ifdef CONFIG_USBHOST_ASYNCH -static void lpc17_freeasynch(struct lpc17_asynch_s *asynch) +static void lpc17_free_xfrinfo(struct lpc17_xfrinfo_s *xfrinfo) { struct lpc17_list_s *node; irqstate_t flags; @@ -839,12 +841,11 @@ static void lpc17_freeasynch(struct lpc17_asynch_s *asynch) /* Could be called from the interrupt level */ flags = irqsave(); - node = (struct lpc17_list_s *)asynch; - node->flink = g_asynchfree; - g_asynchfree = node; + node = (struct lpc17_list_s *)xfrinfo; + node->flink = g_xfrfree; + g_xfrfree = node; irqrestore(flags); } -#endif /******************************************************************************* * Name: lpc17_addctrled @@ -1453,9 +1454,13 @@ static int lpc17_enqueuetd(struct lpc17_usbhost_s *priv, static int lpc17_wdhwait(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed) { + struct lpc17_xfrinfo_s *xfrinfo; irqstate_t flags = irqsave(); int ret = -ENODEV; + DEBUGASSERT(ed && ed->xfrinfo); + xfrinfo = ed->xfrinfo; + /* Is the device still connected? */ if (priv->connected) @@ -1464,11 +1469,8 @@ static int lpc17_wdhwait(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed) * either (1) the device is disconnected, or (2) the transfer completed. */ - ed->wdhwait = true; -#ifdef CONFIG_USBHOST_ASYNCH - ed->asynch = NULL; -#endif - ret = OK; + xfrinfo->wdhwait = true; + ret = OK; } irqrestore(flags); @@ -1492,19 +1494,44 @@ static int lpc17_wdhwait(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed) static int lpc17_ctrltd(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed, uint32_t dirpid, uint8_t *buffer, size_t buflen) { + struct lpc17_xfrinfo_s *xfrinfo; uint32_t toggle; uint32_t regval; int ret; + xfrinfo = ed->xfrinfo; + DEBUGASSERT(xfrinfo); + + /* Allocate a structure to retain the information needed when the asynchronous + * transfer completes. + */ + + xfrinfo = lpc17_alloc_xfrinfo(); + if (xfrinfo == NULL) + { + udbg("ERROR: lpc17_alloc_xfrinfo failed\n"); + return -ENOMEM; + } + + /* Initialize the transfer structure */ + + memset(xfrinfo, 0, sizeof(struct lpc17_xfrinfo_s)); + xfrinfo->buffer = buffer; +#if defined(CONFIG_USBHOST_ASYNCH) && LPC17_IOBUFFERS > 0 + xfrinfo->buflen = buflen; +#endif + + ed->xfrinfo = xfrinfo; + /* Set the request for the Writeback Done Head event well BEFORE enabling the * transfer. */ ret = lpc17_wdhwait(priv, ed); - if (ret != OK) + if (ret < 0) { udbg("ERROR: Device disconnected\n"); - return ret; + goto errout_with_xfrinfo; } /* Configure the toggle field in the TD */ @@ -1520,7 +1547,7 @@ static int lpc17_ctrltd(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed, /* Then enqueue the transfer */ - ed->tdstatus = TD_CC_NOERROR; + xfrinfo->tdstatus = TD_CC_NOERROR; ret = lpc17_enqueuetd(priv, ed, dirpid, toggle, buffer, buflen); if (ret == OK) { @@ -1538,20 +1565,22 @@ static int lpc17_ctrltd(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed, /* Check the TD completion status bits */ - if (ed->tdstatus == TD_CC_NOERROR) + if (xfrinfo->tdstatus == TD_CC_NOERROR) { ret = OK; } else { uvdbg("Bad TD completion status: %d\n", ed->tdstatus); - ret = ed->tdstatus == TD_CC_STALL ? -EPERM : -EIO; + ret = xfrinfo->tdstatus == TD_CC_STALL ? -EPERM : -EIO; } } /* Make sure that there is no outstanding request on this endpoint */ - ed->wdhwait = false; +errout_with_xfrinfo: + lpc17_free_xfrinfo(xfrinfo); + ed->xfrinfo = NULL; return ret; } @@ -1566,6 +1595,9 @@ static int lpc17_ctrltd(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed, static int lpc17_usbinterrupt(int irq, void *context) { struct lpc17_usbhost_s *priv = &g_usbhost; + struct lpc17_ed_s *ed; + struct lpc17_xfrinfo_s *xfrinfo; + uintptr_t tmp; uint32_t intst; uint32_t pending; uint32_t regval; @@ -1721,50 +1753,60 @@ static int lpc17_usbinterrupt(int irq, void *context) { /* Get the ED in which this TD was enqueued */ - struct lpc17_ed_s *ed = td->ed; - DEBUGASSERT(ed != NULL); + ed = td->ed; + DEBUGASSERT(ed != NULL && ed->xfrinfo != NULL); + xfrinfo = ed->xfrinfo; /* Save the condition code from the (single) TD status/control * word. */ - ed->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT; + xfrinfo->tdstatus = (td->hw.ctrl & GTD_STATUS_CC_MASK) >> GTD_STATUS_CC_SHIFT; #ifdef CONFIG_DEBUG_USB - if (ed->tdstatus != TD_CC_NOERROR) + if (xfrinfo->tdstatus != TD_CC_NOERROR) { /* The transfer failed for some reason... dump some diagnostic info. */ ulldbg("ERROR: ED xfrtype:%d TD CTRL:%08x/CC:%d RHPORTST1:%08x\n", - ed->xfrtype, td->hw.ctrl, ed->tdstatus, + ed->xfrtype, td->hw.ctrl, xfrinfo->tdstatus, lpc17_getreg(LPC17_USBHOST_RHPORTST1)); } #endif + /* Determine the size of the transfer by subtracting the + * current buffer pointer (CBP) from the initial buffer + * pointer (on packet receipt only). + */ + + tmp = (uintptr_t)td->hw.cbp - (uintptr_t)xfrinfo->buffer; + DEBUGASSERT(tmp < UINT16_MAX); + + xfrinfo->xfrd = (uint16_t)tmp; + /* Return the TD to the free list */ next = (struct lpc17_gtd_s *)td->hw.nexttd; lpc17_tdfree(td); + if (xfrinfo->wdhwait) + { + /* Wake up the thread waiting for the WDH event */ + + lpc17_givesem(&ed->wdhsem); + xfrinfo->wdhwait = false; + } #ifdef CONFIG_USBHOST_ASYNCH /* Perform any pending callbacks for the case of asynchronous * transfers. */ - if (ed->asynch) + else if (xfrinfo->callback) { - DEBUGASSERT(ed->wdhwait == false); + DEBUGASSERT(xfrinfo->wdhwait == false); lpc17_asynch_completion(priv, ed); } - else #endif - if (ed->wdhwait) - { - /* Wake up the thread waiting for the WDH event */ - - lpc17_givesem(&ed->wdhsem); - ed->wdhwait = false; - } } } @@ -2165,7 +2207,7 @@ static int lpc17_epalloc(struct usbhost_driver_s *drvr, /* Was the ED successfully added? */ - if (ret != OK) + if (ret < 0) { /* No.. destroy it and report the error */ @@ -2572,12 +2614,15 @@ static int lpc17_transfer_common(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed, uint8_t *buffer, size_t buflen) { + struct lpc17_xfrinfo_s *xfrinfo; uint32_t dirpid; uint32_t regval; bool in; int ret; - in = (ed->hw.ctrl & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN; + xfrinfo = ed->xfrinfo; + in = (ed->hw.ctrl & ED_CONTROL_D_MASK) == ED_CONTROL_D_IN; + uvdbg("EP%u %s toggle:%u maxpacket:%u buflen:%lu\n", (ed->hw.ctrl & ED_CONTROL_EN_MASK) >> ED_CONTROL_EN_SHIFT, in ? "IN" : "OUT", @@ -2598,7 +2643,7 @@ static int lpc17_transfer_common(struct lpc17_usbhost_s *priv, /* Then enqueue the transfer */ - ed->tdstatus = TD_CC_NOERROR; + xfrinfo->tdstatus = TD_CC_NOERROR; ret = lpc17_enqueuetd(priv, ed, dirpid, GTD_STATUS_T_TOGGLE, buffer, buflen); if (ret == OK) { @@ -2767,8 +2812,9 @@ static void lpc17_dma_free(struct lpc17_usbhost_s *priv, * buflen - The length of the data to be sent or received. * * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure: + * On success, a non-negative value is returned that indicates the number + * of bytes successfully transferred. On a failure, a negated errno value is + * returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -2782,23 +2828,21 @@ static void lpc17_dma_free(struct lpc17_usbhost_s *priv, * *******************************************************************************/ -static int lpc17_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, - uint8_t *buffer, size_t buflen) +static ssize_t lpc17_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, + uint8_t *buffer, size_t buflen) { struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr; struct lpc17_ed_s *ed = (struct lpc17_ed_s *)ep; + struct lpc17_xfrinfo_s *xfrinfo; #if LPC17_IOBUFFERS > 0 uint8_t *alloc = NULL; uint8_t *userbuffer = NULL; #endif + ssize_t nbytes; int ret; DEBUGASSERT(priv && ed && buffer && buflen > 0); -#ifdef CONFIG_USBHOST_ASYNCH - DEBUGASSERT(ed->wdhwait == false && ed->asynch == NULL); -#else - DEBUGASSERT(ed->wdhwait == false); -#endif + DEBUGASSERT(ed->xfrinfo == NULL); /* We must have exclusive access to the endpoint, the TD pool, the I/O buffer * pool, the bulk and interrupt lists, and the HCCA interrupt table. @@ -2806,6 +2850,28 @@ static int lpc17_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, lpc17_takesem(&priv->exclsem); + /* Allocate a structure to retain the information needed when the asynchronous + * transfer completes. + */ + + xfrinfo = lpc17_alloc_xfrinfo(); + if (xfrinfo == NULL) + { + udbg("ERROR: lpc17_alloc_xfrinfo failed\n"); + nbytes = -ENOMEM; + goto errout_with_sem; + } + + /* Initialize the transfer structure */ + + memset(xfrinfo, 0, sizeof(struct lpc17_xfrinfo_s)); + xfrinfo->buffer = buffer; +#if defined(CONFIG_USBHOST_ASYNCH) && LPC17_IOBUFFERS > 0 + xfrinfo->buflen = buflen; +#endif + + ed->xfrinfo = xfrinfo; + #if LPC17_IOBUFFERS > 0 /* Allocate an IO buffer if the user buffer does not lie in AHB SRAM */ @@ -2813,7 +2879,8 @@ static int lpc17_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, if (ret < 0) { udbg("ERROR: lpc17_dma_alloc failed: %d\n", ret); - goto errout_with_sem; + nbytes = (ssize_t)ret; + goto errout_with_xfrinfo; } /* If a buffer was allocated, then use it instead of the callers buffer */ @@ -2830,9 +2897,10 @@ static int lpc17_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, */ ret = lpc17_wdhwait(priv, ed); - if (ret != OK) + if (ret < 0) { udbg("ERROR: Device disconnected\n"); + nbytes = (ssize_t)ret; goto errout_with_buffers; } @@ -2842,6 +2910,7 @@ static int lpc17_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, if (ret < 0) { udbg("ERROR: lpc17_transfer_common failed: %d\n", ret); + nbytes = (ssize_t)ret; goto errout_with_wdhwait; } @@ -2851,20 +2920,25 @@ static int lpc17_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* Check the TD completion status bits */ - if (ed->tdstatus == TD_CC_NOERROR) + if (xfrinfo->tdstatus == TD_CC_NOERROR) { - ret = OK; + /* Return the number of bytes successfully transferred */ + + nbytes = xfrinfo->xfrd; + DEBUGASSERT(nbytes >=0 && nbytes <= buflen); } else { - udbg("ERROR: Bad TD completion status: %d\n", ed->tdstatus); - ret = -EIO; + /* Return an I/O error */ + + udbg("ERROR: Bad TD completion status: %d\n", xfrinfo->tdstatus); + nbytes = -EIO; } errout_with_wdhwait: /* Make sure that there is no outstanding request on this endpoint */ - ed->wdhwait = false; + xfrinfo->wdhwait = false; errout_with_buffers: #if LPC17_IOBUFFERS > 0 @@ -2873,9 +2947,15 @@ errout_with_buffers: lpc17_dma_free(priv, ed, userbuffer, buflen, alloc); #endif +errout_with_xfrinfo: + /* Make sure that there is no outstanding request on this endpoint */ + + lpc17_free_xfrinfo(xfrinfo); + ed->xfrinfo = NULL; + errout_with_sem: lpc17_givesem(&priv->exclsem); - return ret; + return nbytes; } /******************************************************************************* @@ -2902,54 +2982,56 @@ errout_with_sem: static void lpc17_asynch_completion(struct lpc17_usbhost_s *priv, struct lpc17_ed_s *ed) { - struct lpc17_asynch_s *asynch; + struct lpc17_xfrinfo_s *xfrinfo; usbhost_asynch_t callback; void *arg; - int result; + ssize_t nbytes; - DEBUGASSERT(ed != NULL && ed->wdhwait == false && ed->asynch != NULL); - asynch = ed->asynch; + DEBUGASSERT(ed != NULL && ed->xfrinfo != NULL); + xfrinfo = ed->xfrinfo; - DEBUGASSERT(asynch->callback != NULL && asynch->user != NULL && asynch->buflen > 0); + DEBUGASSERT(xfrinfo->wdhwait == false && xfrinfo->callback != NULL && + xfrinfo->buffer != NULL); + +#if LPC17_IOBUFFERS > 0 + DEBUGASSERT(xfrinfo->buflen > 0); +#endif /* Check the TD completion status bits */ - if (ed->tdstatus == TD_CC_NOERROR) + if (xfrinfo->tdstatus == TD_CC_NOERROR) { - result = OK; + /* Provide the number of bytes successfully transferred */ + + nbytes = xfrinfo->xfrd; } else { - udbg("ERROR: Bad TD completion status: %d\n", ed->tdstatus); - result = -EIO; + /* Provide an I/O error indication */ + + udbg("ERROR: Bad TD completion status: %d\n", xfrinfo->tdstatus); + nbytes = -EIO; } #if LPC17_IOBUFFERS > 0 /* Free any temporary IO buffers */ - lpc17_dma_free(priv, ed, asynch->user, asynch->buflen, asynch->alloc); + lpc17_dma_free(priv, ed, xfrinfo->buffer, xfrinfo->buflen, xfrinfo->alloc); #endif /* Extract the callback information before freeing the buffer */ - callback = asynch->callback; - arg = asynch->arg; - - /* Clear any pending transfer indicators */ - - ed->wdhwait = false; - ed->asynch = NULL; + callback = xfrinfo->callback; + arg = xfrinfo->arg; /* Make sure that there is no outstanding request on this endpoint */ -#ifdef CONFIG_DEBUG - memset(asynch, 0, sizeof(struct lpc17_asynch_s)); -#endif - lpc17_freeasynch(asynch); + lpc17_free_xfrinfo(xfrinfo); + ed->xfrinfo = NULL; /* Then perform the callback */ - callback(arg, result); + callback(arg, nbytes); } #endif @@ -2995,11 +3077,10 @@ static int lpc17_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, { struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr; struct lpc17_ed_s *ed = (struct lpc17_ed_s *)ep; - struct lpc17_asynch_s *asynch; + struct lpc17_xfrinfo_s *xfrinfo; int ret; - DEBUGASSERT(priv && ed && buffer && buflen > 0 && callback); - DEBUGASSERT(ed->wdhwait == false && ed->asynch == NULL); + DEBUGASSERT(priv && ed && ed->xfrinfo == NULL && buffer && buflen > 0 && callback); /* We must have exclusive access to the endpoint, the TD pool, the I/O buffer * pool, the bulk and interrupt lists, and the HCCA interrupt table. @@ -3011,25 +3092,30 @@ static int lpc17_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, * transfer completes. */ - asynch = lpc17_allocasynch(); - if (asynch == NULL) + xfrinfo = lpc17_alloc_xfrinfo(); + if (xfrinfo == NULL) { - udbg("ERROR: lpc17_allocasynch failed\n"); + udbg("ERROR: lpc17_alloc_xfrinfo failed\n"); ret = -ENOMEM; goto errout_with_sem; } - /* Initialize the asynch structure */ - - asynch->buflen = buflen; - asynch->user = buffer; - asynch->callback = callback; - asynch->arg = arg; + /* Initialize the transfer structure */ + memset(xfrinfo, 0, sizeof(struct lpc17_xfrinfo_s)); + xfrinfo->buffer = buffer; #if LPC17_IOBUFFERS > 0 + xfrinfo->buflen = buflen; +#endif + xfrinfo->callback = callback; + xfrinfo->arg = arg; + + ed->xfrinfo = xfrinfo; + + #if LPC17_IOBUFFERS > 0 /* Allocate an IO buffer if the user buffer does not lie in AHB SRAM */ - ret = lpc17_dma_alloc(priv, ed, buffer, buflen, &asynch->alloc); + ret = lpc17_dma_alloc(priv, ed, buffer, buflen, &xfrinfo->alloc); if (ret < 0) { udbg("ERROR: lpc17_dma_alloc failed: %d\n", ret); @@ -3038,17 +3124,12 @@ static int lpc17_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, /* If a buffer was allocated, then use it instead of the callers buffer */ - if (asynch->alloc) + if (xfrinfo->alloc) { - buffer = asynch->alloc; + buffer = xfrinfo->alloc; } #endif - /* Set the callback information BEFORE enabling the transfer. */ - - ed->wdhwait = false; - ed->asynch = asynch; - /* Set up the transfer */ ret = lpc17_transfer_common(priv, ed, buffer, buflen); @@ -3069,12 +3150,13 @@ errout_with_asynch: #if LPC17_IOBUFFERS > 0 /* Free any temporary IO buffers */ - lpc17_dma_free(priv, ed, buffer, buflen, asynch->alloc); + lpc17_dma_free(priv, ed, buffer, buflen, xfrinfo->alloc); #endif - /* Free the asynchronous structure */ + /* Free the transfer structure */ - lpc17_freeasynch(asynch); + lpc17_free_xfrinfo(xfrinfo); + ed->xfrinfo = NULL; errout_with_sem: lpc17_givesem(&priv->exclsem); @@ -3106,28 +3188,32 @@ static int lpc17_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) struct lpc17_ed_s *ed = (struct lpc17_ed_s *)ep; struct lpc17_gtd_s *td; struct lpc17_gtd_s *next; - struct lpc17_asynch_s *asynch; + struct lpc17_xfrinfo_s *xfrinfo; irqstate_t flags; - int ret; + int ret = OK; /* These first steps must be atomic as possible */ flags = irqsave(); - /* It might be possible for no transfer to be in progress (asynch == NULL), - * but it would be an usage error to use the interface to try to cancel a - * synchronous transfer (wdhwait == true). - */ + /* It might be possible for no transfer to be in progress */ - DEBUGASSERT(ed != NULL && ed->wdhwait == false); - asynch = ed->asynch; - if (asynch) + DEBUGASSERT(ed != NULL && ed->xfrinfo != NULL); + xfrinfo = ed->xfrinfo; + + if (xfrinfo) { + /* It would be an usage error to use the interface to try to cancel a + * synchronous transfer (wdhwait == true). + */ + + DEBUGASSERT(xfrinfo->wdhwait == false); + /* We really need some kind of atomic test and set to do this right */ - td = (struct lpc17_gtd_s *)(ed->hw.headp & ED_HEADP_ADDR_MASK); - ed->hw.headp = LPC17_TDTAIL_ADDR; - ed->asynch = NULL; + td = (struct lpc17_gtd_s *)(ed->hw.headp & ED_HEADP_ADDR_MASK); + ed->hw.headp = LPC17_TDTAIL_ADDR; + ed->xfrinfo = NULL; /* Free all transfer descriptors that were connected to the ED */ @@ -3139,13 +3225,16 @@ static int lpc17_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) td = next; } - memset(asynch, 0, sizeof(struct lpc17_asynch_s)); - lpc17_freeasynch(asynch); + ret = xfrinfo->wdhwait ? -EINVAL : OK; + + /* Free the transfer structure */ + + lpc17_free_xfrinfo(xfrinfo); + ed->xfrinfo = NULL; } /* Determine the return value */ - ret = ed->wdhwait ? -EINVAL : OK; irqrestore(flags); return ret; } @@ -3229,9 +3318,7 @@ static int lpc17_connect(FAR struct usbhost_driver_s *drvr, static void lpc17_disconnect(struct usbhost_driver_s *drvr, struct usbhost_hubport_s *hport) { - struct lpc17_usbhost_s *priv = (struct lpc17_usbhost_s *)drvr; - DEBUGASSERT(priv != NULL && hport != NULL); - + DEBUGASSERT(hport != NULL); hport->devclass = NULL; } @@ -3310,9 +3397,7 @@ struct usbhost_connection_s *lpc17_usbhost_initialize(int controller) struct lpc17_usbhost_s *priv = &g_usbhost; struct usbhost_driver_s *drvr; struct usbhost_hubport_s *hport; -#ifdef CONFIG_USBHOST_ASYNCH - struct lpc17_asynch_s *asynch; -#endif + struct lpc17_xfrinfo_s *xfrinfo; uint32_t regval; uint8_t *buffer; irqstate_t flags; @@ -3496,18 +3581,16 @@ struct usbhost_connection_s *lpc17_usbhost_initialize(int controller) } #endif -#ifdef CONFIG_USBHOST_ASYNCH - /* Initialize asynchronous transfer structures */ + /* Initialize transfer structures */ - for (i = 0, asynch = g_asynchbuffers; - i < CONFIG_LPC17_USBHOST_NASYNCH; - i++, asynch++) + for (i = 0, xfrinfo = g_xfrbuffers; + i < CONFIG_LPC17_USBHOST_NPREALLOC; + i++, xfrinfo++) { - /* Put the asynch structure in a free list */ + /* Put the transfer structure in a free list */ - lpc17_freeasynch(asynch); + lpc17_free_xfrinfo(xfrinfo); } -#endif /* Wait 50MS then perform hardware reset */ diff --git a/arch/arm/src/lpc31xx/lpc31_ehci.c b/arch/arm/src/lpc31xx/lpc31_ehci.c index eec4f7cafef..21cc26e72f1 100644 --- a/arch/arm/src/lpc31xx/lpc31_ehci.c +++ b/arch/arm/src/lpc31xx/lpc31_ehci.c @@ -545,7 +545,7 @@ static int lpc31_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static int lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, +static ssize_t lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int lpc31_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, @@ -2630,6 +2630,7 @@ static inline int lpc31_asynch_setup(struct lpc31_rhport_s *rhport, static void lpc31_asynch_completion(struct lpc31_epinfo_s *epinfo) { usbhost_asynch_t callback; + ssize_t nbytes; void *arg; int result; @@ -2641,15 +2642,23 @@ static void lpc31_asynch_completion(struct lpc31_epinfo_s *epinfo) callback = epinfo->callback; arg = epinfo->arg; result = epinfo->result; + nbytes = epinfo->xfrd; epinfo->callback = NULL; epinfo->arg = NULL; epinfo->result = OK; epinfo->iocwait = false; - /* Then perform the callback */ + /* Then perform the callback. Provide the number of bytes successfully + * transferred or the negated errno value in the event of a failure. + */ - callback(arg, result); + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); } #endif @@ -4273,8 +4282,9 @@ static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * buflen - The length of the data to be sent or received. * * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure: + * On success, a non-negative value is returned that indicates the number + * of bytes successfully transferred. On a failure, a negated errno value is + * returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4288,8 +4298,8 @@ static int lpc31_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * *******************************************************************************/ -static int lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, + FAR uint8_t *buffer, size_t buflen) { struct lpc31_rhport_s *rhport = (struct lpc31_rhport_s *)drvr; struct lpc31_epinfo_s *epinfo = (struct lpc31_epinfo_s *)ep; @@ -4347,13 +4357,13 @@ static int lpc31_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, nbytes = lpc31_transfer_wait(epinfo); lpc31_givesem(&g_ehci.exclsem); - return nbytes >= 0 ? OK : (int)nbytes; + return nbytes; errout_with_iocwait: epinfo->iocwait = false; errout_with_sem: lpc31_givesem(&g_ehci.exclsem); - return ret; + return (ssize_t)ret; } /******************************************************************************* @@ -4676,12 +4686,7 @@ static int lpc31_connect(FAR struct usbhost_driver_s *drvr, static void lpc31_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport) { - struct lpc31_rhport_s *rhport = (struct lpc31_rhport_s *)drvr; - DEBUGASSERT(rhport != NULL && hport != NULL); - - /* Unbind the class */ - /* REVISIT: Is there more that needs to be done? */ - + DEBUGASSERT(hport != NULL); hport->devclass = NULL; } diff --git a/arch/arm/src/sama5/sam_ehci.c b/arch/arm/src/sama5/sam_ehci.c index 6f9d6ecfef1..a898e9c86c8 100644 --- a/arch/arm/src/sama5/sam_ehci.c +++ b/arch/arm/src/sama5/sam_ehci.c @@ -421,7 +421,7 @@ static int sam_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR uint8_t *buffer); static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, +static ssize_t sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int sam_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, @@ -2448,6 +2448,7 @@ static inline int sam_asynch_setup(struct sam_rhport_s *rhport, static void sam_asynch_completion(struct sam_epinfo_s *epinfo) { usbhost_asynch_t callback; + ssize_t nbytes; void *arg; int result; @@ -2459,15 +2460,23 @@ static void sam_asynch_completion(struct sam_epinfo_s *epinfo) callback = epinfo->callback; arg = epinfo->arg; result = epinfo->result; + nbytes = epinfo->xfrd; epinfo->callback = NULL; epinfo->arg = NULL; epinfo->result = OK; epinfo->iocwait = false; - /* Then perform the callback */ + /* Then perform the callback. Provide the number of bytes successfully + * transferred or the negated errno value in the event of a failure. + */ - callback(arg, result); + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); } #endif @@ -4099,8 +4108,9 @@ static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * buflen - The length of the data to be sent or received. * * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure: + * On success, a non-negative value is returned that indicates the number + * of bytes successfully transferred. On a failure, a negated errno value is + * returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4114,8 +4124,8 @@ static int sam_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * *******************************************************************************/ -static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, + FAR uint8_t *buffer, size_t buflen) { struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr; struct sam_epinfo_s *epinfo = (struct sam_epinfo_s *)ep; @@ -4174,13 +4184,13 @@ static int sam_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, nbytes = sam_transfer_wait(epinfo); sam_givesem(&g_ehci.exclsem); - return nbytes >= 0 ? OK : (int)nbytes; + return nbytes; errout_with_iocwait: epinfo->iocwait = false; errout_with_sem: sam_givesem(&g_ehci.exclsem); - return ret; + return (ssize_t)ret; } /******************************************************************************* @@ -4503,13 +4513,8 @@ static int sam_connect(FAR struct usbhost_driver_s *drvr, static void sam_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport) { - struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr; - DEBUGASSERT(rhport != NULL && hport != NULL); - - /* Unbind the class */ - /* REVISIT: Is there more that needs to be done? */ - - rhport->hport.hport.devclass = NULL; + DEBUGASSERT(hport != NULL); + hport->devclass = NULL; } /******************************************************************************* diff --git a/arch/arm/src/sama5/sam_ohci.c b/arch/arm/src/sama5/sam_ohci.c index b0a0896109d..2a03aaa0e83 100644 --- a/arch/arm/src/sama5/sam_ohci.c +++ b/arch/arm/src/sama5/sam_ohci.c @@ -219,14 +219,15 @@ struct sam_eplist_s { - volatile bool wdhwait; /* TRUE: Thread is waiting for WDH interrupt */ - sem_t wdhsem; /* Semaphore used to wait for Writeback Done Head event */ + volatile bool wdhwait; /* TRUE: Thread is waiting for WDH interrupt */ + sem_t wdhsem; /* Semaphore used to wait for Writeback Done Head event */ #ifdef CONFIG_USBHOST_ASYNCH - usbhost_asynch_t callback; /* Transfer complete callback */ - void *arg; /* Argument that accompanies the callback */ - uint8_t *buffer; /* Buffer being transferred */ - uint16_t buflen; /* Length of the buffer */ + usbhost_asynch_t callback; /* Transfer complete callback */ + void *arg; /* Argument that accompanies the callback */ + uint16_t buflen; /* Length of the buffer */ #endif + uint8_t *buffer; /* Buffer being transferred */ + uint16_t xfrd; /* Number of bytes completed in the last transfer */ struct sam_ed_s *ed; /* Endpoint descriptor (ED) */ struct sam_gtd_s *tail; /* Tail transfer descriptor (TD) */ }; @@ -444,8 +445,8 @@ static int sam_ctrlout(struct usbhost_driver_s *drvr, usbhost_ep_t ep0, static int sam_transfer_common(struct sam_rhport_s *rhport, struct sam_eplist_s *eplist, uint8_t *buffer, size_t buflen); -static int sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, - uint8_t *buffer, size_t buflen); +static ssize_t sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, + uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void sam_asynch_completion(struct sam_eplist_s *eplist); static int sam_asynch(struct usbhost_driver_s *drvr, usbhost_ep_t ep, @@ -2077,6 +2078,8 @@ static void sam_wdh_bottomhalf(void) struct sam_gtd_s *td; struct sam_gtd_s *next; struct sam_ed_s *ed; + uintptr_t paddr; + uintptr_t tmp; /* The host controller just wrote the one finished TDs into the HCCA * done head. This may include multiple packets that were transferred @@ -2147,6 +2150,16 @@ static void sam_wdh_bottomhalf(void) } #endif + /* Determine the size of the transfer by subtracting the current buffer + * pointer (CBP) from the initial buffer pointer (on packet receipt only). + */ + + paddr = sam_physramaddr((uintptr_t)eplist->buffer); + tmp = (uintptr_t)td->hw.cbp - paddr; + DEBUGASSERT(tmp < UINT16_MAX); + + eplist->xfrd = (uint16_t)tmp; + /* Return the TD to the free list */ next = (struct sam_gtd_s *)sam_virtramaddr(td->hw.nexttd); @@ -3253,12 +3266,13 @@ static int sam_transfer_common(struct sam_rhport_s *rhport, * *******************************************************************************/ -static int sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, - uint8_t *buffer, size_t buflen) +static ssize_t sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, + uint8_t *buffer, size_t buflen) { struct sam_rhport_s *rhport = (struct sam_rhport_s *)drvr; struct sam_eplist_s *eplist = (struct sam_eplist_s *)ep; struct sam_ed_s *ed; + ssize_t nbytes; bool in; int ret; @@ -3339,21 +3353,24 @@ static int sam_transfer(struct usbhost_driver_s *drvr, usbhost_ep_t ep, (uintptr_t)buffer + buflen); } - ret = OK; - } - else - { - usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, RHPORT(rhport), - ed->tdstatus); - ret = ed->tdstatus == TD_CC_STALL ? -EPERM : -EIO; + nbytes = eplist->xfrd; + DEBUGASSERT(nbytes >=0 && nbytes <= buflen); + + sam_givesem(&g_ohci.exclsem); + return nbytes; } + /* A transfer error occurred */ + + usbhost_trace2(OHCI_TRACE2_BADTDSTATUS, RHPORT(rhport), ed->tdstatus); + ret = ed->tdstatus == TD_CC_STALL ? -EPERM : -EIO; + errout: /* Make sure that there is no outstanding request on this endpoint */ eplist->wdhwait = false; sam_givesem(&g_ohci.exclsem); - return ret; + return (ssize_t)ret; } /******************************************************************************* @@ -3382,7 +3399,7 @@ static void sam_asynch_completion(struct sam_eplist_s *eplist) struct sam_ed_s *ed; usbhost_asynch_t callback; void *arg; - int result; + ssize_t nbytes; DEBUGASSERT(eplist->ed && eplist->tail && eplist->callback != NULL && eplist->buffer != NULL && eplist->buflen > 0); @@ -3407,12 +3424,13 @@ static void sam_asynch_completion(struct sam_eplist_s *eplist) arch_invalidate_dcache(buffaddr, buffaddr + eplist->buflen); } - result = OK; + nbytes = eplist->xfrd; + DEBUGASSERT(nbytes >= 0 && nbytes <= eplist->buflen); } else { usbhost_trace1(OHCI_TRACE1_BADTDSTATUS, ed->tdstatus); - result = ed->tdstatus == TD_CC_STALL ? -EPERM : -EIO; + nbytes = (ed->tdstatus == TD_CC_STALL) ? -EPERM : -EIO; } /* Extract the callback information before freeing the buffer */ @@ -3430,7 +3448,7 @@ static void sam_asynch_completion(struct sam_eplist_s *eplist) /* Then perform the callback */ - callback(arg, result); + callback(arg, nbytes); } #endif diff --git a/arch/arm/src/stm32/stm32_otgfshost.c b/arch/arm/src/stm32/stm32_otgfshost.c index ab5455d6435..137ffa66e76 100644 --- a/arch/arm/src/stm32/stm32_otgfshost.c +++ b/arch/arm/src/stm32/stm32_otgfshost.c @@ -220,7 +220,8 @@ struct stm32_chan_s bool in; /* True: IN endpoint */ volatile bool waiter; /* True: Thread is waiting for a channel event */ uint16_t maxpacket; /* Max packet size */ - volatile uint16_t buflen; /* Buffer length (remaining) */ + uint16_t buflen; /* Buffer length (at start of transfer) */ + volatile uint16_t xfrd; /* Bytes transferred (at end of transfer) */ volatile uint16_t inflight; /* Number of Tx bytes "in-flight" */ FAR uint8_t *buffer; /* Transfer buffer pointer */ #ifdef CONFIG_USBHOST_ASYNCH @@ -356,8 +357,8 @@ static int stm32_ctrl_recvdata(FAR struct stm32_usbhost_s *priv, FAR struct stm32_ctrlinfo_s *ep0, FAR uint8_t *buffer, unsigned int buflen); static int stm32_in_setup(FAR struct stm32_usbhost_s *priv, int chidx); -static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32_in_next(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); @@ -366,8 +367,8 @@ static int stm32_in_asynch(FAR struct stm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx); -static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32_out_next(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); @@ -441,8 +442,8 @@ static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, + FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, @@ -1104,7 +1105,7 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, ret = sem_wait(&chan->waitsem); - /* sem_wait should succeeed. But it is possible that we could be + /* sem_wait should succeed. But it is possible that we could be * awakened by a signal too. */ @@ -1402,6 +1403,7 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx) chan->result = EBUSY; chan->inflight = 0; + chan->xfrd = 0; priv->chidx = chidx; /* Compute the expected number of packets associated to the transfer. @@ -1611,11 +1613,12 @@ static int stm32_ctrl_sendsetup(FAR struct stm32_usbhost_s *priv, chan->pid = OTGFS_PID_SETUP; chan->buffer = (FAR uint8_t *)req; chan->buflen = USB_SIZEOF_CTRLREQ; + chan->xfrd = 0; /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); return ret; @@ -1677,6 +1680,7 @@ static int stm32_ctrl_senddata(FAR struct stm32_usbhost_s *priv, chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; /* Set the DATA PID */ @@ -1694,7 +1698,7 @@ static int stm32_ctrl_senddata(FAR struct stm32_usbhost_s *priv, /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); return ret; @@ -1730,11 +1734,12 @@ static int stm32_ctrl_recvdata(FAR struct stm32_usbhost_s *priv, chan->pid = OTGFS_PID_DATA1; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); return ret; @@ -1818,13 +1823,13 @@ static int stm32_in_setup(FAR struct stm32_usbhost_s *priv, int chidx) * *******************************************************************************/ -static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_chan_s *chan; uint32_t start; uint32_t elapsed; - int ret = OK; + int ret; /* Loop until the transfer completes (i.e., buflen is decremented to zero) * or a fatal error occurs (any error other than a simple NAK) @@ -1833,17 +1838,18 @@ static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; start = clock_systimer(); - while (chan->buflen > 0) + while (chan->xfrd < chan->buflen) { /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGFS_TRACE1_DEVDISCONN, 0); - return ret; + return (ssize_t)ret; } /* Set up for the transfer based on the direction and the endpoint type */ @@ -1852,7 +1858,7 @@ static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, if (ret < 0) { udbg("ERROR: stm32_in_setup failed: %d\n", ret); - return ret; + return (ssize_t)ret; } /* Wait for the transfer to complete and get the result */ @@ -1864,7 +1870,7 @@ static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, * cause use to return */ - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED,ret); @@ -1878,16 +1884,17 @@ static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, elapsed = clock_systimer() - start; if (ret != -EAGAIN || /* Not a NAK condition OR */ elapsed >= STM32_DATANAK_DELAY || /* Timeout has elapsed OR */ - chan->buflen != buflen) /* Data has been partially transferred */ + chan->xfrd > 0) /* Data has been partially transferred */ { /* Break out and return the error */ - break; + udbg("ERROR: stm32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; } } } - return ret; + return (ssize_t)chan->xfrd; } /******************************************************************************* @@ -1907,13 +1914,14 @@ static void stm32_in_next(FAR struct stm32_usbhost_s *priv, { usbhost_asynch_t callback; FAR void *arg; + ssize_t nbytes; int result; int ret; - /* Is the full transfer complete? Did the last chunk transfer complete OK?*/ + /* Is the full transfer complete? Did the last chunk transfer complete OK? */ - result = chan->result; - if (chan->buflen > 0 && result == OK) + result = -(int)chan->result; + if (chan->xfrd < chan->buflen && result == OK) { /* Yes.. Set up for the next transfer based on the direction and the * endpoint type @@ -1937,12 +1945,20 @@ static void stm32_in_next(FAR struct stm32_usbhost_s *priv, callback = chan->callback; arg = chan->arg; + nbytes = chan->xfrd; + chan->callback = NULL; chan->arg = NULL; + chan->xfrd = 0; /* Then perform the callback */ - callback(arg, chan->result); + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); } #endif @@ -1970,6 +1986,7 @@ static int stm32_in_asynch(FAR struct stm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; ret = stm32_chan_asynchsetup(priv, chan, callback, arg); if (ret < 0) @@ -2065,14 +2082,15 @@ static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx) * *******************************************************************************/ -static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_chan_s *chan; uint32_t start; uint32_t elapsed; size_t xfrlen; - int ret = OK; + ssize_t xfrd; + int ret; /* Loop until the transfer completes (i.e., buflen is decremented to zero) * or a fatal error occurs (any error other than a simple NAK) @@ -2080,6 +2098,7 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; start = clock_systimer(); + xfrd = 0; while (buflen > 0) { @@ -2091,14 +2110,15 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, xfrlen = MIN(chan->maxpacket, buflen); chan->buffer = buffer; chan->buflen = xfrlen; + chan->xfrd = 0; /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGFS_TRACE1_DEVDISCONN,0); - return ret; + return (ssize_t)ret; } /* Set up for the transfer based on the direction and the endpoint type */ @@ -2107,7 +2127,7 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, if (ret < 0) { udbg("ERROR: stm32_out_setup failed: %d\n", ret); - return ret; + return (ssize_t)ret; } /* Wait for the transfer to complete and get the result */ @@ -2116,7 +2136,7 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, /* Handle transfer failures */ - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGFS_TRACE1_TRNSFRFAILED,ret); @@ -2128,13 +2148,14 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, */ elapsed = clock_systimer() - start; - if (ret != -EAGAIN || /* Not a NAK condition OR */ - elapsed >= STM32_DATANAK_DELAY || /* Timeout has elapsed OR */ - chan->buflen != xfrlen) /* Data has been partially transferred */ + if (ret != -EAGAIN || /* Not a NAK condition OR */ + elapsed >= STM32_DATANAK_DELAY || /* Timeout has elapsed OR */ + chan->xfrd != xfrlen) /* Data has been partially transferred */ { /* Break out and return the error */ - break; + udbg("ERROR: stm32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; } /* Is this flush really necessary? What does the hardware do with the @@ -2155,10 +2176,11 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, buffer += xfrlen; buflen -= xfrlen; + xfrd += chan->xfrd; } } - return ret; + return xfrd; } /******************************************************************************* @@ -2178,13 +2200,14 @@ static void stm32_out_next(FAR struct stm32_usbhost_s *priv, { usbhost_asynch_t callback; FAR void *arg; + ssize_t nbytes; int result; int ret; /* Is the full transfer complete? Did the last chunk transfer complete OK?*/ - result = chan->result; - if (chan->buflen > 0 && result == OK) + result = -(int)chan->result; + if (chan->xfrd < chan->buflen && result == OK) { /* Yes.. Set up for the next transfer based on the direction and the * endpoint type @@ -2208,12 +2231,20 @@ static void stm32_out_next(FAR struct stm32_usbhost_s *priv, callback = chan->callback; arg = chan->arg; + nbytes = chan->xfrd; + chan->callback = NULL; chan->arg = NULL; + chan->xfrd = 0; /* Then perform the callback */ - callback(arg, chan->result); + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); } #endif @@ -2241,6 +2272,7 @@ static int stm32_out_asynch(FAR struct stm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; ret = stm32_chan_asynchsetup(priv, chan, callback, arg); if (ret < 0) @@ -2631,7 +2663,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, */ priv->chan[chidx].buffer += priv->chan[chidx].inflight; - priv->chan[chidx].buflen -= priv->chan[chidx].inflight; + priv->chan[chidx].xfrd += priv->chan[chidx].inflight; priv->chan[chidx].inflight = 0; /* Halt the channel -- the CHH interrupt is expected next */ @@ -2957,7 +2989,7 @@ static inline void stm32_gint_rxflvlisr(FAR struct stm32_usbhost_s *priv) /* Manage multiple packet transfers */ priv->chan[chidx].buffer += bcnt; - priv->chan[chidx].buflen -= bcnt; + priv->chan[chidx].xfrd += bcnt; /* Check if more packets are expected */ @@ -3015,15 +3047,15 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) */ chan->buffer += chan->inflight; - chan->buflen -= chan->inflight; + chan->xfrd += chan->inflight; chan->inflight = 0; - /* If we have now transfered the entire buffer, then this transfer is + /* If we have now transferred the entire buffer, then this transfer is * complete (this case really should never happen because we disable * the NPTXFE interrupt on the final packet). */ - if (chan->buflen <= 0) + if (chan->xfrd >= chan->buflen) { /* Disable further Tx FIFO empty interrupts and bail. */ @@ -3039,16 +3071,15 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) avail = ((regval & OTGFS_HNPTXSTS_NPTXFSAV_MASK) >> OTGFS_HNPTXSTS_NPTXFSAV_SHIFT) << 2; + /* Get the size to put in the Tx FIFO now */ + + wrsize = chan->buflen - chan->xfrd; + /* Get minimal size packet that can be sent. Something is seriously * configured wrong if one packet will not fit into the empty Tx FIFO. */ - DEBUGASSERT(chan->buflen > 0 && - avail >= MIN(chan->buflen, chan->maxpacket)); - - /* Get the size to put in the Tx FIFO now */ - - wrsize = chan->buflen; + DEBUGASSERT(wrsize > 0 && avail >= MIN(wrsize, chan->maxpacket)); if (wrsize > avail) { /* Clip the write size to the number of full, max sized packets @@ -3070,8 +3101,8 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - ullvdbg("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, wrsize); + ullvdbg("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); stm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -3104,7 +3135,7 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) */ chan->buffer += chan->inflight; - chan->buflen -= chan->inflight; + chan->xfrd += chan->inflight; chan->inflight = 0; /* If we have now transfered the entire buffer, then this transfer is @@ -3112,7 +3143,7 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) * the PTXFE interrupt on the final packet). */ - if (chan->buflen <= 0) + if (chan->xfrd >= chan->buflen) { /* Disable further Tx FIFO empty interrupts and bail. */ @@ -3128,16 +3159,15 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) avail = ((regval & OTGFS_HPTXSTS_PTXFSAVL_MASK) >> OTGFS_HPTXSTS_PTXFSAVL_SHIFT) << 2; + /* Get the size to put in the Tx FIFO now */ + + wrsize = chan->buflen - chan->xfrd; + /* Get minimal size packet that can be sent. Something is seriously * configured wrong if one packet will not fit into the empty Tx FIFO. */ - DEBUGASSERT(chan->buflen > 0 && - avail >= MIN(chan->buflen, chan->maxpacket)); - - /* Get the size to put in the Tx FIFO now */ - - wrsize = chan->buflen; + DEBUGASSERT(wrsize && avail >= MIN(wrsize, chan->maxpacket)); if (wrsize > avail) { /* Clip the write size to the number of full, max sized packets @@ -3159,8 +3189,8 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - ullvdbg("HPTXSTS: %08x chidx: %d avail: %d buflen: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, wrsize); + ullvdbg("HPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); stm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -4462,8 +4492,9 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * buflen - The length of the data to be sent or received. * * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure: + * On success, a non-negative value is returned that indicates the number + * of bytes successfully transferred. On a failure, a negated errno value is + * returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4477,12 +4508,12 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * *******************************************************************************/ -static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, + FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; unsigned int chidx = (unsigned int)ep; - int ret; + ssize_t nbytes; uvdbg("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); @@ -4496,15 +4527,15 @@ static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, if (priv->chan[chidx].in) { - ret = stm32_in_transfer(priv, chidx, buffer, buflen); + nbytes = stm32_in_transfer(priv, chidx, buffer, buflen); } else { - ret = stm32_out_transfer(priv, chidx, buffer, buflen); + nbytes = stm32_out_transfer(priv, chidx, buffer, buflen); } stm32_givesem(&priv->exclsem); - return ret; + return nbytes; } /******************************************************************************* @@ -4700,9 +4731,7 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport) { - FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; - DEBUGASSERT(priv != NULL && hport != NULL); - + DEBUGASSERT(hport != NULL); hport->devclass = NULL; } diff --git a/arch/arm/src/stm32/stm32_otghshost.c b/arch/arm/src/stm32/stm32_otghshost.c index 2bc898442fc..638caec1470 100644 --- a/arch/arm/src/stm32/stm32_otghshost.c +++ b/arch/arm/src/stm32/stm32_otghshost.c @@ -220,7 +220,8 @@ struct stm32_chan_s bool in; /* True: IN endpoint */ volatile bool waiter; /* True: Thread is waiting for a channel event */ uint16_t maxpacket; /* Max packet size */ - volatile uint16_t buflen; /* Buffer length (remaining) */ + uint16_t buflen; /* Buffer length (at start of transfer) */ + volatile uint16_t xfrd; /* Bytes transferred (at end of transfer) */ volatile uint16_t inflight; /* Number of Tx bytes "in-flight" */ FAR uint8_t *buffer; /* Transfer buffer pointer */ #ifdef CONFIG_USBHOST_ASYNCH @@ -356,8 +357,8 @@ static int stm32_ctrl_recvdata(FAR struct stm32_usbhost_s *priv, FAR struct stm32_ctrlinfo_s *ep0, FAR uint8_t *buffer, unsigned int buflen); static int stm32_in_setup(FAR struct stm32_usbhost_s *priv, int chidx); -static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32_in_next(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); @@ -366,8 +367,8 @@ static int stm32_in_asynch(FAR struct stm32_usbhost_s *priv, int chidx, usbhost_asynch_t callback, FAR void *arg); #endif static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx); -static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static void stm32_out_next(FAR struct stm32_usbhost_s *priv, FAR struct stm32_chan_s *chan); @@ -441,8 +442,8 @@ static int stm32_ctrlin(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, FAR const struct usb_ctrlreq_s *req, FAR const uint8_t *buffer); -static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, + FAR uint8_t *buffer, size_t buflen); #ifdef CONFIG_USBHOST_ASYNCH static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, FAR uint8_t *buffer, size_t buflen, @@ -1104,7 +1105,7 @@ static int stm32_chan_wait(FAR struct stm32_usbhost_s *priv, ret = sem_wait(&chan->waitsem); - /* sem_wait should succeeed. But it is possible that we could be + /* sem_wait should succeed. But it is possible that we could be * awakened by a signal too. */ @@ -1402,6 +1403,7 @@ static void stm32_transfer_start(FAR struct stm32_usbhost_s *priv, int chidx) chan->result = EBUSY; chan->inflight = 0; + chan->xfrd = 0; priv->chidx = chidx; /* Compute the expected number of packets associated to the transfer. @@ -1611,11 +1613,12 @@ static int stm32_ctrl_sendsetup(FAR struct stm32_usbhost_s *priv, chan->pid = OTGHS_PID_SETUP; chan->buffer = (FAR uint8_t *)req; chan->buflen = USB_SIZEOF_CTRLREQ; + chan->xfrd = 0; /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGHS_TRACE1_DEVDISCONN, 0); return ret; @@ -1677,6 +1680,7 @@ static int stm32_ctrl_senddata(FAR struct stm32_usbhost_s *priv, chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; /* Set the DATA PID */ @@ -1694,7 +1698,7 @@ static int stm32_ctrl_senddata(FAR struct stm32_usbhost_s *priv, /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGHS_TRACE1_DEVDISCONN, 0); return ret; @@ -1730,11 +1734,12 @@ static int stm32_ctrl_recvdata(FAR struct stm32_usbhost_s *priv, chan->pid = OTGHS_PID_DATA1; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGHS_TRACE1_DEVDISCONN, 0); return ret; @@ -1818,13 +1823,13 @@ static int stm32_in_setup(FAR struct stm32_usbhost_s *priv, int chidx) * *******************************************************************************/ -static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_chan_s *chan; uint32_t start; uint32_t elapsed; - int ret = OK; + int ret; /* Loop until the transfer completes (i.e., buflen is decremented to zero) * or a fatal error occurs (any error other than a simple NAK) @@ -1833,17 +1838,18 @@ static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; start = clock_systimer(); - while (chan->buflen > 0) + while (chan->xfrd < chan->buflen) { /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGHS_TRACE1_DEVDISCONN, 0); - return ret; + return (ssize_t)ret; } /* Set up for the transfer based on the direction and the endpoint type */ @@ -1852,7 +1858,7 @@ static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, if (ret < 0) { udbg("ERROR: stm32_in_setup failed: %d\n", ret); - return ret; + return (ssize_t)ret; } /* Wait for the transfer to complete and get the result */ @@ -1864,7 +1870,7 @@ static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, * cause use to return */ - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGHS_TRACE1_TRNSFRFAILED,ret); @@ -1878,16 +1884,17 @@ static int stm32_in_transfer(FAR struct stm32_usbhost_s *priv, int chidx, elapsed = clock_systimer() - start; if (ret != -EAGAIN || /* Not a NAK condition OR */ elapsed >= STM32_DATANAK_DELAY || /* Timeout has elapsed OR */ - chan->buflen != buflen) /* Data has been partially transferred */ + chan->xfrd > 0) /* Data has been partially transferred */ { /* Break out and return the error */ - break; + udbg("ERROR: stm32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; } } } - return ret; + return (ssize_t)chan->xfrd; } /******************************************************************************* @@ -1907,13 +1914,14 @@ static void stm32_in_next(FAR struct stm32_usbhost_s *priv, { usbhost_asynch_t callback; FAR void *arg; + ssize_t nbytes; int result; int ret; - /* Is the full transfer complete? Did the last chunk transfer complete OK?*/ + /* Is the full transfer complete? Did the last chunk transfer complete OK? */ - result = chan->result; - if (chan->buflen > 0 && result == OK) + result = -(int)chan->result; + if (chan->xfrd < chan->buflen && result == OK) { /* Yes.. Set up for the next transfer based on the direction and the * endpoint type @@ -1937,12 +1945,20 @@ static void stm32_in_next(FAR struct stm32_usbhost_s *priv, callback = chan->callback; arg = chan->arg; + nbytes = chan->xfrd; + chan->callback = NULL; chan->arg = NULL; + chan->xfrd = 0; /* Then perform the callback */ - callback(arg, chan->result); + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); } #endif @@ -1970,6 +1986,7 @@ static int stm32_in_asynch(FAR struct stm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; ret = stm32_chan_asynchsetup(priv, chan, callback, arg); if (ret < 0) @@ -2065,14 +2082,15 @@ static int stm32_out_setup(FAR struct stm32_usbhost_s *priv, int chidx) * *******************************************************************************/ -static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, + FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_chan_s *chan; uint32_t start; uint32_t elapsed; size_t xfrlen; - int ret = OK; + ssize_t xfrd; + int ret; /* Loop until the transfer completes (i.e., buflen is decremented to zero) * or a fatal error occurs (any error other than a simple NAK) @@ -2080,6 +2098,7 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; start = clock_systimer(); + xfrd = 0; while (buflen > 0) { @@ -2091,14 +2110,15 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, xfrlen = MIN(chan->maxpacket, buflen); chan->buffer = buffer; chan->buflen = xfrlen; + chan->xfrd = 0; /* Set up for the wait BEFORE starting the transfer */ ret = stm32_chan_waitsetup(priv, chan); - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGHS_TRACE1_DEVDISCONN,0); - return ret; + return (ssize_t)ret; } /* Set up for the transfer based on the direction and the endpoint type */ @@ -2107,7 +2127,7 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, if (ret < 0) { udbg("ERROR: stm32_out_setup failed: %d\n", ret); - return ret; + return (ssize_t)ret; } /* Wait for the transfer to complete and get the result */ @@ -2116,7 +2136,7 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, /* Handle transfer failures */ - if (ret != OK) + if (ret < 0) { usbhost_trace1(OTGHS_TRACE1_TRNSFRFAILED,ret); @@ -2128,13 +2148,14 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, */ elapsed = clock_systimer() - start; - if (ret != -EAGAIN || /* Not a NAK condition OR */ - elapsed >= STM32_DATANAK_DELAY || /* Timeout has elapsed OR */ - chan->buflen != xfrlen) /* Data has been partially transferred */ + if (ret != -EAGAIN || /* Not a NAK condition OR */ + elapsed >= STM32_DATANAK_DELAY || /* Timeout has elapsed OR */ + chan->xfrd != xfrlen) /* Data has been partially transferred */ { /* Break out and return the error */ - break; + udbg("ERROR: stm32_chan_wait failed: %d\n", ret); + return (ssize_t)ret; } /* Is this flush really necessary? What does the hardware do with the @@ -2155,10 +2176,11 @@ static int stm32_out_transfer(FAR struct stm32_usbhost_s *priv, int chidx, buffer += xfrlen; buflen -= xfrlen; + xfrd += chan->xfrd; } } - return ret; + return xfrd; } /******************************************************************************* @@ -2178,13 +2200,14 @@ static void stm32_out_next(FAR struct stm32_usbhost_s *priv, { usbhost_asynch_t callback; FAR void *arg; + ssize_t nbytes; int result; int ret; /* Is the full transfer complete? Did the last chunk transfer complete OK?*/ - result = chan->result; - if (chan->buflen > 0 && result == OK) + result = -(int)chan->result; + if (chan->xfrd < chan->buflen && result == OK) { /* Yes.. Set up for the next transfer based on the direction and the * endpoint type @@ -2208,12 +2231,20 @@ static void stm32_out_next(FAR struct stm32_usbhost_s *priv, callback = chan->callback; arg = chan->arg; + nbytes = chan->xfrd; + chan->callback = NULL; chan->arg = NULL; + chan->xfrd = 0; /* Then perform the callback */ - callback(arg, chan->result); + if (result < 0) + { + nbytes = (ssize_t)result; + } + + callback(arg, nbytes); } #endif @@ -2241,6 +2272,7 @@ static int stm32_out_asynch(FAR struct stm32_usbhost_s *priv, int chidx, chan = &priv->chan[chidx]; chan->buffer = buffer; chan->buflen = buflen; + chan->xfrd = 0; ret = stm32_chan_asynchsetup(priv, chan, callback, arg); if (ret < 0) @@ -2631,7 +2663,7 @@ static inline void stm32_gint_hcoutisr(FAR struct stm32_usbhost_s *priv, */ priv->chan[chidx].buffer += priv->chan[chidx].inflight; - priv->chan[chidx].buflen -= priv->chan[chidx].inflight; + priv->chan[chidx].xfrd += priv->chan[chidx].inflight; priv->chan[chidx].inflight = 0; /* Halt the channel -- the CHH interrupt is expected next */ @@ -2957,7 +2989,7 @@ static inline void stm32_gint_rxflvlisr(FAR struct stm32_usbhost_s *priv) /* Manage multiple packet transfers */ priv->chan[chidx].buffer += bcnt; - priv->chan[chidx].buflen -= bcnt; + priv->chan[chidx].xfrd += bcnt; /* Check if more packets are expected */ @@ -3015,15 +3047,15 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) */ chan->buffer += chan->inflight; - chan->buflen -= chan->inflight; + chan->xfrd += chan->inflight; chan->inflight = 0; - /* If we have now transfered the entire buffer, then this transfer is + /* If we have now transferred the entire buffer, then this transfer is * complete (this case really should never happen because we disable * the NPTXFE interrupt on the final packet). */ - if (chan->buflen <= 0) + if (chan->xfrd >= chan->buflen) { /* Disable further Tx FIFO empty interrupts and bail. */ @@ -3039,16 +3071,15 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) avail = ((regval & OTGHS_HNPTXSTS_NPTXFSAV_MASK) >> OTGHS_HNPTXSTS_NPTXFSAV_SHIFT) << 2; + /* Get the size to put in the Tx FIFO now */ + + wrsize = chan->buflen - chan->xfrd; + /* Get minimal size packet that can be sent. Something is seriously * configured wrong if one packet will not fit into the empty Tx FIFO. */ - DEBUGASSERT(chan->buflen > 0 && - avail >= MIN(chan->buflen, chan->maxpacket)); - - /* Get the size to put in the Tx FIFO now */ - - wrsize = chan->buflen; + DEBUGASSERT(wrsize > 0 && avail >= MIN(wrsize, chan->maxpacket)); if (wrsize > avail) { /* Clip the write size to the number of full, max sized packets @@ -3070,8 +3101,8 @@ static inline void stm32_gint_nptxfeisr(FAR struct stm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - ullvdbg("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, wrsize); + ullvdbg("HNPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %dwrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); stm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -3104,7 +3135,7 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) */ chan->buffer += chan->inflight; - chan->buflen -= chan->inflight; + chan->xfrd += chan->inflight; chan->inflight = 0; /* If we have now transfered the entire buffer, then this transfer is @@ -3112,7 +3143,7 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) * the PTXFE interrupt on the final packet). */ - if (chan->buflen <= 0) + if (chan->xfrd >= chan->buflen) { /* Disable further Tx FIFO empty interrupts and bail. */ @@ -3128,16 +3159,15 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) avail = ((regval & OTGHS_HPTXSTS_PTXFSAVL_MASK) >> OTGHS_HPTXSTS_PTXFSAVL_SHIFT) << 2; + /* Get the size to put in the Tx FIFO now */ + + wrsize = chan->buflen - chan->xfrd; + /* Get minimal size packet that can be sent. Something is seriously * configured wrong if one packet will not fit into the empty Tx FIFO. */ - DEBUGASSERT(chan->buflen > 0 && - avail >= MIN(chan->buflen, chan->maxpacket)); - - /* Get the size to put in the Tx FIFO now */ - - wrsize = chan->buflen; + DEBUGASSERT(wrsize > 0 && avail >= MIN(wrsize, chan->maxpacket)); if (wrsize > avail) { /* Clip the write size to the number of full, max sized packets @@ -3159,8 +3189,8 @@ static inline void stm32_gint_ptxfeisr(FAR struct stm32_usbhost_s *priv) /* Write the next group of packets into the Tx FIFO */ - ullvdbg("HPTXSTS: %08x chidx: %d avail: %d buflen: %d wrsize: %d\n", - regval, chidx, avail, chan->buflen, wrsize); + ullvdbg("HPTXSTS: %08x chidx: %d avail: %d buflen: %d xfrd: %d wrsize: %d\n", + regval, chidx, avail, chan->buflen, chan->xfrd, wrsize); stm32_gint_wrpacket(priv, chan->buffer, chidx, wrsize); } @@ -4462,8 +4492,9 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * buflen - The length of the data to be sent or received. * * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure: + * On success, a non-negative value is returned that indicates the number + * of bytes successfully transferred. On a failure, a negated errno value is + * returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -4477,12 +4508,12 @@ static int stm32_ctrlout(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0, * *******************************************************************************/ -static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen) +static ssize_t stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, + FAR uint8_t *buffer, size_t buflen) { FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; unsigned int chidx = (unsigned int)ep; - int ret; + ssize_t nbytes; uvdbg("chidx: %d buflen: %d\n", (unsigned int)ep, buflen); @@ -4496,15 +4527,15 @@ static int stm32_transfer(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, if (priv->chan[chidx].in) { - ret = stm32_in_transfer(priv, chidx, buffer, buflen); + nbytes = stm32_in_transfer(priv, chidx, buffer, buflen); } else { - ret = stm32_out_transfer(priv, chidx, buffer, buflen); + nbytes = stm32_out_transfer(priv, chidx, buffer, buflen); } stm32_givesem(&priv->exclsem); - return ret; + return nbytes; } /******************************************************************************* @@ -4700,9 +4731,7 @@ static int stm32_connect(FAR struct usbhost_driver_s *drvr, static void stm32_disconnect(FAR struct usbhost_driver_s *drvr, FAR struct usbhost_hubport_s *hport) { - FAR struct stm32_usbhost_s *priv = (FAR struct stm32_usbhost_s *)drvr; - DEBUGASSERT(priv != NULL && hport != NULL); - + DEBUGASSERT(hport != NULL); hport->devclass = NULL; } diff --git a/drivers/usbhost/usbhost_hidmouse.c b/drivers/usbhost/usbhost_hidmouse.c index 5d09edbd04f..e710072663e 100644 --- a/drivers/usbhost/usbhost_hidmouse.c +++ b/drivers/usbhost/usbhost_hidmouse.c @@ -1052,6 +1052,7 @@ static int usbhost_mouse_poll(int argc, char *argv[]) unsigned int npolls = 0; #endif unsigned int nerrors = 0; + ssize_t nbytes; int ret; uvdbg("Started\n"); @@ -1084,14 +1085,14 @@ static int usbhost_mouse_poll(int argc, char *argv[]) * sends data. */ - ret = DRVR_TRANSFER(hport->drvr, priv->epin, - priv->tbuffer, priv->tbuflen); + nbytes = DRVR_TRANSFER(hport->drvr, priv->epin, + priv->tbuffer, priv->tbuflen); /* Check for errors -- Bail if an excessive number of consecutive * errors are encountered. */ - if (ret < 0) + if (nbytes < 0) { /* If DRVR_TRANSFER() returns EAGAIN, that simply means that * the devices was not ready and has NAK'ed the transfer. That @@ -1100,11 +1101,12 @@ static int usbhost_mouse_poll(int argc, char *argv[]) */ udbg("ERROR: DRVR_TRANSFER returned: %d/%d\n", ret, nerrors); - if (ret != -EAGAIN) + if (nbytes != -EAGAIN) { if (++nerrors > 200) { udbg("Too many errors... aborting: %d\n", nerrors); + ret = (int)nbytes; break; } } diff --git a/drivers/usbhost/usbhost_hub.c b/drivers/usbhost/usbhost_hub.c index ceae12f79ad..7c98230c2e0 100644 --- a/drivers/usbhost/usbhost_hub.c +++ b/drivers/usbhost/usbhost_hub.c @@ -86,7 +86,7 @@ # error Asynchronous transfer support is required (CONFIG_USBHOST_ASYNCH) #endif -#ifdef CONFIG_USBHOST_HUB_POLLMSEC +#ifndef CONFIG_USBHOST_HUB_POLLMSEC # define CONFIG_USBHOST_HUB_POLLMSEC 400 #endif @@ -166,7 +166,7 @@ static void usbhost_disconnect_event(FAR void *arg); static inline uint16_t usbhost_getle16(const uint8_t *val); static void usbhost_putle16(uint8_t *dest, uint16_t val); -static void usbhost_callback(FAR void *arg, int result); +static void usbhost_callback(FAR void *arg, ssize_t nbytes); /* struct usbhost_registry_s methods */ @@ -1149,7 +1149,8 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val) * * Input Parameters: * arg - The argument provided with the asynchronous I/O was setup - * result - The result of the transfer + * nbytes - The number of bytes actually transferred (or a negated errno + * value; * * Returned Values: * None @@ -1159,7 +1160,7 @@ static void usbhost_putle16(uint8_t *dest, uint16_t val) * ****************************************************************************/ -static void usbhost_callback(FAR void *arg, int result) +static void usbhost_callback(FAR void *arg, ssize_t nbytes) { FAR struct usbhost_class_s *hubclass; FAR struct usbhost_hubpriv_s *priv; @@ -1173,22 +1174,22 @@ static void usbhost_callback(FAR void *arg, int result) * transfer will pend until data is available (OHCI and EHCI). On lower * end host controllers (like STM32 and EFM32), the transfer will fail * immediately when the device NAKs the first attempted interrupt IN - * transfer (with result == EAGAIN). In that case (or in the case of + * transfer (with nbytes == -EAGAIN). In that case (or in the case of * other errors), we must fall back to polling. */ - if (result != OK) + if (nbytes < 0) { /* This debug output is good to know, but really a nuisance for * those configurations where we have to fall back to polling. - * FIX: Don't output the message is the result is EAGAIN. + * FIX: Don't output the message is the result is -EAGAIN. */ #if defined(CONFIG_DEBUG_USB) && !defined(CONFIG_DEBUG_VERBOSE) - if (result != EAGAIN) + if (nbytes != -EAGAIN) #endif { - ulldbg("ERROR: Transfer failed: %d\n", result); + ulldbg("ERROR: Transfer failed: %d\n", (int)nbytes); } /* Indicate there there is nothing to do. So when the work is diff --git a/drivers/usbhost/usbhost_storage.c b/drivers/usbhost/usbhost_storage.c index be9a3c76114..7b6aa12a2eb 100644 --- a/drivers/usbhost/usbhost_storage.c +++ b/drivers/usbhost/usbhost_storage.c @@ -711,7 +711,7 @@ static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv) { FAR struct usbhost_hubport_s *hport; FAR struct usbmsc_cbw_s *cbw; - int result; + ssize_t nbytes; DEBUGASSERT(priv->usbclass.hport); hport = priv->usbclass.hport; @@ -728,28 +728,28 @@ static inline int usbhost_testunitready(FAR struct usbhost_state_s *priv) /* Construct and send the CBW */ usbhost_testunitreadycbw(cbw); - result = DRVR_TRANSFER(hport->drvr, priv->bulkout, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { /* Receive the CSW */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer); } } - return result; + return nbytes < 0 ? (int)nbytes : OK; } static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv) { FAR struct usbhost_hubport_s *hport; FAR struct usbmsc_cbw_s *cbw; - int result; + ssize_t nbytes; DEBUGASSERT(priv->usbclass.hport); hport = priv->usbclass.hport; @@ -766,28 +766,28 @@ static inline int usbhost_requestsense(FAR struct usbhost_state_s *priv) /* Construct and send the CBW */ usbhost_requestsensecbw(cbw); - result = DRVR_TRANSFER(hport->drvr, priv->bulkout, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { /* Receive the sense data response */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, priv->tbuffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF); - if (result == OK) + if (nbytes >= 0) { /* Receive the CSW */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer); } } } - return result; + return nbytes < 0 ? (int)nbytes : OK; } static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv) @@ -795,7 +795,7 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv) FAR struct usbhost_hubport_s *hport; FAR struct usbmsc_cbw_s *cbw; FAR struct scsiresp_readcapacity10_s *resp; - int result; + ssize_t nbytes; DEBUGASSERT(priv->usbclass.hport); hport = priv->usbclass.hport; @@ -812,15 +812,15 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv) /* Construct and send the CBW */ usbhost_readcapacitycbw(cbw); - result = DRVR_TRANSFER(hport->drvr, priv->bulkout, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { /* Receive the read capacity CBW IN response */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, priv->tbuffer, SCSIRESP_READCAPACITY10_SIZEOF); - if (result == OK) + if (nbytes >= 0) { /* Save the capacity information */ @@ -830,23 +830,23 @@ static inline int usbhost_readcapacity(FAR struct usbhost_state_s *priv) /* Receive the CSW */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer); } } } - return result; + return nbytes < 0 ? (int)nbytes : OK; } static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv) { FAR struct usbhost_hubport_s *hport; FAR struct usbmsc_cbw_s *cbw; - int result; + ssize_t nbytes; DEBUGASSERT(priv->usbclass.hport); hport = priv->usbclass.hport; @@ -863,35 +863,35 @@ static inline int usbhost_inquiry(FAR struct usbhost_state_s *priv) /* Construct and send the CBW */ usbhost_inquirycbw(cbw); - result = DRVR_TRANSFER(hport->drvr, priv->bulkout, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { /* Receive the CBW IN response */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, priv->tbuffer, SCSIRESP_INQUIRY_SIZEOF); - if (result == OK) + if (nbytes >= 0) { #if 0 FAR struct scsiresp_inquiry_s *resp; /* TODO: If USB debug is enabled, dump the response data here */ + resp = (FAR struct scsiresp_inquiry_s *)priv->tbuffer; #endif - /* Receive the CSW */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { usbhost_dumpcsw((FAR struct usbmsc_csw_s *)priv->tbuffer); } } } - return result; + return nbytes < 0 ? (int)nbytes : OK; } /**************************************************************************** @@ -1977,8 +1977,7 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, { FAR struct usbhost_state_s *priv; FAR struct usbhost_hubport_s *hport; - ssize_t ret = 0; - int result; + ssize_t nbytes = 0; DEBUGASSERT(inode && inode->i_private); priv = (FAR struct usbhost_state_s *)inode->i_private; @@ -1998,7 +1997,7 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, * attempt to read from the device. */ - ret = -ENODEV; + nbytes = -ENODEV; } else if (nsectors > 0) { @@ -2008,7 +2007,7 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, /* Assume allocation failure */ - ret = -ENOMEM; + nbytes = -ENOMEM; /* Initialize a CBW (re-using the allocated transfer buffer) */ @@ -2023,26 +2022,26 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, { /* Assume some device failure */ - ret = -ENODEV; + nbytes = -ENODEV; /* Construct and send the CBW */ usbhost_readcbw(startsector, priv->blocksize, nsectors, cbw); - result = DRVR_TRANSFER(hport->drvr, priv->bulkout, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { /* Receive the user data */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, buffer, priv->blocksize * nsectors); - if (result == OK) + if (nbytes >= 0) { /* Receive the CSW */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { FAR struct usbmsc_csw_s *csw; @@ -2051,12 +2050,12 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, csw = (FAR struct usbmsc_csw_s *)priv->tbuffer; if (csw->status == 0) { - ret = nsectors; + nbytes = nsectors; } } } } - } while (result == -EAGAIN); + } while (nbytes == -EAGAIN); } usbhost_givesem(&priv->exclsem); @@ -2064,7 +2063,7 @@ static ssize_t usbhost_read(FAR struct inode *inode, unsigned char *buffer, /* On success, return the number of blocks read */ - return ret; + return nbytes < 0 ? (int)nbytes : OK; } /**************************************************************************** @@ -2082,8 +2081,7 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe { FAR struct usbhost_state_s *priv; FAR struct usbhost_hubport_s *hport; - ssize_t ret; - int result; + ssize_t nbytes; uvdbg("sector: %d nsectors: %d sectorsize: %d\n"); @@ -2102,7 +2100,7 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe * attempt to write to the device. */ - ret = -ENODEV; + nbytes = -ENODEV; } else { @@ -2112,7 +2110,7 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe /* Assume allocation failure */ - ret = -ENOMEM; + nbytes = -ENOMEM; /* Initialize a CBW (re-using the allocated transfer buffer) */ @@ -2121,26 +2119,26 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe { /* Assume some device failure */ - ret = -ENODEV; + nbytes = -ENODEV; /* Construct and send the CBW */ usbhost_writecbw(startsector, priv->blocksize, nsectors, cbw); - result = DRVR_TRANSFER(hport->drvr, priv->bulkout, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkout, (uint8_t*)cbw, USBMSC_CBW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { /* Send the user data */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkout, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkout, (uint8_t*)buffer, priv->blocksize * nsectors); - if (result == OK) + if (nbytes >= 0) { /* Receive the CSW */ - result = DRVR_TRANSFER(hport->drvr, priv->bulkin, + nbytes = DRVR_TRANSFER(hport->drvr, priv->bulkin, priv->tbuffer, USBMSC_CSW_SIZEOF); - if (result == OK) + if (nbytes >= 0) { FAR struct usbmsc_csw_s *csw; @@ -2149,7 +2147,7 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe csw = (FAR struct usbmsc_csw_s *)priv->tbuffer; if (csw->status == 0) { - ret = nsectors; + nbytes = nsectors; } } } @@ -2161,7 +2159,7 @@ static ssize_t usbhost_write(FAR struct inode *inode, const unsigned char *buffe /* On success, return the number of blocks written */ - return ret; + return nbytes < 0 ? (int)nbytes : OK; } #endif diff --git a/include/nuttx/usb/usbhost.h b/include/nuttx/usb/usbhost.h index c51bff704e3..927dace064f 100644 --- a/include/nuttx/usb/usbhost.h +++ b/include/nuttx/usb/usbhost.h @@ -490,8 +490,9 @@ * buflen - The length of the data to be sent or received. * * Returned Values: - * On success, zero (OK) is returned. On a failure, a negated errno value is - * returned indicating the nature of the failure: + * On success, a non-negative value is returned that indicates the number + * of bytes successfully transferred. On a failure, a negated errno value is + * returned that indicates the nature of the failure: * * EAGAIN - If devices NAKs the transfer (or NYET or other error where * it may be appropriate to restart the entire transaction). @@ -791,9 +792,13 @@ struct usbhost_connection_s FAR struct usbhost_hubport_s *hport); }; -/* Callback type used with asynchronous transfers */ +/* Callback type used with asynchronous transfers. The result of the + * transfer is provided by the 'result' parameters. If >= 0, then 'result' + * is the number of bytes transfers. If < 0 then the transfer failed and + * result is a negated errno value that indicates the nature of the failure. + */ -typedef CODE void (*usbhost_asynch_t)(FAR void *arg, int result); +typedef CODE void (*usbhost_asynch_t)(FAR void *arg, ssize_t result); /* struct usbhost_driver_s provides access to the USB host driver from the * USB host class implementation. @@ -869,8 +874,8 @@ struct usbhost_driver_s * transfer has completed. */ - int (*transfer)(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, - FAR uint8_t *buffer, size_t buflen); + ssize_t (*transfer)(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, + FAR uint8_t *buffer, size_t buflen); /* Process a request to handle a transfer asynchronously. This method * will enqueue the transfer request and return immediately. Only one