/*
- * Copyright (c) 2001-2002 by David Brownell
- *
+ * Copyright (C) 2001-2004 by David Brownell
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
* interrupts) needs careful scheduling. Performance improvements can be
* an ongoing challenge. That's in "ehci-sched.c".
- *
+ *
* USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
* or otherwise through transaction translators (TTs) in USB 2.0 hubs using
* (b) special fields in qh entries or (c) split iso entries. TTs will
/*-------------------------------------------------------------------------*/
-/* update halted (but potentially linked) qh */
-
static inline void
qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
{
+ /* writes to an active overlay are unsafe */
+ BUG_ON(qh->qh_state != QH_STATE_IDLE);
+
qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
qh->hw_alt_next = EHCI_LIST_END;
+ /* Except for control endpoints, we make hardware maintain data
+ * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
+ * and set the pseudo-toggle in udev. Only usb_clear_halt() will
+ * ever clear it.
+ */
+ if (!(qh->hw_info1 & cpu_to_le32(1 << 14))) {
+ unsigned is_out, epnum;
+
+ is_out = !(qtd->hw_token & cpu_to_le32(1 << 8));
+ epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f;
+ if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
+ qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
+ usb_settoggle (qh->dev, epnum, is_out, 1);
+ }
+ }
+
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
wmb ();
qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
}
+/* if it weren't for a common silicon quirk (writing the dummy into the qh
+ * overlay, so qh->hw_token wrongly becomes inactive/halted), only fault
+ * recovery (including urb dequeue) would need software changes to a QH...
+ */
+static void
+qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+ struct ehci_qtd *qtd;
+
+ if (list_empty (&qh->qtd_list))
+ qtd = qh->dummy;
+ else {
+ qtd = list_entry (qh->qtd_list.next,
+ struct ehci_qtd, qtd_list);
+ /* first qtd may already be partially processed */
+ if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current)
+ qtd = NULL;
+ }
+
+ if (qtd)
+ qh_update (ehci, qh, qtd);
+}
+
/*-------------------------------------------------------------------------*/
static void qtd_copy_status (
usb_pipein (urb->pipe) ? "in" : "out",
token, urb->status);
- /* stall indicates some recovery action is needed */
- if (urb->status == -EPIPE) {
- int pipe = urb->pipe;
-
- if (!usb_pipecontrol (pipe))
- usb_endpoint_halt (urb->dev,
- usb_pipeendpoint (pipe),
- usb_pipeout (pipe));
-
/* if async CSPLIT failed, try cleaning out the TT buffer */
- } else if (urb->dev->tt && !usb_pipeint (urb->pipe)
+ if (urb->status != -EPIPE
+ && urb->dev->tt && !usb_pipeint (urb->pipe)
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
- && (!ehci_is_ARC(ehci)
- || urb->dev->tt->hub !=
- ehci->hcd.self.root_hub)) {
+ && (!ehci_is_TDI(ehci)
+ || urb->dev->tt->hub !=
+ ehci_to_hcd(ehci)->self.root_hub)) {
#ifdef DEBUG
struct usb_device *tt = urb->dev->tt->hub;
dev_dbg (&tt->dev,
}
static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
+ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+__releases(ehci->lock)
+__acquires(ehci->lock)
{
- if (likely (urb->hcpriv != 0)) {
+ if (likely (urb->hcpriv != NULL)) {
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
/* S-mask in a QH means it's an interrupt urb */
- if ((qh->hw_info2 & __constant_cpu_to_le32 (0x00ff)) != 0) {
+ if ((qh->hw_info2 & __constant_cpu_to_le32 (QH_SMASK)) != 0) {
/* ... update hc-wide periodic stats (for usbfs) */
- hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
+ ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
}
qh_put (qh);
}
/* complete() can reenter this HCD */
spin_unlock (&ehci->lock);
- usb_hcd_giveback_urb (&ehci->hcd, urb, regs);
+ usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
spin_lock (&ehci->lock);
}
+static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
+static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
+
+static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
+static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
/*
* Process and free completed qtds for a qh, returning URBs to drivers.
*/
#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
static unsigned
-qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
+qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *last = NULL, *end = qh->dummy;
struct list_head *entry, *tmp;
/* clean up any state from previous QTD ...*/
if (last) {
if (likely (last->urb != urb)) {
- ehci_urb_done (ehci, last->urb, regs);
+ ehci_urb_done (ehci, last->urb);
count++;
}
ehci_qtd_free (ehci, last);
if ((token & QTD_STS_HALT) != 0) {
stopped = 1;
- /* magic dummy for some short reads; qh won't advance */
+ /* magic dummy for some short reads; qh won't advance.
+ * that silicon quirk can kick in with this dummy too.
+ */
} else if (IS_SHORT_READ (token)
- && (qh->hw_alt_next & QTD_MASK)
- == ehci->async->hw_alt_next) {
+ && !(qtd->hw_alt_next & EHCI_LIST_END)) {
stopped = 1;
goto halt;
}
/* stop scanning when we reach qtds the hc is using */
} else if (likely (!stopped
- && HCD_IS_RUNNING (ehci->hcd.state))) {
+ && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))) {
break;
} else {
stopped = 1;
+ if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
+ urb->status = -ESHUTDOWN;
+
/* ignore active urbs unless some previous qtd
* for the urb faulted (including short read) or
* its urb was canceled. we may patch qh or qtds.
*/
if (likely (urb->status == -EINPROGRESS))
continue;
-
+
/* issue status after short control reads */
if (unlikely (do_status != 0)
&& QTD_PID (token) == 0 /* OUT */) {
wmb ();
}
}
-
+
/* remove it from the queue */
spin_lock (&urb->lock);
qtd_copy_status (ehci, urb, qtd->length, token);
}
/* last urb's completion might still need calling */
- if (likely (last != 0)) {
- ehci_urb_done (ehci, last->urb, regs);
+ if (likely (last != NULL)) {
+ ehci_urb_done (ehci, last->urb);
count++;
ehci_qtd_free (ehci, last);
}
/* restore original state; caller must unlink or relink */
qh->qh_state = state;
- /* update qh after fault cleanup */
- if (unlikely (stopped != 0)
- /* some EHCI 0.95 impls will overlay dummy qtds */
- || qh->hw_qtd_next == EHCI_LIST_END) {
- if (list_empty (&qh->qtd_list))
- end = qh->dummy;
- else {
- end = list_entry (qh->qtd_list.next,
- struct ehci_qtd, qtd_list);
- /* first qtd may already be partially processed */
- if (cpu_to_le32 (end->qtd_dma) == qh->hw_current)
- end = NULL;
+ /* be sure the hardware's done with the qh before refreshing
+ * it after fault cleanup, or recovering from silicon wrongly
+ * overlaying the dummy qtd (which reduces DMA chatter).
+ */
+ if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) {
+ switch (state) {
+ case QH_STATE_IDLE:
+ qh_refresh(ehci, qh);
+ break;
+ case QH_STATE_LINKED:
+ /* should be rare for periodic transfers,
+ * except maybe high bandwidth ...
+ */
+ if ((__constant_cpu_to_le32 (QH_SMASK)
+ & qh->hw_info2) != 0) {
+ intr_deschedule (ehci, qh);
+ (void) qh_schedule (ehci, qh);
+ } else
+ unlink_async (ehci, qh);
+ break;
+ /* otherwise, unlink already started */
}
- if (end)
- qh_update (ehci, qh, end);
}
return count;
struct ehci_hcd *ehci,
struct urb *urb,
struct list_head *head,
- int flags
+ gfp_t flags
) {
struct ehci_qtd *qtd, *qtd_prev;
dma_addr_t buf;
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head);
- }
+
+ /* for zero length DATA stages, STATUS is always IN */
+ if (len == 0)
+ token |= (1 /* "in" */ << 8);
+ }
/*
* data transfer stage: buffer setup
*/
- if (likely (len > 0))
- buf = urb->transfer_dma;
- else
- buf = 0;
+ buf = urb->transfer_dma;
- // FIXME this 'buf' check break some zlps...
- if (!buf || is_input)
+ if (is_input)
token |= (1 /* "in" */ << 8);
/* else it's already initted to "out" pid (0 << 8) */
* control requests may need a terminating data "status" ack;
* bulk ones may need a terminating short packet (zero length).
*/
- if (likely (buf != 0)) {
+ if (likely (urb->transfer_buffer_length != 0)) {
int one_more = 0;
if (usb_pipecontrol (urb->pipe)) {
/*-------------------------------------------------------------------------*/
-/*
- * Hardware maintains data toggle (like OHCI) ... here we (re)initialize
- * the hardware data toggle in the QH, and set the pseudo-toggle in udev
- * so we can see if usb_clear_halt() was called. NOP for control, since
- * we set up qh->hw_info1 to always use the QTD toggle bits.
- */
-static inline void
-clear_toggle (struct usb_device *udev, int ep, int is_out, struct ehci_qh *qh)
-{
- vdbg ("clear toggle, dev %d ep 0x%x-%s",
- udev->devnum, ep, is_out ? "out" : "in");
- qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
- usb_settoggle (udev, ep, is_out, 1);
-}
-
// Would be best to create all qh's from config descriptors,
// when each interface/altsetting is established. Unlink
// any previous qh and cancel its urbs first; endpoints are
qh_make (
struct ehci_hcd *ehci,
struct urb *urb,
- int flags
+ gfp_t flags
) {
struct ehci_qh *qh = ehci_qh_alloc (ehci, flags);
u32 info1 = 0, info2 = 0;
* For control/bulk requests, the HC or TT handles these.
*/
if (type == PIPE_INTERRUPT) {
- qh->usecs = usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
- hb_mult (maxp) * max_packet (maxp));
+ qh->usecs = NS_TO_US (usb_calc_bus_time (USB_SPEED_HIGH, is_input, 0,
+ hb_mult (maxp) * max_packet (maxp)));
qh->start = NO_FRAME;
if (urb->dev->speed == USB_SPEED_HIGH) {
qh->c_usecs = 0;
qh->gap_uf = 0;
- /* FIXME handle HS periods of less than 1 frame. */
qh->period = urb->interval >> 3;
- if (qh->period < 1) {
+ if (qh->period == 0 && urb->interval != 1) {
+ /* NOTE interval 2 or 4 uframes could work.
+ * But interval 1 scheduling is simpler, and
+ * includes high bandwidth.
+ */
dbg ("intr period %d uframes, NYET!",
urb->interval);
goto done;
}
} else {
+ struct usb_tt *tt = urb->dev->tt;
+ int think_time;
+
/* gap is f(FS/LS transfer times) */
qh->gap_uf = 1 + usb_calc_bus_time (urb->dev->speed,
is_input, 0, maxp) / (125 * 1000);
qh->c_usecs = HS_USECS (0);
}
+ think_time = tt ? tt->think_time : 0;
+ qh->tt_usecs = NS_TO_US (think_time +
+ usb_calc_bus_time (urb->dev->speed,
+ is_input, 0, max_packet (maxp)));
qh->period = urb->interval;
}
-
- /* support for tt scheduling */
- qh->dev = usb_get_dev (urb->dev);
}
+ /* support for tt scheduling, and access to toggles */
+ qh->dev = urb->dev;
+
/* using TT? */
switch (urb->dev->speed) {
case USB_SPEED_LOW:
info1 |= maxp << 16;
info2 |= (EHCI_TUNE_MULT_TT << 30);
- info2 |= urb->dev->ttport << 23;
- /* set the address of the TT; for ARC's integrated
+ /* Some Freescale processors have an erratum in which the
+ * port number in the queue head was 0..N-1 instead of 1..N.
+ */
+ if (ehci_has_fsl_portno_bug(ehci))
+ info2 |= (urb->dev->ttport-1) << 23;
+ else
+ info2 |= urb->dev->ttport << 23;
+
+ /* set the address of the TT; for TDI's integrated
* root hub tt, leave it zeroed.
*/
- if (!ehci_is_ARC(ehci)
- || urb->dev->tt->hub != ehci->hcd.self.root_hub)
+ if (!ehci_is_TDI(ehci)
+ || urb->dev->tt->hub !=
+ ehci_to_hcd(ehci)->self.root_hub)
info2 |= urb->dev->tt->hub->devnum << 16;
/* NOTE: if (PIPE_INTERRUPT) { scheduler sets c-mask } */
}
break;
default:
- dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
done:
qh_put (qh);
return NULL;
qh->qh_state = QH_STATE_IDLE;
qh->hw_info1 = cpu_to_le32 (info1);
qh->hw_info2 = cpu_to_le32 (info2);
- qh_update (ehci, qh, qh->dummy);
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
+ qh_refresh (ehci, qh);
return qh;
}
static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- u32 dma = QH_NEXT (qh->qh_dma);
+ __le32 dma = QH_NEXT (qh->qh_dma);
struct ehci_qh *head;
/* (re)start the async schedule? */
(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
cmd |= CMD_ASE | CMD_RUN;
writel (cmd, &ehci->regs->command);
- ehci->hcd.state = USB_STATE_RUNNING;
+ ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* posted write need not be known to HC yet ... */
}
}
- qh->hw_token &= ~HALT_BIT;
+ /* clear halt and/or toggle; and maybe recover from silicon quirk */
+ if (qh->qh_state == QH_STATE_IDLE)
+ qh_refresh (ehci, qh);
/* splice right after start */
qh->qh_next = head->qh_next;
/*-------------------------------------------------------------------------*/
-#define QH_ADDR_MASK __constant_le32_to_cpu(0x7f)
+#define QH_ADDR_MASK __constant_cpu_to_le32(0x7f)
/*
* For control/bulk/interrupt, return QH with these TDs appended.
qtd = list_entry (qtd_list->next, struct ehci_qtd,
qtd_list);
- /* control qh may need patching after enumeration */
+ /* control qh may need patching ... */
if (unlikely (epnum == 0)) {
- /* set_address changes the address */
- if ((qh->hw_info1 & QH_ADDR_MASK) == 0)
- qh->hw_info1 |= cpu_to_le32 (
- usb_pipedevice (urb->pipe));
-
- /* for full speed, ep0 maxpacket can grow */
- else if (!(qh->hw_info1
- & __constant_cpu_to_le32 (0x3 << 12))) {
- u32 info, max;
-
- info = le32_to_cpu (qh->hw_info1);
- max = urb->dev->descriptor.bMaxPacketSize0;
- if (max > (0x07ff & (info >> 16))) {
- info &= ~(0x07ff << 16);
- info |= max << 16;
- qh->hw_info1 = cpu_to_le32 (info);
- }
- }
/* usb_reset_device() briefly reverts to address 0 */
if (usb_pipedevice (urb->pipe) == 0)
qh->hw_info1 &= ~QH_ADDR_MASK;
}
- /* usb_clear_halt() means qh data toggle gets reset */
- if (unlikely (!usb_gettoggle (urb->dev,
- (epnum & 0x0f), !(epnum & 0x10)))
- && !usb_pipecontrol (urb->pipe)) {
- /* "never happens": drivers do stall cleanup right */
- if (qh->qh_state != QH_STATE_IDLE
- && !list_empty (&qh->qtd_list)
- && qh->qh_state != QH_STATE_COMPLETING)
- ehci_warn (ehci, "clear toggle dev%d "
- "ep%d%s: not idle\n",
- usb_pipedevice (urb->pipe),
- epnum & 0x0f,
- usb_pipein (urb->pipe)
- ? "in" : "out");
- /* else we know this overlay write is safe */
- clear_toggle (urb->dev,
- epnum & 0x0f, !(epnum & 0x10), qh);
- }
-
/* just one way to queue requests: swap with the dummy qtd.
- * only hc or qh_completions() usually modify the overlay.
+ * only hc or qh_refresh() ever modify the overlay.
*/
- if (likely (qtd != 0)) {
+ if (likely (qtd != NULL)) {
struct ehci_qtd *dummy;
dma_addr_t dma;
- u32 token;
+ __le32 token;
/* to avoid racing the HC, use the dummy td instead of
* the first td of our list (becomes new dummy). both
static int
submit_async (
struct ehci_hcd *ehci,
+ struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
- int mem_flags
+ gfp_t mem_flags
) {
struct ehci_qtd *qtd;
- struct hcd_dev *dev;
int epnum;
unsigned long flags;
struct ehci_qh *qh = NULL;
+ int rc = 0;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
- dev = (struct hcd_dev *)urb->dev->hcpriv;
- epnum = usb_pipeendpoint (urb->pipe);
- if (usb_pipein (urb->pipe) && !usb_pipecontrol (urb->pipe))
- epnum |= 0x10;
+ epnum = ep->desc.bEndpointAddress;
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
"%s %s urb %p ep%d%s len %d, qtd %p [qh %p]\n",
__FUNCTION__, urb->dev->devpath, urb,
- epnum & 0x0f, usb_pipein (urb->pipe) ? "in" : "out",
+ epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
urb->transfer_buffer_length,
- qtd, dev ? dev->ep [epnum] : (void *)~0);
+ qtd, ep->hcpriv);
#endif
spin_lock_irqsave (&ehci->lock, flags);
- qh = qh_append_tds (ehci, urb, qtd_list, epnum, &dev->ep [epnum]);
+ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
+ &ehci_to_hcd(ehci)->flags))) {
+ rc = -ESHUTDOWN;
+ goto done;
+ }
+
+ qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+ if (unlikely(qh == NULL)) {
+ rc = -ENOMEM;
+ goto done;
+ }
/* Control/bulk operations through TTs don't need scheduling,
* the HC and TT handle it when the TT has a buffer ready.
*/
- if (likely (qh != 0)) {
- if (likely (qh->qh_state == QH_STATE_IDLE))
- qh_link_async (ehci, qh_get (qh));
- }
+ if (likely (qh->qh_state == QH_STATE_IDLE))
+ qh_link_async (ehci, qh_get (qh));
+ done:
spin_unlock_irqrestore (&ehci->lock, flags);
- if (unlikely (qh == 0)) {
+ if (unlikely (qh == NULL))
qtd_list_free (ehci, urb, qtd_list);
- return -ENOMEM;
- }
- return 0;
+ return rc;
}
/*-------------------------------------------------------------------------*/
/* the async qh for the qtds being reclaimed are now unlinked from the HC */
-static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
-
-static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
+static void end_unlink_async (struct ehci_hcd *ehci)
{
struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL;
- qh_put (qh); // refcount from reclaim
+ qh_put (qh); // refcount from reclaim
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
ehci->reclaim_ready = 0;
qh->reclaim = NULL;
- qh_completions (ehci, qh, regs);
+ qh_completions (ehci, qh);
if (!list_empty (&qh->qtd_list)
- && HCD_IS_RUNNING (ehci->hcd.state))
+ && HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
qh_link_async (ehci, qh);
else {
qh_put (qh); // refcount from async list
/* it's not free to turn the async schedule on/off; leave it
* active but idle for a while once it empties.
*/
- if (HCD_IS_RUNNING (ehci->hcd.state)
- && ehci->async->qh_next.qh == 0)
+ if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)
+ && ehci->async->qh_next.qh == NULL)
timer_action (ehci, TIMER_ASYNC_OFF);
}
struct ehci_qh *prev;
#ifdef DEBUG
+ assert_spin_locked(&ehci->lock);
if (ehci->reclaim
|| (qh->qh_state != QH_STATE_LINKED
&& qh->qh_state != QH_STATE_UNLINK_WAIT)
-#ifdef CONFIG_SMP
-// this macro lies except on SMP compiles
- || !spin_is_locked (&ehci->lock)
-#endif
)
BUG ();
#endif
/* stop async schedule right now? */
if (unlikely (qh == ehci->async)) {
/* can't get here without STS_ASS set */
- if (ehci->hcd.state != USB_STATE_HALT) {
+ if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
+ && !ehci->reclaim) {
+ /* ... and CMD_IAAD clear */
writel (cmd & ~CMD_ASE, &ehci->regs->command);
wmb ();
// handshake later, if we need to
+ timer_action_done (ehci, TIMER_ASYNC_OFF);
}
- timer_action_done (ehci, TIMER_ASYNC_OFF);
return;
- }
+ }
qh->qh_state = QH_STATE_UNLINK;
ehci->reclaim = qh = qh_get (qh);
prev->qh_next = qh->qh_next;
wmb ();
- if (unlikely (ehci->hcd.state == USB_STATE_HALT)) {
+ if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) {
/* if (unlikely (qh->reclaim != 0))
- * this will recurse, probably not much
+ * this will recurse, probably not much
*/
- end_unlink_async (ehci, NULL);
+ end_unlink_async (ehci);
return;
}
/*-------------------------------------------------------------------------*/
-static void
-scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
+static void scan_async (struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
timer_action_done (ehci, TIMER_ASYNC_SHRINK);
rescan:
qh = ehci->async->qh_next.qh;
- if (likely (qh != 0)) {
+ if (likely (qh != NULL)) {
do {
/* clean any finished work for this qh */
if (!list_empty (&qh->qtd_list)
*/
qh = qh_get (qh);
qh->stamp = ehci->stamp;
- temp = qh_completions (ehci, qh, regs);
+ temp = qh_completions (ehci, qh);
qh_put (qh);
if (temp != 0) {
goto rescan;