summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-09-24 15:06:17 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-09-24 15:06:17 -0600
commit9a55ea648e523e303636ccd01c00d56eadc47f9c (patch)
treedf85454aea2443903d25354db20c41de714ee93b
parent8d771db4b2d0566066d204b293dc869f3e570593 (diff)
downloadnuttx-9a55ea648e523e303636ccd01c00d56eadc47f9c.tar.gz
nuttx-9a55ea648e523e303636ccd01c00d56eadc47f9c.tar.bz2
nuttx-9a55ea648e523e303636ccd01c00d56eadc47f9c.zip
SAMA5 UDPHS: Dont' reject read request submissions while stalled. That causes an infinite loop. When stalling, cancel all pending write requests, but cancel only a reqd request if it is in progress. It will be immediately requeued
-rw-r--r--nuttx/arch/arm/src/sama5/sam_udphs.c58
-rw-r--r--nuttx/drivers/usbdev/usbmsc.c20
-rw-r--r--nuttx/drivers/usbdev/usbmsc_scsi.c1
3 files changed, 53 insertions, 26 deletions
diff --git a/nuttx/arch/arm/src/sama5/sam_udphs.c b/nuttx/arch/arm/src/sama5/sam_udphs.c
index 501f3cbc9..0ad87e98b 100644
--- a/nuttx/arch/arm/src/sama5/sam_udphs.c
+++ b/nuttx/arch/arm/src/sama5/sam_udphs.c
@@ -3588,32 +3588,36 @@ static int sam_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
privep->zlpsent = false;
flags = irqsave();
- /* If we are stalled, then drop all requests on the floor */
-
- if (privep->stalled)
- {
- sam_req_abort(privep, privreq, -EBUSY);
- ulldbg("ERROR: stalled\n");
- ret = -EBUSY;
- }
-
/* Handle IN (device-to-host) requests. NOTE: If the class device is
* using the bi-directional EP0, then we assume that they intend the EP0
- * IN functionality (EP0 OUT data receipt does not use requests).
+ * IN functionality (EP0 SETUP OUT data receipt does not use requests).
*/
- else if (USB_ISEPIN(ep->eplog) || epno == EP0)
+ if (USB_ISEPIN(ep->eplog) || epno == EP0)
{
- /* Add the new request to the request queue for the IN endpoint */
+ /* If the endpoint is stalled, then fail any attempts to write
+ * through the endpoint.
+ */
- sam_req_enqueue(&privep->reqq, privreq);
- usbtrace(TRACE_INREQQUEUED(epno), req->len);
+ if (privep->stalled)
+ {
+ sam_req_abort(privep, privreq, -EBUSY);
+ ulldbg("ERROR: stalled\n");
+ ret = -EPERM;
+ }
+ else
+ {
+ /* Add the new request to the request queue for the IN endpoint */
- /* If the IN endpoint is IDLE, then transfer the data now */
+ sam_req_enqueue(&privep->reqq, privreq);
+ usbtrace(TRACE_INREQQUEUED(epno), req->len);
- if (privep->epstate == UDPHS_EPSTATE_IDLE)
- {
- ret = sam_req_write(priv, privep);
+ /* If the IN endpoint is IDLE, then transfer the data now */
+
+ if (privep->epstate == UDPHS_EPSTATE_IDLE)
+ {
+ ret = sam_req_write(priv, privep);
+ }
}
}
@@ -3750,12 +3754,22 @@ static int sam_ep_stall(struct usbdev_ep_s *ep, bool resume)
{
usbtrace(TRACE_EPSTALL, epno);
- /* Abort the current transfer if necessary */
+ /* If this is an IN endpoint (or endpoint 0), then cancel all
+ * of the pending write requests.
+ */
+
+ if (epno == 0 || USB_ISEPIN(ep->eplog))
+ {
+ sam_req_cancel(privep, -EPERM);
+ }
+
+ /* Otherwise, it is an OUT endpoint. Complete any read request
+ * currently in progress (it will get requeued immediately).
+ */
- if (privep->epstate == UDPHS_EPSTATE_SENDING ||
- privep->epstate == UDPHS_EPSTATE_RECEIVING)
+ else if (privep->epstate == UDPHS_EPSTATE_RECEIVING)
{
- sam_req_complete(privep, -EIO);
+ sam_req_complete(privep, -EPERM);
}
/* Put endpoint into stalled state */
diff --git a/nuttx/drivers/usbdev/usbmsc.c b/nuttx/drivers/usbdev/usbmsc.c
index ee8da5236..2faa07b12 100644
--- a/nuttx/drivers/usbdev/usbmsc.c
+++ b/nuttx/drivers/usbdev/usbmsc.c
@@ -213,6 +213,7 @@ static struct usbdev_req_s *usbmsc_allocreq(FAR struct usbdev_ep_s *ep,
req = NULL;
}
}
+
return req;
}
@@ -288,6 +289,7 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver,
ret = -ENOMEM;
goto errout;
}
+
priv->ctrlreq->callback = usbmsc_ep0incomplete;
/* Pre-allocate all endpoints... the endpoints will not be functional
@@ -306,6 +308,7 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver,
ret = -ENODEV;
goto errout;
}
+
priv->epbulkin->priv = priv;
/* Pre-allocate the OUT bulk endpoint */
@@ -317,6 +320,7 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver,
ret = -ENODEV;
goto errout;
}
+
priv->epbulkout->priv = priv;
/* Pre-allocate read requests */
@@ -517,7 +521,7 @@ static int usbmsc_setup(FAR struct usbdevclass_driver_s *driver,
{
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SETUPINVALIDARGS), 0);
return -EIO;
- }
+ }
#endif
/* Extract reference to private data */
@@ -1070,7 +1074,7 @@ void usbmsc_wrcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
{
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRCOMPLETEINVALIDARGS), 0);
return;
- }
+ }
#endif
/* Extract references to private data */
@@ -1131,7 +1135,7 @@ void usbmsc_rdcomplete(FAR struct usbdev_ep_s *ep, FAR struct usbdev_req_s *req)
{
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDCOMPLETEINVALIDARGS), 0);
return;
- }
+ }
#endif
/* Extract references to private data */
@@ -1324,6 +1328,7 @@ int usbmsc_configure(unsigned int nluns, void **handle)
ret = -ENOMEM;
goto errout;
}
+
memset(priv->luntab, 0, priv->nluns * sizeof(struct usbmsc_lun_s));
/* Initialize the USB class driver structure */
@@ -1465,6 +1470,7 @@ int usbmsc_bindlun(FAR void *handle, FAR const char *drvrpath,
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALLOCIOBUFFER), geo.geo_sectorsize);
return -ENOMEM;
}
+
priv->iosize = geo.geo_sectorsize;
}
else if (priv->iosize < geo.geo_sectorsize)
@@ -1492,6 +1498,7 @@ int usbmsc_bindlun(FAR void *handle, FAR const char *drvrpath,
{
lun->readonly = true;
}
+
return OK;
}
@@ -1680,6 +1687,7 @@ int usbmsc_classobject(FAR void *handle,
*classdev = &alloc->drvr.drvr;
}
+
return ret;
}
#endif
@@ -1717,6 +1725,7 @@ void usbmsc_uninitialize(FAR void *handle)
return;
}
#endif
+
priv = &alloc->dev;
/* If the thread hasn't already exitted, tell it to exit now */
@@ -1735,6 +1744,7 @@ void usbmsc_uninitialize(FAR void *handle)
pthread_cond_signal(&priv->cond);
irqrestore(flags);
}
+
pthread_mutex_unlock(&priv->mutex);
/* Wait for the thread to exit. This is necessary even if the
@@ -1744,9 +1754,10 @@ void usbmsc_uninitialize(FAR void *handle)
(void)pthread_join(priv->thread, &value);
}
+
priv->thread = 0;
- /* Unregister the driver (unless we are a part of a composite device */
+ /* Unregister the driver (unless we are a part of a composite device) */
#ifndef CONFIG_USBMSC_COMPOSITE
usbdev_unregister(&alloc->drvr.drvr);
@@ -1758,6 +1769,7 @@ void usbmsc_uninitialize(FAR void *handle)
{
usbmsc_lununinitialize(&priv->luntab[i]);
}
+
kfree(priv->luntab);
/* Release the I/O buffer */
diff --git a/nuttx/drivers/usbdev/usbmsc_scsi.c b/nuttx/drivers/usbdev/usbmsc_scsi.c
index fbeb0f192..7791141d8 100644
--- a/nuttx/drivers/usbdev/usbmsc_scsi.c
+++ b/nuttx/drivers/usbdev/usbmsc_scsi.c
@@ -2619,6 +2619,7 @@ void *usbmsc_workerthread(void *arg)
priv->thstate = USBMSC_STATE_IDLE;
}
+
irqrestore(flags);
/* Loop processing each SCSI command state. Each state handling