HUB class must cancel any pending interrupt IN transfers before destroying the endpoint
This commit is contained in:
parent
7d7ab442e1
commit
becfe4ef9d
@ -298,6 +298,11 @@ static void lpc17_freeasynch(struct lpc17_asynch_s *asynch);
|
|||||||
|
|
||||||
/* ED list helper functions ****************************************************/
|
/* ED list helper functions ****************************************************/
|
||||||
|
|
||||||
|
static inline int lpc17_addctrled(struct lpc17_usbhost_s *priv,
|
||||||
|
struct lpc17_ed_s *ed);
|
||||||
|
static inline int lpc17_remctrled(struct lpc17_usbhost_s *priv,
|
||||||
|
struct lpc17_ed_s *ed);
|
||||||
|
|
||||||
static inline int lpc17_addbulked(struct lpc17_usbhost_s *priv,
|
static inline int lpc17_addbulked(struct lpc17_usbhost_s *priv,
|
||||||
struct lpc17_ed_s *ed);
|
struct lpc17_ed_s *ed);
|
||||||
static inline int lpc17_rembulked(struct lpc17_usbhost_s *priv,
|
static inline int lpc17_rembulked(struct lpc17_usbhost_s *priv,
|
||||||
@ -841,6 +846,97 @@ static void lpc17_freeasynch(struct lpc17_asynch_s *asynch)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Name: lpc17_addctrled
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Helper function to add an ED to the control list.
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
static inline int lpc17_addctrled(struct lpc17_usbhost_s *priv,
|
||||||
|
struct lpc17_ed_s *ed)
|
||||||
|
{
|
||||||
|
uint32_t regval;
|
||||||
|
|
||||||
|
/* Add the new bulk ED to the head of the bulk list */
|
||||||
|
|
||||||
|
ed->hw.nexted = lpc17_getreg(LPC17_USBHOST_CTRLHEADED);
|
||||||
|
lpc17_putreg((uint32_t)ed, LPC17_USBHOST_CTRLHEADED);
|
||||||
|
|
||||||
|
/* ControlListEnable. This bit is set to enable the processing of the
|
||||||
|
* Control list. Note: once enabled, it remains enabled and we may even
|
||||||
|
* complete list processing before we get the bit set. We really
|
||||||
|
* should never modify the control list while CLE is set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
|
regval |= OHCI_CTRL_CLE;
|
||||||
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* Name: lpc17_remctrled
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Helper function remove an ED from the control list.
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
static inline int lpc17_remctrled(struct lpc17_usbhost_s *priv,
|
||||||
|
struct lpc17_ed_s *ed)
|
||||||
|
{
|
||||||
|
struct lpc17_ed_s *curr;
|
||||||
|
struct lpc17_ed_s *prev;
|
||||||
|
uint32_t regval;
|
||||||
|
|
||||||
|
/* Find the ED in the control list. NOTE: We really should never be mucking
|
||||||
|
* with the control list while CLE is set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (curr = (struct lpc17_ed_s *)lpc17_getreg(LPC17_USBHOST_CTRLHEADED),
|
||||||
|
prev = NULL;
|
||||||
|
curr && curr != ed;
|
||||||
|
prev = curr, curr = (struct lpc17_ed_s *)curr->hw.nexted);
|
||||||
|
|
||||||
|
/* Hmmm.. It would be a bug if we do not find the ED in the control list. */
|
||||||
|
|
||||||
|
DEBUGASSERT(curr != NULL);
|
||||||
|
|
||||||
|
/* Remove the ED from the control list */
|
||||||
|
|
||||||
|
if (curr != NULL)
|
||||||
|
{
|
||||||
|
/* Is this ED the first on in the control list? */
|
||||||
|
|
||||||
|
if (prev == NULL)
|
||||||
|
{
|
||||||
|
/* Yes... set the head of the control list to skip over this ED */
|
||||||
|
|
||||||
|
lpc17_putreg(ed->hw.nexted, LPC17_USBHOST_CTRLHEADED);
|
||||||
|
|
||||||
|
/* If the control list is now empty, then disable it.
|
||||||
|
* This should never happen!
|
||||||
|
*/
|
||||||
|
|
||||||
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
|
regval &= ~OHCI_CTRL_CLE;
|
||||||
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No.. set the forward link of the previous ED in the list
|
||||||
|
* skip over this ED.
|
||||||
|
*/
|
||||||
|
|
||||||
|
prev->hw.nexted = ed->hw.nexted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Name: lpc17_addbulked
|
* Name: lpc17_addbulked
|
||||||
*
|
*
|
||||||
@ -1260,7 +1356,6 @@ static inline int lpc17_addisoced(struct lpc17_usbhost_s *priv,
|
|||||||
# warning "Isochronous endpoints not yet supported"
|
# warning "Isochronous endpoints not yet supported"
|
||||||
#endif
|
#endif
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@ -2011,6 +2106,10 @@ static int lpc17_epalloc(struct usbhost_driver_s *drvr,
|
|||||||
|
|
||||||
switch (ed->xfrtype)
|
switch (ed->xfrtype)
|
||||||
{
|
{
|
||||||
|
case USB_EP_ATTR_XFER_CONTROL:
|
||||||
|
ret = lpc17_addctrled(priv, ed);
|
||||||
|
break;
|
||||||
|
|
||||||
case USB_EP_ATTR_XFER_BULK:
|
case USB_EP_ATTR_XFER_BULK:
|
||||||
ret = lpc17_addbulked(priv, ed);
|
ret = lpc17_addbulked(priv, ed);
|
||||||
break;
|
break;
|
||||||
@ -2023,7 +2122,6 @@ static int lpc17_epalloc(struct usbhost_driver_s *drvr,
|
|||||||
ret = lpc17_addisoced(priv, epdesc, ed);
|
ret = lpc17_addisoced(priv, epdesc, ed);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_EP_ATTR_XFER_CONTROL:
|
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
@ -2091,6 +2189,10 @@ static int lpc17_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep)
|
|||||||
|
|
||||||
switch (ed->xfrtype)
|
switch (ed->xfrtype)
|
||||||
{
|
{
|
||||||
|
case USB_EP_ATTR_XFER_CONTROL:
|
||||||
|
ret = lpc17_remctrled(priv, ed);
|
||||||
|
break;
|
||||||
|
|
||||||
case USB_EP_ATTR_XFER_BULK:
|
case USB_EP_ATTR_XFER_BULK:
|
||||||
ret = lpc17_rembulked(priv, ed);
|
ret = lpc17_rembulked(priv, ed);
|
||||||
break;
|
break;
|
||||||
@ -2103,7 +2205,6 @@ static int lpc17_epfree(struct usbhost_driver_s *drvr, usbhost_ep_t ep)
|
|||||||
ret = lpc17_remisoced(priv, ed);
|
ret = lpc17_remisoced(priv, ed);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_EP_ATTR_XFER_CONTROL:
|
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
@ -2818,7 +2919,7 @@ static void lpc17_asynch_completion(struct lpc17_usbhost_s *priv,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Name: lcp17_async
|
* Name: lcp17_asynch
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Process a request to handle a transfer descriptor. This method will
|
* Process a request to handle a transfer descriptor. This method will
|
||||||
@ -2947,7 +3048,7 @@ errout_with_sem:
|
|||||||
#endif /* CONFIG_USBHOST_ASYNCH */
|
#endif /* CONFIG_USBHOST_ASYNCH */
|
||||||
|
|
||||||
/************************************************************************************
|
/************************************************************************************
|
||||||
* Name: DRVR_CANCEL
|
* Name: lpc17_cancel
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Cancel a pending asynchronous transfer on an endpoint.
|
* Cancel a pending asynchronous transfer on an endpoint.
|
||||||
@ -3114,12 +3215,13 @@ static void lpc17_disconnect(struct usbhost_driver_s *drvr)
|
|||||||
|
|
||||||
static inline void lpc17_ep0init(struct lpc17_usbhost_s *priv)
|
static inline void lpc17_ep0init(struct lpc17_usbhost_s *priv)
|
||||||
{
|
{
|
||||||
uint32_t regval;
|
|
||||||
|
|
||||||
/* Set up some default values */
|
/* Set up some default values */
|
||||||
|
|
||||||
(void)lpc17_ep0configure(&priv->drvr, (usbhost_ep_t)EDCTRL, 1, 8);
|
(void)lpc17_ep0configure(&priv->drvr, (usbhost_ep_t)EDCTRL, 1, 8);
|
||||||
|
|
||||||
|
/* Initialize the common tail TD.*/
|
||||||
|
|
||||||
|
memset(TDTAIL, 0, sizeof(struct lpc17_gtd_s));
|
||||||
/* Initialize the common tail TD. */
|
/* Initialize the common tail TD. */
|
||||||
|
|
||||||
memset(TDTAIL, 0, sizeof(struct lpc17_gtd_s));
|
memset(TDTAIL, 0, sizeof(struct lpc17_gtd_s));
|
||||||
@ -3128,24 +3230,16 @@ static inline void lpc17_ep0init(struct lpc17_usbhost_s *priv)
|
|||||||
/* Link the common tail TD to the ED's TD list */
|
/* Link the common tail TD to the ED's TD list */
|
||||||
|
|
||||||
memset(EDCTRL, 0, sizeof(struct lpc17_ed_s));
|
memset(EDCTRL, 0, sizeof(struct lpc17_ed_s));
|
||||||
EDCTRL->hw.headp = (uint32_t)TDTAIL;
|
EDCTRL->hw.headp = (uint32_t)TDTAIL;
|
||||||
EDCTRL->hw.tailp = (uint32_t)TDTAIL;
|
EDCTRL->hw.tailp = (uint32_t)TDTAIL;
|
||||||
|
|
||||||
/* Set the head of the control list to the EP0 EDCTRL (this would have to
|
/* Set the head of the control list to the NULL (for now). */
|
||||||
* change if we want more than on control EP queued at a time).
|
|
||||||
*/
|
|
||||||
|
|
||||||
lpc17_putreg(LPC17_EDCTRL_ADDR, LPC17_USBHOST_CTRLHEADED);
|
lpc17_putreg(0, LPC17_USBHOST_CTRLHEADED);
|
||||||
|
|
||||||
/* ControlListEnable. This bit is set to enable the processing of the
|
/* Then add EP0 to the empty Control List */
|
||||||
* Control list. Note: once enabled, it remains enabled and we may even
|
|
||||||
* complete list processing before we get the bit set. We really
|
|
||||||
* should never modify the control list while CLE is set.
|
|
||||||
*/
|
|
||||||
|
|
||||||
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
lpc17_addctrled(priv, EDCTRL);
|
||||||
regval |= OHCI_CTRL_CLE;
|
|
||||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
@ -3427,7 +3427,7 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
|||||||
* the class create() method.
|
* the class create() method.
|
||||||
* epdesc - Describes the endpoint to be allocated.
|
* epdesc - Describes the endpoint to be allocated.
|
||||||
* ep - A memory location provided by the caller in which to receive the
|
* ep - A memory location provided by the caller in which to receive the
|
||||||
* allocated endpoint desciptor.
|
* allocated endpoint descriptor.
|
||||||
*
|
*
|
||||||
* Returned Values:
|
* Returned Values:
|
||||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||||
|
@ -2375,7 +2375,7 @@ static int sam_ep0configure(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep0,
|
|||||||
* the class create() method.
|
* the class create() method.
|
||||||
* epdesc - Describes the endpoint to be allocated.
|
* epdesc - Describes the endpoint to be allocated.
|
||||||
* ep - A memory location provided by the caller in which to receive the
|
* ep - A memory location provided by the caller in which to receive the
|
||||||
* allocated endpoint desciptor.
|
* allocated endpoint descriptor.
|
||||||
*
|
*
|
||||||
* Returned Values:
|
* Returned Values:
|
||||||
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
* On success, zero (OK) is returned. On a failure, a negated errno value is
|
||||||
|
@ -824,14 +824,14 @@ static void usbhost_hub_event(FAR void *arg)
|
|||||||
|
|
||||||
ctrlreq->type = USBHUB_REQ_TYPE_PORT;
|
ctrlreq->type = USBHUB_REQ_TYPE_PORT;
|
||||||
ctrlreq->req = USB_REQ_SETFEATURE;
|
ctrlreq->req = USB_REQ_SETFEATURE;
|
||||||
usbhost_putle16(ctrlreq->value, (USBHUB_PORT_FEAT_RESET << 8));
|
usbhost_putle16(ctrlreq->value, USBHUB_PORT_FEAT_RESET);
|
||||||
usbhost_putle16(ctrlreq->index, port);
|
usbhost_putle16(ctrlreq->index, port);
|
||||||
usbhost_putle16(ctrlreq->len, 0);
|
usbhost_putle16(ctrlreq->len, 0);
|
||||||
|
|
||||||
ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
|
ret = DRVR_CTRLOUT(hport->drvr, hport->ep0, ctrlreq, NULL);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
udbg("ERROR: ailed to reset port %d: %d\n", port, ret);
|
udbg("ERROR: Failed to reset port %d: %d\n", port, ret);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -985,6 +985,17 @@ static void usbhost_disconnect_event(FAR void *arg)
|
|||||||
flags = irqsave();
|
flags = irqsave();
|
||||||
priv->disconnected = true;
|
priv->disconnected = true;
|
||||||
|
|
||||||
|
/* Cancel any pending transfers on the interrupt IN pipe */
|
||||||
|
|
||||||
|
DRVR_CANCEL(hport->drvr, priv->intin);
|
||||||
|
|
||||||
|
/* Cancel any pending port status change events */
|
||||||
|
|
||||||
|
work_cancel(EVENT_WORK, &priv->work);
|
||||||
|
#if EVENT_WORK != POLL_WORK
|
||||||
|
work_cancel(POLL_WORK, &priv->work);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Disable power to all downstream ports */
|
/* Disable power to all downstream ports */
|
||||||
|
|
||||||
(void)usbhost_hubpwr(priv, hport, false);
|
(void)usbhost_hubpwr(priv, hport, false);
|
||||||
@ -997,10 +1008,6 @@ static void usbhost_disconnect_event(FAR void *arg)
|
|||||||
|
|
||||||
DRVR_IOFREE(hport->drvr, priv->buffer);
|
DRVR_IOFREE(hport->drvr, priv->buffer);
|
||||||
|
|
||||||
/* Destroy EP0 */
|
|
||||||
|
|
||||||
DRVR_EPFREE(hport->drvr, priv->intin);
|
|
||||||
|
|
||||||
/* Destroy the interrupt IN endpoint */
|
/* Destroy the interrupt IN endpoint */
|
||||||
|
|
||||||
DRVR_EPFREE(hport->drvr, priv->intin);
|
DRVR_EPFREE(hport->drvr, priv->intin);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user