From 9a55ea648e523e303636ccd01c00d56eadc47f9c Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Tue, 24 Sep 2013 15:06:17 -0600 Subject: 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 --- nuttx/arch/arm/src/sama5/sam_udphs.c | 58 ++++++++++++++++++++++-------------- nuttx/drivers/usbdev/usbmsc.c | 20 ++++++++++--- nuttx/drivers/usbdev/usbmsc_scsi.c | 1 + 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 -- cgit v1.2.3