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
This commit is contained in:
parent
446ced4799
commit
9a9fc90794
@ -3588,32 +3588,36 @@ static int sam_ep_submit(struct usbdev_ep_s *ep, struct usbdev_req_s *req)
|
|||||||
privep->zlpsent = false;
|
privep->zlpsent = false;
|
||||||
flags = irqsave();
|
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
|
/* 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
|
* 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);
|
if (privep->stalled)
|
||||||
usbtrace(TRACE_INREQQUEUED(epno), req->len);
|
|
||||||
|
|
||||||
/* If the IN endpoint is IDLE, then transfer the data now */
|
|
||||||
|
|
||||||
if (privep->epstate == UDPHS_EPSTATE_IDLE)
|
|
||||||
{
|
{
|
||||||
ret = sam_req_write(priv, privep);
|
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 */
|
||||||
|
|
||||||
|
sam_req_enqueue(&privep->reqq, privreq);
|
||||||
|
usbtrace(TRACE_INREQQUEUED(epno), req->len);
|
||||||
|
|
||||||
|
/* 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);
|
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 (privep->epstate == UDPHS_EPSTATE_SENDING ||
|
if (epno == 0 || USB_ISEPIN(ep->eplog))
|
||||||
privep->epstate == UDPHS_EPSTATE_RECEIVING)
|
|
||||||
{
|
{
|
||||||
sam_req_complete(privep, -EIO);
|
sam_req_cancel(privep, -EPERM);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, it is an OUT endpoint. Complete any read request
|
||||||
|
* currently in progress (it will get requeued immediately).
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if (privep->epstate == UDPHS_EPSTATE_RECEIVING)
|
||||||
|
{
|
||||||
|
sam_req_complete(privep, -EPERM);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Put endpoint into stalled state */
|
/* Put endpoint into stalled state */
|
||||||
|
@ -213,6 +213,7 @@ static struct usbdev_req_s *usbmsc_allocreq(FAR struct usbdev_ep_s *ep,
|
|||||||
req = NULL;
|
req = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,6 +289,7 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver,
|
|||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->ctrlreq->callback = usbmsc_ep0incomplete;
|
priv->ctrlreq->callback = usbmsc_ep0incomplete;
|
||||||
|
|
||||||
/* Pre-allocate all endpoints... the endpoints will not be functional
|
/* 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;
|
ret = -ENODEV;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->epbulkin->priv = priv;
|
priv->epbulkin->priv = priv;
|
||||||
|
|
||||||
/* Pre-allocate the OUT bulk endpoint */
|
/* Pre-allocate the OUT bulk endpoint */
|
||||||
@ -317,6 +320,7 @@ static int usbmsc_bind(FAR struct usbdevclass_driver_s *driver,
|
|||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->epbulkout->priv = priv;
|
priv->epbulkout->priv = priv;
|
||||||
|
|
||||||
/* Pre-allocate read requests */
|
/* 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);
|
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_SETUPINVALIDARGS), 0);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Extract reference to private data */
|
/* 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);
|
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_WRCOMPLETEINVALIDARGS), 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Extract references to private data */
|
/* 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);
|
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_RDCOMPLETEINVALIDARGS), 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Extract references to private data */
|
/* Extract references to private data */
|
||||||
@ -1324,6 +1328,7 @@ int usbmsc_configure(unsigned int nluns, void **handle)
|
|||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(priv->luntab, 0, priv->nluns * sizeof(struct usbmsc_lun_s));
|
memset(priv->luntab, 0, priv->nluns * sizeof(struct usbmsc_lun_s));
|
||||||
|
|
||||||
/* Initialize the USB class driver structure */
|
/* 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);
|
usbtrace(TRACE_CLSERROR(USBMSC_TRACEERR_ALLOCIOBUFFER), geo.geo_sectorsize);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->iosize = geo.geo_sectorsize;
|
priv->iosize = geo.geo_sectorsize;
|
||||||
}
|
}
|
||||||
else if (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;
|
lun->readonly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1680,6 +1687,7 @@ int usbmsc_classobject(FAR void *handle,
|
|||||||
|
|
||||||
*classdev = &alloc->drvr.drvr;
|
*classdev = &alloc->drvr.drvr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1717,6 +1725,7 @@ void usbmsc_uninitialize(FAR void *handle)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
priv = &alloc->dev;
|
priv = &alloc->dev;
|
||||||
|
|
||||||
/* If the thread hasn't already exitted, tell it to exit now */
|
/* 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);
|
pthread_cond_signal(&priv->cond);
|
||||||
irqrestore(flags);
|
irqrestore(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&priv->mutex);
|
pthread_mutex_unlock(&priv->mutex);
|
||||||
|
|
||||||
/* Wait for the thread to exit. This is necessary even if the
|
/* 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);
|
(void)pthread_join(priv->thread, &value);
|
||||||
}
|
}
|
||||||
|
|
||||||
priv->thread = 0;
|
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
|
#ifndef CONFIG_USBMSC_COMPOSITE
|
||||||
usbdev_unregister(&alloc->drvr.drvr);
|
usbdev_unregister(&alloc->drvr.drvr);
|
||||||
@ -1758,6 +1769,7 @@ void usbmsc_uninitialize(FAR void *handle)
|
|||||||
{
|
{
|
||||||
usbmsc_lununinitialize(&priv->luntab[i]);
|
usbmsc_lununinitialize(&priv->luntab[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
kfree(priv->luntab);
|
kfree(priv->luntab);
|
||||||
|
|
||||||
/* Release the I/O buffer */
|
/* Release the I/O buffer */
|
||||||
|
@ -2619,6 +2619,7 @@ void *usbmsc_workerthread(void *arg)
|
|||||||
|
|
||||||
priv->thstate = USBMSC_STATE_IDLE;
|
priv->thstate = USBMSC_STATE_IDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
irqrestore(flags);
|
irqrestore(flags);
|
||||||
|
|
||||||
/* Loop processing each SCSI command state. Each state handling
|
/* Loop processing each SCSI command state. Each state handling
|
||||||
|
Loading…
Reference in New Issue
Block a user