Commit ee2892c8 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[PATCH] disconnect cleanup, new HCD callback

Attached, find a patch that "ought to" teach OHCI how to do that
cleanup, by implementing the new callback.  (And the first half
is the patch you applied, with that irqsave tweak -- so you should
already have it.)
parent 3c3fbd60
...@@ -313,65 +313,56 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) ...@@ -313,65 +313,56 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
*/ */
static void static void
ohci_free_config (struct usb_hcd *hcd, struct usb_device *udev) ohci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)
{ {
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct hcd_dev *dev = (struct hcd_dev *) udev->hcpriv; int epnum = ep & USB_ENDPOINT_NUMBER_MASK;
int i;
unsigned long flags; unsigned long flags;
struct ed *ed;
/* ASSERT: any requests/urbs are being unlinked */
/* ASSERT: nobody can be submitting urbs for this any more */
ohci_dbg (ohci, "ep %02x disable\n", ep);
epnum <<= 1;
if (epnum != 0 && !(ep & USB_DIR_IN))
epnum |= 1;
rescan: rescan:
/* free any eds, and dummy tds, still hanging around */
spin_lock_irqsave (&ohci->lock, flags); spin_lock_irqsave (&ohci->lock, flags);
for (i = 0; i < 32; i++) { ed = dev->ep [epnum];
struct ed *ed = dev->ep [i]; if (!ed)
goto done;
if (!ed)
continue; if (!HCD_IS_RUNNING (ohci->hcd.state) || ohci->disabled)
ed->state = ED_IDLE;
if (ohci->disabled && ed->state != ED_IDLE) switch (ed->state) {
ed->state = ED_IDLE; case ED_UNLINK: /* wait for hw to finish? */
switch (ed->state) { spin_unlock_irqrestore (&ohci->lock, flags);
case ED_UNLINK: /* wait a frame? */ set_current_state (TASK_UNINTERRUPTIBLE);
goto do_rescan; schedule_timeout (1);
case ED_IDLE: /* fully unlinked */ goto rescan;
case ED_IDLE: /* fully unlinked */
if (list_empty (&ed->td_list)) {
td_free (ohci, ed->dummy); td_free (ohci, ed->dummy);
ed_free (ohci, ed);
break; break;
default:
ohci_err (ohci,
"dev %s ep%d-%s linked; disconnect() bug?\n",
udev->devpath,
(i >> 1) & 0x0f, (i & 1) ? "out" : "in");
/* ED_OPER: some driver disconnect() is broken,
* it didn't even start its unlinks much less wait
* for their completions.
* OTHERWISE: hcd bug, ed is garbage
*
* ... we can't recycle this memory in either case,
* so just leak it to avoid oopsing.
*/
continue;
} }
ed_free (ohci, ed); /* else FALL THROUGH */
default:
/* caller was supposed to have unlinked any requests;
* that's not our job. can't recover; must leak ed.
*/
ohci_err (ohci, "ed %p (#%d) state %d%s\n",
ed, epnum, ed->state,
list_empty (&ed->td_list) ? "" : "(has tds)");
td_free (ohci, ed->dummy);
break;
} }
dev->ep [epnum] = 0;
done:
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irqrestore (&ohci->lock, flags);
return; return;
do_rescan:
#ifdef DEBUG
/* a driver->disconnect() returned before its unlinks completed? */
if (in_interrupt ()) {
ohci_warn (ohci,
"driver disconnect() bug %s ep%d-%s\n",
udev->devpath,
(i >> 1) & 0x0f, (i & 1) ? "out" : "in");
}
#endif
spin_unlock_irqrestore (&ohci->lock, flags);
wait_ms (1);
goto rescan;
} }
static int ohci_get_frame (struct usb_hcd *hcd) static int ohci_get_frame (struct usb_hcd *hcd)
......
...@@ -334,7 +334,7 @@ static const struct hc_driver ohci_pci_hc_driver = { ...@@ -334,7 +334,7 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/ */
.urb_enqueue = ohci_urb_enqueue, .urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue, .urb_dequeue = ohci_urb_dequeue,
.free_config = ohci_free_config, .endpoint_disable = ohci_endpoint_disable,
/* /*
* scheduling support * scheduling support
......
...@@ -333,7 +333,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = { ...@@ -333,7 +333,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
*/ */
.urb_enqueue = ohci_urb_enqueue, .urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue, .urb_dequeue = ohci_urb_dequeue,
.free_config = ohci_free_config, .endpoint_disable = ohci_endpoint_disable,
/* /*
* scheduling support * scheduling support
......
...@@ -2390,7 +2390,6 @@ static const struct hc_driver uhci_driver = { ...@@ -2390,7 +2390,6 @@ static const struct hc_driver uhci_driver = {
.urb_enqueue = uhci_urb_enqueue, .urb_enqueue = uhci_urb_enqueue,
.urb_dequeue = uhci_urb_dequeue, .urb_dequeue = uhci_urb_dequeue,
.free_config = NULL,
.get_frame_number = uhci_hcd_get_frame_number, .get_frame_number = uhci_hcd_get_frame_number,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment