USB ECHI: Fix a bug when trying to traverse an empty asynchronous queue

This commit is contained in:
Gregory Nutt 2015-04-28 11:29:16 -06:00
parent 5c76c53909
commit 5b80b257ce
2 changed files with 86 additions and 8 deletions

View File

@ -2995,13 +2995,18 @@ static inline void lpc31_ioc_bottomhalf(void)
cp15_invalidate_dcache((uintptr_t)&g_asynchead.hw, cp15_invalidate_dcache((uintptr_t)&g_asynchead.hw,
(uintptr_t)&g_asynchead.hw + sizeof(struct ehci_qh_s)); (uintptr_t)&g_asynchead.hw + sizeof(struct ehci_qh_s));
/* Set the back pointer to the forward qTD pointer of the asynchronous /* Set the back pointer to the forward QH pointer of the asynchronous
* queue head. * queue head.
*/ */
bp = (uint32_t *)&g_asynchead.hw.hlp; bp = (uint32_t *)&g_asynchead.hw.hlp;
qh = (struct lpc31_qh_s *)lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK); qh = (struct lpc31_qh_s *)lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK);
if (qh)
/* If the asynchronous queue is empty, then the forward point in the
* asynchronous queue head will point back to the the queue head.
*/
if (qh && qh != &g_asynchead)
{ {
/* Then traverse and operate on every QH and qTD in the asynchronous /* Then traverse and operate on every QH and qTD in the asynchronous
* queue * queue
@ -4491,12 +4496,46 @@ static int lpc31_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
{ {
case USB_EP_ATTR_XFER_CONTROL: case USB_EP_ATTR_XFER_CONTROL:
case USB_EP_ATTR_XFER_BULK: case USB_EP_ATTR_XFER_BULK:
qh = &g_asynchead; {
/* Get the horizontal pointer from the head of the asynchronous
* queue.
*/
bp = (uint32_t *)&g_asynchead.hw.hlp;
qh = (struct lpc31_qh_s *)lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK);
/* If the asynchronous queue is empty, then the forward point in
* the asynchronous queue head will point back to the the queue
* head.
*/
if (qh && qh != &g_asynchead)
{
/* Claim that we successfully cancelled the transfer */
return OK;
}
}
break; break;
#ifndef CONFIG_USBHOST_INT_DISABLE #ifndef CONFIG_USBHOST_INT_DISABLE
case USB_EP_ATTR_XFER_INT: case USB_EP_ATTR_XFER_INT:
qh = &g_intrhead; {
/* Get the horizontal pointer from the head of the interrupt
* queue.
*/
bp = (uint32_t *)&g_intrhead.hw.hlp;
qh = (struct lpc31_qh_s *)lpc31_virtramaddr(lpc31_swap32(*bp) & QH_HLP_MASK);
if (qh)
{
/* if the queue is empty, then just claim that we successfully
* cancelled the transfer.
*/
return OK;
}
}
break; break;
#endif #endif

View File

@ -2814,13 +2814,18 @@ static inline void sam_ioc_bottomhalf(void)
arch_invalidate_dcache((uintptr_t)&g_asynchead.hw, arch_invalidate_dcache((uintptr_t)&g_asynchead.hw,
(uintptr_t)&g_asynchead.hw + sizeof(struct ehci_qh_s)); (uintptr_t)&g_asynchead.hw + sizeof(struct ehci_qh_s));
/* Set the back pointer to the forward qTD pointer of the asynchronous /* Set the back pointer to the forward QH pointer of the asynchronous
* queue head. * queue head.
*/ */
bp = (uint32_t *)&g_asynchead.hw.hlp; bp = (uint32_t *)&g_asynchead.hw.hlp;
qh = (struct sam_qh_s *)sam_virtramaddr(sam_swap32(*bp) & QH_HLP_MASK); qh = (struct sam_qh_s *)sam_virtramaddr(sam_swap32(*bp) & QH_HLP_MASK);
if (qh)
/* If the asynchronous queue is empty, then the forward point in the
* asynchronous queue head will point back to the the queue head.
*/
if (qh && qh != &g_asynchead)
{ {
/* Then traverse and operate on every QH and qTD in the asynchronous /* Then traverse and operate on every QH and qTD in the asynchronous
* queue * queue
@ -4317,12 +4322,46 @@ static int sam_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
{ {
case USB_EP_ATTR_XFER_CONTROL: case USB_EP_ATTR_XFER_CONTROL:
case USB_EP_ATTR_XFER_BULK: case USB_EP_ATTR_XFER_BULK:
qh = &g_asynchead; {
/* Get the horizontal pointer from the head of the asynchronous
* queue.
*/
bp = (uint32_t *)&g_asynchead.hw.hlp;
qh = (struct sam_qh_s *)sam_virtramaddr(sam_swap32(*bp) & QH_HLP_MASK);
/* If the asynchronous queue is empty, then the forward point in
* the asynchronous queue head will point back to the the queue
* head.
*/
if (qh && qh != &g_asynchead)
{
/* Claim that we successfully cancelled the transfer */
return OK;
}
}
break; break;
#ifndef CONFIG_USBHOST_INT_DISABLE #ifndef CONFIG_USBHOST_INT_DISABLE
case USB_EP_ATTR_XFER_INT: case USB_EP_ATTR_XFER_INT:
qh = &g_intrhead; {
/* Get the horizontal pointer from the head of the interrupt
* queue.
*/
bp = (uint32_t *)&g_intrhead.hw.hlp;
qh = (struct sam_qh_s *)sam_virtramaddr(sam_swap32(*bp) & QH_HLP_MASK);
if (qh)
{
/* if the queue is empty, then just claim that we successfully
* cancelled the transfer.
*/
return OK;
}
}
break; break;
#endif #endif