patch-2.4.19 linux-2.4.19/drivers/usb/usb-ohci.c
Next file: linux-2.4.19/drivers/usb/usb-ohci.h
Previous file: linux-2.4.19/drivers/usb/uhci.h
Back to the patch index
Back to the overall index
- Lines: 256
- Date:
Fri Aug 2 17:39:45 2002
- Orig file:
linux-2.4.18/drivers/usb/usb-ohci.c
- Orig date:
Mon Feb 25 11:38:07 2002
diff -urN linux-2.4.18/drivers/usb/usb-ohci.c linux-2.4.19/drivers/usb/usb-ohci.c
@@ -11,7 +11,11 @@
*
*
* 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);
@@ -486,9 +490,8 @@
/* implicitly requeued */
urb->actual_length = 0;
- urb->status = USB_ST_URB_PENDING;
- if (urb_priv->state != URB_DEL)
- td_submit_urb (urb);
+ urb->status = -EINPROGRESS;
+ td_submit_urb (urb);
break;
case PIPE_ISOCHRONOUS:
@@ -790,6 +793,7 @@
/* usb_dec_dev_use done in dl_del_list() */
urb->status = -EINPROGRESS;
spin_unlock_irqrestore (&usb_ed_lock, flags);
+ return -EINPROGRESS;
}
} else {
urb_rm_priv (urb);
@@ -1073,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
@@ -1080,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);
@@ -1124,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");
@@ -1149,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
@@ -1337,6 +1336,7 @@
td->hwPSW [0] = cpu_to_le16 ((data & 0x0FFF) | 0xE000);
/* append to queue */
+ wmb();
td->ed->hwTailP = td->hwNextTD;
}
@@ -1400,8 +1400,10 @@
cnt++;
}
- if (!ohci->sleeping)
+ if (!ohci->sleeping) {
+ wmb();
writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+ }
break;
case PIPE_INTERRUPT:
@@ -1426,8 +1428,10 @@
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
td_fill (ohci, info, data, 0, urb, cnt++);
- if (!ohci->sleeping)
+ if (!ohci->sleeping) {
+ wmb();
writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+ }
break;
case PIPE_ISOCHRONOUS:
@@ -2351,7 +2355,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)
@@ -2380,14 +2383,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;
}
@@ -2413,9 +2417,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);
@@ -2563,12 +2569,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;
}
@@ -2577,19 +2585,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;
}
/*-------------------------------------------------------------------------*/
@@ -2627,6 +2644,7 @@
hc_release_ohci (ohci);
release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
+ pci_disable_device (dev);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)