OHCI drivers: Try disabling bulk list when cancelling bulk transfers
This commit is contained in:
parent
4dc10dbe85
commit
9061809e2d
@ -192,7 +192,7 @@ struct lpc17_xfrinfo_s
|
|||||||
uint8_t *buffer; /* Transfer buffer start */
|
uint8_t *buffer; /* Transfer buffer start */
|
||||||
uint16_t buflen; /* Buffer length */
|
uint16_t buflen; /* Buffer length */
|
||||||
uint16_t xfrd; /* Number of bytes transferred */
|
uint16_t xfrd; /* Number of bytes transferred */
|
||||||
|
|
||||||
#ifdef CONFIG_USBHOST_ASYNCH
|
#ifdef CONFIG_USBHOST_ASYNCH
|
||||||
#if LPC17_IOBUFFERS > 0
|
#if LPC17_IOBUFFERS > 0
|
||||||
/* Remember the allocated DMA buffer address so that it can be freed when
|
/* Remember the allocated DMA buffer address so that it can be freed when
|
||||||
@ -858,22 +858,30 @@ static void lpc17_free_xfrinfo(struct lpc17_xfrinfo_s *xfrinfo)
|
|||||||
static inline int lpc17_addctrled(struct lpc17_usbhost_s *priv,
|
static inline int lpc17_addctrled(struct lpc17_usbhost_s *priv,
|
||||||
struct lpc17_ed_s *ed)
|
struct lpc17_ed_s *ed)
|
||||||
{
|
{
|
||||||
|
irqstate_t flags;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
|
/* Disable control list processing while we modify the list */
|
||||||
|
|
||||||
|
flags = irqsave();
|
||||||
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
|
regval &= ~OHCI_CTRL_CLE;
|
||||||
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
|
||||||
/* Add the new bulk ED to the head of the bulk list */
|
/* Add the new bulk ED to the head of the bulk list */
|
||||||
|
|
||||||
ed->hw.nexted = lpc17_getreg(LPC17_USBHOST_CTRLHEADED);
|
ed->hw.nexted = lpc17_getreg(LPC17_USBHOST_CTRLHEADED);
|
||||||
lpc17_putreg((uint32_t)ed, LPC17_USBHOST_CTRLHEADED);
|
lpc17_putreg((uint32_t)ed, LPC17_USBHOST_CTRLHEADED);
|
||||||
|
|
||||||
/* ControlListEnable. This bit is set to enable the processing of the
|
/* Re-enable control list processing. */
|
||||||
* Control list. Note: once enabled, it remains enabled and we may even
|
|
||||||
* complete list processing before we get the bit set. We really
|
lpc17_putreg(0, LPC17_USBHOST_CTRLED);
|
||||||
* should never modify the control list while CLE is set.
|
|
||||||
*/
|
|
||||||
|
|
||||||
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
regval |= OHCI_CTRL_CLE;
|
regval |= OHCI_CTRL_CLE;
|
||||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
|
||||||
|
irqrestore(flags);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -891,11 +899,17 @@ static inline int lpc17_remctrled(struct lpc17_usbhost_s *priv,
|
|||||||
struct lpc17_ed_s *curr;
|
struct lpc17_ed_s *curr;
|
||||||
struct lpc17_ed_s *prev;
|
struct lpc17_ed_s *prev;
|
||||||
struct lpc17_ed_s *head;
|
struct lpc17_ed_s *head;
|
||||||
|
irqstate_t flags;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
/* Find the ED in the control list. NOTE: We really should never be mucking
|
/* Disable control list processing while we modify the list */
|
||||||
* with the control list while CLE is set.
|
|
||||||
*/
|
flags = irqsave();
|
||||||
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
|
regval &= ~OHCI_CTRL_CLE;
|
||||||
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
|
||||||
|
/* Find the ED in the control list. */
|
||||||
|
|
||||||
head = (struct lpc17_ed_s *)lpc17_getreg(LPC17_USBHOST_CTRLHEADED);
|
head = (struct lpc17_ed_s *)lpc17_getreg(LPC17_USBHOST_CTRLHEADED);
|
||||||
for (prev = NULL, curr = head;
|
for (prev = NULL, curr = head;
|
||||||
@ -918,17 +932,6 @@ static inline int lpc17_remctrled(struct lpc17_usbhost_s *priv,
|
|||||||
|
|
||||||
head = (struct lpc17_ed_s *)ed->hw.nexted;
|
head = (struct lpc17_ed_s *)ed->hw.nexted;
|
||||||
lpc17_putreg((uint32_t)head, LPC17_USBHOST_CTRLHEADED);
|
lpc17_putreg((uint32_t)head, LPC17_USBHOST_CTRLHEADED);
|
||||||
|
|
||||||
/* If the control list is now empty, then disable it.
|
|
||||||
* This should never happen!
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (head == NULL)
|
|
||||||
{
|
|
||||||
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
|
||||||
regval &= ~OHCI_CTRL_CLE;
|
|
||||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -946,6 +949,21 @@ static inline int lpc17_remctrled(struct lpc17_usbhost_s *priv,
|
|||||||
ed->hw.nexted = 0;
|
ed->hw.nexted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Re-enable control list processing if the control list is still non-empty
|
||||||
|
* after removing the ED node.
|
||||||
|
*/
|
||||||
|
|
||||||
|
lpc17_putreg(0, LPC17_USBHOST_CTRLED);
|
||||||
|
if (lpc17_getreg(LPC17_USBHOST_CTRLHEADED) != 0)
|
||||||
|
{
|
||||||
|
/* If the control list is now empty, then disable it */
|
||||||
|
|
||||||
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
|
regval &= ~OHCI_CTRL_CLE;
|
||||||
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
}
|
||||||
|
|
||||||
|
irqrestore(flags);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -961,21 +979,30 @@ static inline int lpc17_addbulked(struct lpc17_usbhost_s *priv,
|
|||||||
struct lpc17_ed_s *ed)
|
struct lpc17_ed_s *ed)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_USBHOST_BULK_DISABLE
|
#ifndef CONFIG_USBHOST_BULK_DISABLE
|
||||||
|
irqstate_t flags;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
|
/* Disable bulk list processing while we modify the list */
|
||||||
|
|
||||||
|
flags = irqsave();
|
||||||
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
|
regval &= ~OHCI_CTRL_BLE;
|
||||||
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
|
||||||
/* Add the new bulk ED to the head of the bulk list */
|
/* Add the new bulk ED to the head of the bulk list */
|
||||||
|
|
||||||
ed->hw.nexted = lpc17_getreg(LPC17_USBHOST_BULKHEADED);
|
ed->hw.nexted = lpc17_getreg(LPC17_USBHOST_BULKHEADED);
|
||||||
lpc17_putreg((uint32_t)ed, LPC17_USBHOST_BULKHEADED);
|
lpc17_putreg((uint32_t)ed, LPC17_USBHOST_BULKHEADED);
|
||||||
|
|
||||||
/* BulkListEnable. This bit is set to enable the processing of the
|
/* Re-enable bulk list processing. */
|
||||||
* Bulk list. Note: once enabled, it remains. We really should
|
|
||||||
* never modify the bulk list while BLE is set.
|
lpc17_putreg(0, LPC17_USBHOST_BULKED);
|
||||||
*/
|
|
||||||
|
|
||||||
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
regval |= OHCI_CTRL_BLE;
|
regval |= OHCI_CTRL_BLE;
|
||||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
|
||||||
|
irqrestore(flags);
|
||||||
return OK;
|
return OK;
|
||||||
#else
|
#else
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
@ -997,18 +1024,24 @@ static inline int lpc17_rembulked(struct lpc17_usbhost_s *priv,
|
|||||||
struct lpc17_ed_s *curr;
|
struct lpc17_ed_s *curr;
|
||||||
struct lpc17_ed_s *prev;
|
struct lpc17_ed_s *prev;
|
||||||
struct lpc17_ed_s *head;
|
struct lpc17_ed_s *head;
|
||||||
|
irqstate_t flags;
|
||||||
uint32_t regval;
|
uint32_t regval;
|
||||||
|
|
||||||
/* Find the ED in the bulk list. NOTE: We really should never be mucking
|
/* Disable bulk list processing while we modify the list */
|
||||||
* with the bulk list while BLE is set.
|
|
||||||
*/
|
flags = irqsave();
|
||||||
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
|
regval &= ~OHCI_CTRL_BLE;
|
||||||
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
|
||||||
|
/* Find the ED in the bulk list. */
|
||||||
|
|
||||||
head = (struct lpc17_ed_s *)lpc17_getreg(LPC17_USBHOST_BULKHEADED);
|
head = (struct lpc17_ed_s *)lpc17_getreg(LPC17_USBHOST_BULKHEADED);
|
||||||
for (prev = NULL, curr = head;
|
for (prev = NULL, curr = head;
|
||||||
curr && curr != ed;
|
curr && curr != ed;
|
||||||
prev = curr, curr = (struct lpc17_ed_s *)curr->hw.nexted);
|
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 bulk list. */
|
/* It would be a bug if we do not find the ED in the bulk list. */
|
||||||
|
|
||||||
DEBUGASSERT(curr != NULL);
|
DEBUGASSERT(curr != NULL);
|
||||||
|
|
||||||
@ -1024,15 +1057,6 @@ static inline int lpc17_rembulked(struct lpc17_usbhost_s *priv,
|
|||||||
|
|
||||||
head = (struct lpc17_ed_s *)ed->hw.nexted;
|
head = (struct lpc17_ed_s *)ed->hw.nexted;
|
||||||
lpc17_putreg((uint32_t)head, LPC17_USBHOST_BULKHEADED);
|
lpc17_putreg((uint32_t)head, LPC17_USBHOST_BULKHEADED);
|
||||||
|
|
||||||
/* If the bulk list is now empty, then disable it */
|
|
||||||
|
|
||||||
if (head == NULL);
|
|
||||||
{
|
|
||||||
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
|
||||||
regval &= ~OHCI_CTRL_BLE;
|
|
||||||
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1044,6 +1068,21 @@ static inline int lpc17_rembulked(struct lpc17_usbhost_s *priv,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Re-enable bulk list processing if the bulk list is still non-empty
|
||||||
|
* after removing the ED node.
|
||||||
|
*/
|
||||||
|
|
||||||
|
lpc17_putreg(0, LPC17_USBHOST_BULKED);
|
||||||
|
if (lpc17_getreg(LPC17_USBHOST_BULKHEADED) != 0)
|
||||||
|
{
|
||||||
|
/* If the bulk list is now empty, then disable it */
|
||||||
|
|
||||||
|
regval = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
|
regval |= OHCI_CTRL_BLE;
|
||||||
|
lpc17_putreg(regval, LPC17_USBHOST_CTRL);
|
||||||
|
}
|
||||||
|
|
||||||
|
irqrestore(flags);
|
||||||
return OK;
|
return OK;
|
||||||
#else
|
#else
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
@ -3246,6 +3285,7 @@ static int lpc17_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
|
|||||||
struct lpc17_gtd_s *td;
|
struct lpc17_gtd_s *td;
|
||||||
struct lpc17_gtd_s *next;
|
struct lpc17_gtd_s *next;
|
||||||
struct lpc17_xfrinfo_s *xfrinfo;
|
struct lpc17_xfrinfo_s *xfrinfo;
|
||||||
|
uint32_t ctrl;
|
||||||
irqstate_t flags;
|
irqstate_t flags;
|
||||||
|
|
||||||
DEBUGASSERT(priv != NULL && ed != NULL);
|
DEBUGASSERT(priv != NULL && ed != NULL);
|
||||||
@ -3269,15 +3309,42 @@ static int lpc17_cancel(FAR struct usbhost_driver_s *drvr, usbhost_ep_t ep)
|
|||||||
if (xfrinfo->wdhwait)
|
if (xfrinfo->wdhwait)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
/* We really need some kind of atomic test and set to do this right */
|
/* Control endpoints should not come through this path and
|
||||||
|
* isochronous endpoints are not yet implemented. So we only have
|
||||||
|
* to distinguish bulk and interrupt endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
td = (struct lpc17_gtd_s *)(ed->hw.headp & ED_HEADP_ADDR_MASK);
|
if (ed->xfrtype == USB_EP_ATTR_XFER_BULK)
|
||||||
ed->hw.headp = LPC17_TDTAIL_ADDR;
|
{
|
||||||
ed->xfrinfo = NULL;
|
/* Disable bulk list processing while we modify the list */
|
||||||
|
|
||||||
/* Free all transfer descriptors that were connected to the ED */
|
ctrl = lpc17_getreg(LPC17_USBHOST_CTRL);
|
||||||
|
lpc17_putreg(ctrl & ~OHCI_CTRL_BLE, LPC17_USBHOST_CTRL);
|
||||||
|
|
||||||
|
/* Remove the TDs attached to the ED, keeping the ED in the list */
|
||||||
|
|
||||||
|
td = (struct lpc17_gtd_s *)(ed->hw.headp & ED_HEADP_ADDR_MASK);
|
||||||
|
ed->hw.headp = LPC17_TDTAIL_ADDR;
|
||||||
|
ed->xfrinfo = NULL;
|
||||||
|
|
||||||
|
/* Re-enable bulk list processing, if it was enabled before */
|
||||||
|
|
||||||
|
lpc17_putreg(0, LPC17_USBHOST_BULKED);
|
||||||
|
lpc17_putreg(ctrl, LPC17_USBHOST_CTRL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Remove the TDs attached to the ED, keeping the Ed in the list */
|
||||||
|
|
||||||
|
td = (struct lpc17_gtd_s *)(ed->hw.headp & ED_HEADP_ADDR_MASK);
|
||||||
|
ed->hw.headp = LPC17_TDTAIL_ADDR;
|
||||||
|
ed->xfrinfo = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free all transfer descriptors that were connected to the ED. In
|
||||||
|
* some race conditions with the hardware, this might be none.
|
||||||
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(td != (struct lpc17_gtd_s *)LPC17_TDTAIL_ADDR);
|
|
||||||
while (td != (struct lpc17_gtd_s *)LPC17_TDTAIL_ADDR)
|
while (td != (struct lpc17_gtd_s *)LPC17_TDTAIL_ADDR)
|
||||||
{
|
{
|
||||||
next = (struct lpc17_gtd_s *)td->hw.nexttd;
|
next = (struct lpc17_gtd_s *)td->hw.nexttd;
|
||||||
|
@ -856,6 +856,8 @@ static int sam_addctrled(struct sam_ed_s *ed)
|
|||||||
|
|
||||||
/* Re-enable control list processing. */
|
/* Re-enable control list processing. */
|
||||||
|
|
||||||
|
sam_putreg(0, SAM_USBHOST_CTRLED);
|
||||||
|
|
||||||
regval = sam_getreg(SAM_USBHOST_CTRL);
|
regval = sam_getreg(SAM_USBHOST_CTRL);
|
||||||
regval |= OHCI_CTRL_CLE;
|
regval |= OHCI_CTRL_CLE;
|
||||||
sam_putreg(regval, SAM_USBHOST_CTRL);
|
sam_putreg(regval, SAM_USBHOST_CTRL);
|
||||||
@ -887,9 +889,7 @@ static inline int sam_remctrled(struct sam_ed_s *ed)
|
|||||||
regval &= ~OHCI_CTRL_CLE;
|
regval &= ~OHCI_CTRL_CLE;
|
||||||
sam_putreg(regval, SAM_USBHOST_CTRL);
|
sam_putreg(regval, SAM_USBHOST_CTRL);
|
||||||
|
|
||||||
/* Find the ED in the control list. NOTE: We really should never be mucking
|
/* Find the ED in the control list. */
|
||||||
* with the control list while BLE is set.
|
|
||||||
*/
|
|
||||||
|
|
||||||
physed = sam_getreg(SAM_USBHOST_CTRLHEADED);
|
physed = sam_getreg(SAM_USBHOST_CTRLHEADED);
|
||||||
for (curr = (struct sam_ed_s *)sam_virtramaddr(physed), prev = NULL;
|
for (curr = (struct sam_ed_s *)sam_virtramaddr(physed), prev = NULL;
|
||||||
@ -928,6 +928,7 @@ static inline int sam_remctrled(struct sam_ed_s *ed)
|
|||||||
* after removing the ED node.
|
* after removing the ED node.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
sam_putreg(0, SAM_USBHOST_CTRLED);
|
||||||
if (sam_getreg(SAM_USBHOST_CTRLHEADED) != 0)
|
if (sam_getreg(SAM_USBHOST_CTRLHEADED) != 0)
|
||||||
{
|
{
|
||||||
/* If the control list is now empty, then disable it */
|
/* If the control list is now empty, then disable it */
|
||||||
@ -973,6 +974,8 @@ static inline int sam_addbulked(struct sam_ed_s *ed)
|
|||||||
|
|
||||||
/* Re-enable bulk list processing. */
|
/* Re-enable bulk list processing. */
|
||||||
|
|
||||||
|
sam_putreg(0, SAM_USBHOST_BULKED);
|
||||||
|
|
||||||
regval = sam_getreg(SAM_USBHOST_CTRL);
|
regval = sam_getreg(SAM_USBHOST_CTRL);
|
||||||
regval |= OHCI_CTRL_BLE;
|
regval |= OHCI_CTRL_BLE;
|
||||||
sam_putreg(regval, SAM_USBHOST_CTRL);
|
sam_putreg(regval, SAM_USBHOST_CTRL);
|
||||||
@ -1008,9 +1011,7 @@ static inline int sam_rembulked(struct sam_ed_s *ed)
|
|||||||
regval &= ~OHCI_CTRL_BLE;
|
regval &= ~OHCI_CTRL_BLE;
|
||||||
sam_putreg(regval, SAM_USBHOST_CTRL);
|
sam_putreg(regval, SAM_USBHOST_CTRL);
|
||||||
|
|
||||||
/* Find the ED in the bulk list. NOTE: We really should never be mucking
|
/* Find the ED in the bulk list. */
|
||||||
* with the bulk list while BLE is set.
|
|
||||||
*/
|
|
||||||
|
|
||||||
physed = sam_getreg(SAM_USBHOST_BULKHEADED);
|
physed = sam_getreg(SAM_USBHOST_BULKHEADED);
|
||||||
for (curr = (struct sam_ed_s *)sam_virtramaddr(physed), prev = NULL;
|
for (curr = (struct sam_ed_s *)sam_virtramaddr(physed), prev = NULL;
|
||||||
@ -1049,6 +1050,7 @@ static inline int sam_rembulked(struct sam_ed_s *ed)
|
|||||||
* after removing the ED node.
|
* after removing the ED node.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
sam_getreg(0, SAM_USBHOST_BULKED);
|
||||||
if (sam_getreg(SAM_USBHOST_BULKHEADED) != 0)
|
if (sam_getreg(SAM_USBHOST_BULKHEADED) != 0)
|
||||||
{
|
{
|
||||||
/* If the bulk list is now empty, then disable it */
|
/* If the bulk list is now empty, then disable it */
|
||||||
@ -3646,20 +3648,52 @@ static int sam_cancel(struct usbhost_driver_s *drvr, usbhost_ep_t ep)
|
|||||||
if (eplist->wdhwait)
|
if (eplist->wdhwait)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
/* We really need some kind of atomic test and set to do this right */
|
/* Control endpoints should not come through this path and
|
||||||
|
* isochronous endpoints are not yet implemented. So we only have
|
||||||
|
* to distinguish bulk and interrupt endpoints.
|
||||||
|
*/
|
||||||
|
|
||||||
paddr = ed->hw.headp & ED_HEADP_ADDR_MASK;
|
if (ed->xfrtype == USB_EP_ATTR_XFER_BULK)
|
||||||
td = (struct sam_gtd_s *)sam_virtramaddr(paddr);
|
{
|
||||||
|
/* Disable bulk list processing while we modify the list */
|
||||||
|
|
||||||
paddr = sam_physramaddr((uintptr_t)eplist->tail);
|
ctrl = sam_getreg(SAM_USBHOST_CTRL);
|
||||||
ed->hw.headp = paddr;
|
sam_putreg(ctrl & ~OHCI_CTRL_BLE, SAM_USBHOST_CTRL);
|
||||||
|
|
||||||
arch_clean_dcache((uintptr_t)ed,
|
/* Remove the TDs attached to the ED, keeping the ED in the list */
|
||||||
(uintptr_t)ed + sizeof(struct ohci_ed_s));
|
|
||||||
|
|
||||||
/* Free all transfer descriptors that were connected to the ED */
|
paddr = ed->hw.headp & ED_HEADP_ADDR_MASK;
|
||||||
|
td = (struct sam_gtd_s *)sam_virtramaddr(paddr);
|
||||||
|
|
||||||
|
paddr = sam_physramaddr((uintptr_t)eplist->tail);
|
||||||
|
ed->hw.headp = paddr;
|
||||||
|
|
||||||
|
arch_clean_dcache((uintptr_t)ed,
|
||||||
|
(uintptr_t)ed + sizeof(struct ohci_ed_s));
|
||||||
|
|
||||||
|
/* Re-enable bulk list processing, if it was enabled before */
|
||||||
|
|
||||||
|
sam_putreg(0, SAM_USBHOST_BULKED);
|
||||||
|
sam_putreg(ctrl, SAM_USBHOST_CTRL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Remove the TDs attached to the ED, keeping the Ed in the list */
|
||||||
|
|
||||||
|
paddr = ed->hw.headp & ED_HEADP_ADDR_MASK;
|
||||||
|
td = (struct sam_gtd_s *)sam_virtramaddr(paddr);
|
||||||
|
|
||||||
|
paddr = sam_physramaddr((uintptr_t)eplist->tail);
|
||||||
|
ed->hw.headp = paddr;
|
||||||
|
|
||||||
|
arch_clean_dcache((uintptr_t)ed,
|
||||||
|
(uintptr_t)ed + sizeof(struct ohci_ed_s));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free all transfer descriptors that were connected to the ED. In some
|
||||||
|
* race conditions with the hardware, this might be none.
|
||||||
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(td != (struct sam_gtd_s *)eplist->tail);
|
|
||||||
while (td != (struct sam_gtd_s *)eplist->tail)
|
while (td != (struct sam_gtd_s *)eplist->tail)
|
||||||
{
|
{
|
||||||
paddr = (uintptr_t)td->hw.nexttd;
|
paddr = (uintptr_t)td->hw.nexttd;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user