On Wed, Apr 03, 2002 at 10:45:09AM -0800, Greg KH wrote:
> [EMAIL PROTECTED], 2002-04-02 16:57:23-08:00, [EMAIL PROTECTED]
> USB ohci driver fixes
>
> - An oopsable bug affecting unlink of interrupt
> transfers. Fix mirrors one done ages ago for ISO.
> (Original patch by Matt Hughes)
> - Better cleanup on init failure (Matthew Frederickson)
>
> drivers/usb/usb-ohci.c | 100 ++++++++++++++++++++++++++-----------------------
> 1 files changed, 55 insertions(+), 45 deletions(-)
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.305 -> 1.306
# drivers/usb/usb-ohci.c 1.21 -> 1.22
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/04/02 [EMAIL PROTECTED] 1.306
# USB ohci driver fixes
#
# - An oopsable bug affecting unlink of interrupt
# transfers. Fix mirrors one done ages ago for ISO.
# (Original patch by Matt Hughes)
# - Better cleanup on init failure (Matthew Frederickson)
# --------------------------------------------
#
diff -Nru a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
--- a/drivers/usb/usb-ohci.c Wed Apr 3 10:47:57 2002
+++ b/drivers/usb/usb-ohci.c Wed Apr 3 10:47:57 2002
@@ -12,9 +12,10 @@
*
* History:
*
+ * 2002/03/08 interrupt unlink fix (Matt Hughes), better cleanup on
+ * load failure (Matthew Frederickson)
* 2002/01/20 async unlink fixes: return -EINPROGRESS (per spec) and
* make interrupt unlink-in-completion work (db)
- *
* 2001/09/19 USB_ZERO_PACKET support (Jean Tourrilhes)
* 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
* 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
@@ -1076,6 +1077,28 @@
/*-------------------------------------------------------------------------*/
+/* scan the periodic table to find and unlink this ED */
+static void periodic_unlink (
+ struct ohci *ohci,
+ struct ed *ed,
+ unsigned index,
+ unsigned period
+) {
+ for (; index < NUM_INTS; index += period) {
+ __u32 *ed_p = &ohci->hcca->int_table [index];
+
+ /* ED might have been unlinked through another path */
+ while (*ed_p != 0) {
+ if ((dma_to_ed (ohci, le32_to_cpup (ed_p))) == ed) {
+ *ed_p = ed->hwNextED;
+ break;
+ }
+ ed_p = & ((dma_to_ed (ohci,
+ le32_to_cpup (ed_p)))->hwNextED);
+ }
+ }
+}
+
/* unlink an ed from one of the HC chains.
* just the link to the ed is unlinked.
* the link from the ed still points to another operational ed or 0
@@ -1083,11 +1106,7 @@
static int ep_unlink (ohci_t * ohci, ed_t * ed)
{
- int int_branch;
int i;
- int inter;
- int interval;
- __u32 * ed_p;
ed->hwINFO |= cpu_to_le32 (OHCI_ED_SKIP);
@@ -1127,21 +1146,8 @@
break;
case PIPE_INTERRUPT:
- int_branch = ed->int_branch;
- interval = ed->int_interval;
-
- for (i = 0; i < ep_rev (6, interval); i += inter) {
- for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) +
int_branch]), inter = 1;
- (*ed_p != 0) && (*ed_p != ed->hwNextED);
- ed_p = &((dma_to_ed (ohci, le32_to_cpup
(ed_p)))->hwNextED),
- inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup
(ed_p)))->int_interval)) {
- if((dma_to_ed (ohci, le32_to_cpup (ed_p))) ==
ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- }
- }
- for (i = int_branch; i < 32; i += interval)
+ periodic_unlink (ohci, ed, 0, 1);
+ for (i = ed->int_branch; i < 32; i += ed->int_interval)
ohci->ohci_int_load[i] -= ed->int_load;
#ifdef DEBUG
ep_print_int_eds (ohci, "UNLINK_INT");
@@ -1152,23 +1158,13 @@
if (ohci->ed_isotail == ed)
ohci->ed_isotail = ed->ed_prev;
if (ed->hwNextED != 0)
- (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))->ed_prev =
ed->ed_prev;
+ (dma_to_ed (ohci, le32_to_cpup (&ed->hwNextED)))
+ ->ed_prev = ed->ed_prev;
- if (ed->ed_prev != NULL) {
+ if (ed->ed_prev != NULL)
ed->ed_prev->hwNextED = ed->hwNextED;
- } else {
- for (i = 0; i < 32; i++) {
- for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i)]);
- *ed_p != 0;
- ed_p = &((dma_to_ed (ohci,
le32_to_cpup (ed_p)))->hwNextED)) {
- // inter = ep_rev (6, (dma_to_ed (ohci,
le32_to_cpup (ed_p)))->int_interval);
- if((dma_to_ed (ohci, le32_to_cpup (ed_p))) ==
ed) {
- *ed_p = ed->hwNextED;
- break;
- }
- }
- }
- }
+ else
+ periodic_unlink (ohci, ed, 0, 1);
#ifdef DEBUG
ep_print_int_eds (ohci, "UNLINK_ISO");
#endif
@@ -2354,7 +2350,6 @@
static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
{
ohci_t * ohci;
- struct usb_bus * bus;
ohci = (ohci_t *) kmalloc (sizeof *ohci, GFP_KERNEL);
if (!ohci)
@@ -2383,14 +2378,15 @@
INIT_LIST_HEAD (&ohci->timeout_list);
- bus = usb_alloc_bus (&sohci_device_operations);
- if (!bus) {
+ ohci->bus = usb_alloc_bus (&sohci_device_operations);
+ if (!ohci->bus) {
+ pci_set_drvdata (dev, NULL);
+ pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
+ ohci->hcca, ohci->hcca_dma);
kfree (ohci);
return NULL;
}
-
- ohci->bus = bus;
- bus->hcpriv = (void *) ohci;
+ ohci->bus->hcpriv = (void *) ohci;
return ohci;
}
@@ -2416,9 +2412,11 @@
ohci->irq = -1;
}
pci_set_drvdata(ohci->ohci_dev, NULL);
-
- usb_deregister_bus (ohci->bus);
- usb_free_bus (ohci->bus);
+ if (ohci->bus) {
+ if (ohci->bus->busnum)
+ usb_deregister_bus (ohci->bus);
+ usb_free_bus (ohci->bus);
+ }
list_del (&ohci->ohci_hcd_list);
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
@@ -2566,12 +2564,14 @@
{
unsigned long mem_resource, mem_len;
void *mem_base;
+ int status;
if (pci_enable_device(dev) < 0)
return -ENODEV;
if (!dev->irq) {
err("found OHCI device with no IRQ assigned. check BIOS settings!");
+ pci_disable_device (dev);
return -ENODEV;
}
@@ -2580,19 +2580,28 @@
mem_len = pci_resource_len(dev, 0);
if (!request_mem_region (mem_resource, mem_len, ohci_pci_driver.name)) {
dbg ("controller already in use");
+ pci_disable_device (dev);
return -EBUSY;
}
mem_base = ioremap_nocache (mem_resource, mem_len);
if (!mem_base) {
err("Error mapping OHCI memory");
+ release_mem_region (mem_resource, mem_len);
+ pci_disable_device (dev);
return -EFAULT;
}
/* controller writes into our memory */
pci_set_master (dev);
- return hc_found_ohci (dev, dev->irq, mem_base, id);
+ status = hc_found_ohci (dev, dev->irq, mem_base, id);
+ if (status < 0) {
+ iounmap (mem_base);
+ release_mem_region (mem_resource, mem_len);
+ pci_disable_device (dev);
+ }
+ return status;
}
/*-------------------------------------------------------------------------*/
@@ -2630,6 +2639,7 @@
hc_release_ohci (ohci);
release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
+ pci_disable_device (dev);
}
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel