From cac9879ad2d85beeb75de768d9dec085b53b797b Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 11 May 2015 11:43:31 -0600 Subject: [PATCH] EHCI HCDs will now support cancellation of syncrhonous transfers --- arch/arm/src/efm32/efm32_usbhost.c | 3 +- arch/arm/src/lpc17xx/lpc17_usbhost.c | 3 +- arch/arm/src/lpc31xx/lpc31_ehci.c | 55 ++++++++++++++++++++++------ arch/arm/src/sama5/sam_ehci.c | 54 +++++++++++++++++++-------- arch/arm/src/sama5/sam_ohci.c | 3 +- arch/arm/src/stm32/stm32_otgfshost.c | 3 +- arch/arm/src/stm32/stm32_otghshost.c | 3 +- 7 files changed, 93 insertions(+), 31 deletions(-) diff --git a/arch/arm/src/efm32/efm32_usbhost.c b/arch/arm/src/efm32/efm32_usbhost.c index 46158220f7..b29bee3ca9 100644 --- a/arch/arm/src/efm32/efm32_usbhost.c +++ b/arch/arm/src/efm32/efm32_usbhost.c @@ -4678,7 +4678,8 @@ static int efm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * Name: efm32_cancel * * Description: - * Cancel a pending asynchronous transfer on an endpoint. + * Cancel a pending asynchronous transfer on an endpoint. Cancelled synchronous + * or asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to diff --git a/arch/arm/src/lpc17xx/lpc17_usbhost.c b/arch/arm/src/lpc17xx/lpc17_usbhost.c index 51d43e3278..77f69fb713 100644 --- a/arch/arm/src/lpc17xx/lpc17_usbhost.c +++ b/arch/arm/src/lpc17xx/lpc17_usbhost.c @@ -3224,7 +3224,8 @@ errout_with_sem: * Name: lpc17_cancel * * Description: - * Cancel a pending asynchronous transfer on an endpoint. + * Cancel a pending asynchronous transfer on an endpoint. Cancelled synchronous + * or asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to diff --git a/arch/arm/src/lpc31xx/lpc31_ehci.c b/arch/arm/src/lpc31xx/lpc31_ehci.c index 21cc26e72f..54406ec3b9 100644 --- a/arch/arm/src/lpc31xx/lpc31_ehci.c +++ b/arch/arm/src/lpc31xx/lpc31_ehci.c @@ -3822,7 +3822,7 @@ static int lpc31_enumerate(FAR struct usbhost_connection_s *conn, usbhost_trace2(EHCI_TRACE2_CLASSENUM_FAILED, hport->port + 1, -ret); /* If this is a root hub port, then marking the hub port not connected will - * cause sam_wait() to return and we will try the connection again. + * cause lpc31_wait() to return and we will try the connection again. */ hport->connected = false; @@ -4475,7 +4475,8 @@ errout_with_sem: * Name: lpc31_cancel * * Description: - * Cancel a pending asynchronous transfer on an endpoint. + * Cancel a pending asynchronous transfer on an endpoint. Cancelled synchronous + * or asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to @@ -4494,8 +4495,11 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { struct lpc31_epinfo_s *epinfo = (struct lpc31_epinfo_s *)ep; struct lpc31_qh_s *qh; + usbhost_asynch_t callback; + void *arg; uint32_t *bp; irqstate_t flags; + bool iocwait; int ret; DEBUGASSERT(epinfo); @@ -4507,15 +4511,21 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) lpc31_takesem(&g_ehci.exclsem); - /* If there is no asynchronous transfer in progress, then bail now */ + /* Sample and reset all transfer termination information. This will prevent any + * callbacks from occurring while are performing the cancellation. The transfer + * may still be in progress, however, so this does not eliminate other DMA- + * related race conditions. + */ flags = irqsave(); - if (epinfo->callback == NULL) - { - ret = -EINVAL; - irqrestore(flags); - goto errout_with_sem; - } + callback = epinfo->callback; + arg = epinfo->arg; + iocwait = epinfo->iocwait; + + epinfo->callback = NULL; + epinfo->arg = NULL; + epinfo->iocwait = false; + irqrestore(flags); /* This will prevent any callbacks from occurring while are performing * the cancellation. The transfer may still be in progress, however, so @@ -4549,7 +4559,8 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { /* Claim that we successfully cancelled the transfer */ - return OK; + ret = OK; + goto exit_terminate; } } break; @@ -4569,7 +4580,8 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * cancelled the transfer. */ - return OK; + ret = OK; + goto exit_terminate; } } break; @@ -4602,6 +4614,27 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) usbhost_trace1(EHCI_TRACE1_QTDFOREACH_FAILED, -ret); } + /* Was there a pending synchronous transfer? */ + +exit_terminate: + epinfo->result = -ESHUTDOWN; + if (iocwait) + { + /* Yes... wake it up */ + + DEBUGASSERT(callback == NULL); + lpc31_givesem(&epinfo->iocsem); + } + + /* No.. Is there a pending asynchronous transfer? */ + + else if (callback != NULL) + { + /* Yes.. perform the callback */ + + callback(arg, -ESHUTDOWN); + } + errout_with_sem: lpc31_givesem(&g_ehci.exclsem); return ret; diff --git a/arch/arm/src/sama5/sam_ehci.c b/arch/arm/src/sama5/sam_ehci.c index a898e9c86c..1d1007c94d 100644 --- a/arch/arm/src/sama5/sam_ehci.c +++ b/arch/arm/src/sama5/sam_ehci.c @@ -4302,7 +4302,8 @@ errout_with_sem: * Name: sam_cancel * * Description: - * Cancel a pending asynchronous transfer on an endpoint. + * Cancel a pending asynchronous transfer on an endpoint. Cancelled synchronous + * or asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to @@ -4321,8 +4322,11 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { struct sam_epinfo_s *epinfo = (struct sam_epinfo_s *)ep; struct sam_qh_s *qh; + usbhost_asynch_t callback; + void *arg; uint32_t *bp; irqstate_t flags; + bool iocwait; int ret; DEBUGASSERT(epinfo); @@ -4334,23 +4338,20 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) sam_takesem(&g_ehci.exclsem); - /* If there is no asynchronous transfer in progress, then bail now */ + /* Sample and reset all transfer termination information. This will prevent any + * callbacks from occurring while are performing the cancellation. The transfer + * may still be in progress, however, so this does not eliminate other DMA- + * related race conditions. + */ flags = irqsave(); - if (epinfo->callback == NULL) - { - ret = -EINVAL; - irqrestore(flags); - goto errout_with_sem; - } - - /* This will prevent any callbacks from occurring while are performing - * the cancellation. The transfer may still be in progress, however, so - * this does not eliminate other DMA-related race conditions. - */ + callback = epinfo->callback; + arg = epinfo->arg; + iocwait = epinfo->iocwait; epinfo->callback = NULL; epinfo->arg = NULL; + epinfo->iocwait = false; irqrestore(flags); /* Handle the cancellation according to the type of the transfer */ @@ -4376,7 +4377,8 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) { /* Claim that we successfully cancelled the transfer */ - return OK; + ret = OK; + goto exit_terminate; } } break; @@ -4396,7 +4398,8 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) * cancelled the transfer. */ - return OK; + ret = OK; + goto exit_terminate; } } break; @@ -4429,6 +4432,27 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep) usbhost_trace1(EHCI_TRACE1_QTDFOREACH_FAILED, -ret); } + /* Was there a pending synchronous transfer? */ + +exit_terminate: + epinfo->result = -ESHUTDOWN; + if (iocwait) + { + /* Yes... wake it up */ + + DEBUGASSERT(callback == NULL); + sam_givesem(&epinfo->iocsem); + } + + /* No.. Is there a pending asynchronous transfer? */ + + else if (callback != NULL) + { + /* Yes.. perform the callback */ + + callback(arg, -ESHUTDOWN); + } + errout_with_sem: sam_givesem(&g_ehci.exclsem); return ret; diff --git a/arch/arm/src/sama5/sam_ohci.c b/arch/arm/src/sama5/sam_ohci.c index a13551b065..2845224bd8 100644 --- a/arch/arm/src/sama5/sam_ohci.c +++ b/arch/arm/src/sama5/sam_ohci.c @@ -3605,7 +3605,8 @@ errout: * Name: sam_cancel * * Description: - * Cancel a pending asynchronous transfer on an endpoint. + * Cancel a pending asynchronous transfer on an endpoint. Cancelled synchronous + * or asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to diff --git a/arch/arm/src/stm32/stm32_otgfshost.c b/arch/arm/src/stm32/stm32_otgfshost.c index 2774568202..3d7124a95a 100644 --- a/arch/arm/src/stm32/stm32_otgfshost.c +++ b/arch/arm/src/stm32/stm32_otgfshost.c @@ -4610,7 +4610,8 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * Name: stm32_cancel * * Description: - * Cancel a pending asynchronous transfer on an endpoint. + * Cancel a pending asynchronous transfer on an endpoint. Cancelled synchronous + * or asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to diff --git a/arch/arm/src/stm32/stm32_otghshost.c b/arch/arm/src/stm32/stm32_otghshost.c index 28bece03d5..800797beb5 100644 --- a/arch/arm/src/stm32/stm32_otghshost.c +++ b/arch/arm/src/stm32/stm32_otghshost.c @@ -4610,7 +4610,8 @@ static int stm32_asynch(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep, * Name: stm32_cancel * * Description: - * Cancel a pending asynchronous transfer on an endpoint. + * Cancel a pending asynchronous transfer on an endpoint. Cancelled synchronous + * or asynchronous transfer will complete normally with the error -ESHUTDOWN. * * Input Parameters: * drvr - The USB host driver instance obtained as a parameter from the call to