diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-05-12 21:05:59 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-05-12 21:05:59 +0000 |
commit | ba2dacab305c598cd4c34a604f8e276bf5bab5ff (patch) | |
tree | 78670a0139bf4d5ace617b29b7eba82bbc74d602 /drivers/usb/usb-ohci.c | |
parent | b77bf69998121e689c5e86cc5630d39a0a9ee6ca (diff) |
Merge with Linux 2.3.99-pre7 and various other bits.
Diffstat (limited to 'drivers/usb/usb-ohci.c')
-rw-r--r-- | drivers/usb/usb-ohci.c | 136 |
1 files changed, 84 insertions, 52 deletions
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c index 9c9b38167..50388dccf 100644 --- a/drivers/usb/usb-ohci.c +++ b/drivers/usb/usb-ohci.c @@ -81,12 +81,9 @@ static void urb_rm_priv (urb_t * urb) { urb_priv_t * urb_priv = urb->hcpriv; int i; - void * wait; if (!urb_priv) return; - wait = urb_priv->wait; - for (i = 0; i < urb_priv->length; i++) { if (urb_priv->td [i]) { OHCI_FREE (urb_priv->td [i]); @@ -94,11 +91,8 @@ static void urb_rm_priv (urb_t * urb) } kfree (urb->hcpriv); urb->hcpriv = NULL; - - if (wait) { - add_wait_queue (&op_wakeup, wait); - wake_up (&op_wakeup); - } + + wake_up (&op_wakeup); } /*-------------------------------------------------------------------------*/ @@ -476,7 +470,6 @@ static int sohci_submit_urb (urb_t * urb) urb_priv->td_cnt = 0; urb_priv->state = 0; urb_priv->ed = ed; - urb_priv->wait = NULL; /* allocate the TDs */ for (i = 0; i < size; i++) { @@ -527,6 +520,9 @@ static int sohci_unlink_urb (urb_t * urb) if (!urb) /* just to be sure */ return -EINVAL; + if (!urb->dev || !urb->dev->bus) + return -ENODEV; + ohci = (ohci_t *) urb->dev->bus->hcpriv; #ifdef DEBUG @@ -537,25 +533,31 @@ static int sohci_unlink_urb (urb_t * urb) return rh_unlink_urb (urb); /* a request to the virtual root hub */ if (urb->hcpriv) { - if (urb->status == USB_ST_URB_PENDING) { /* URB active? */ + /* URB active? */ + if (urb->status == USB_ST_URB_PENDING && !ohci->disabled) { urb_priv_t * urb_priv = urb->hcpriv; urb_priv->state = URB_DEL; + /* we want to delete the TDs of an URB from an ed - * request the deletion, it will be handled at the next USB-frame */ - urb_priv->wait = &wait; + * request the deletion, it will be handled at the + * next USB-frame */ spin_lock_irqsave (&usb_ed_lock, flags); ep_rm_ed (urb->dev, urb_priv->ed); urb_priv->ed->state |= ED_URB_DEL; spin_unlock_irqrestore (&usb_ed_lock, flags); + add_wait_queue (&op_wakeup, &wait); current->state = TASK_UNINTERRUPTIBLE; - if(schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */ - remove_wait_queue (&op_wakeup, &wait); - else + if (!schedule_timeout (HZ / 10)) /* wait until all TDs are deleted */ err("unlink URB timeout!"); + remove_wait_queue (&op_wakeup, &wait); } else urb_rm_priv (urb); + + urb->status = -ENOENT; // mark urb as killed + if (urb->complete) + urb->complete ((struct urb *) urb); usb_dec_dev_use (urb->dev); } return 0; @@ -611,7 +613,7 @@ static int sohci_free_dev (struct usb_device * usb_dev) spin_unlock_irqrestore (&usb_ed_lock, flags); if (cnt > 0) { - dev->wait = &wait; + add_wait_queue (&op_wakeup, &wait); current->state = TASK_UNINTERRUPTIBLE; schedule_timeout (HZ / 10); remove_wait_queue (&op_wakeup, &wait); @@ -1160,10 +1162,8 @@ static void dl_del_list (ohci_t * ohci, unsigned int frame) ed->hwINFO = cpu_to_le32 (OHCI_ED_SKIP); ed->state = ED_NEW; /* if all eds are removed wake up sohci_free_dev */ - if ((! --dev->ed_cnt) && dev->wait) { - add_wait_queue (&op_wakeup, dev->wait); + if (!--dev->ed_cnt) wake_up (&op_wakeup); - } } else { ed->state &= ~ED_URB_DEL; @@ -1283,7 +1283,7 @@ static __u8 root_hub_dev_des[] = { 0x12, /* __u8 bLength; */ 0x01, /* __u8 bDescriptorType; Device */ - 0x00, /* __u16 bcdUSB; v1.0 */ + 0x10, /* __u16 bcdUSB; v1.1 */ 0x01, 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ 0x00, /* __u8 bDeviceSubClass; */ @@ -1332,7 +1332,7 @@ static __u8 root_hub_config_des[] = 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */ + 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ 0x00, 0xff /* __u8 ep_bInterval; 255 ms */ }; @@ -1631,8 +1631,10 @@ static int rh_unlink_urb (urb_t * urb) { ohci_t * ohci = urb->dev->bus->hcpriv; - ohci->rh.send = 0; - del_timer (&ohci->rh.rh_int_timer); + if (ohci->rh.urb == urb) { + ohci->rh.send = 0; + del_timer (&ohci->rh.rh_int_timer); + } return 0; } @@ -1791,11 +1793,29 @@ static void hc_interrupt (int irq, void * __ohci, struct pt_regs * r) /*-------------------------------------------------------------------------*/ +/* reinitialize after controller reset */ + +static void hc_reinit_ohci (ohci_t *ohci) +{ + int i; + + /* for load balancing of the interrupt branches */ + for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0; + for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0; + + ohci->ed_rm_list [0] = NULL; + ohci->ed_rm_list [1] = NULL; + + /* end of control and bulk lists */ + ohci->ed_isotail = NULL; + ohci->ed_controltail = NULL; + ohci->ed_bulktail = NULL; +} + /* allocate OHCI */ static ohci_t * hc_alloc_ohci (void * mem_base) { - int i; ohci_t * ohci; struct usb_bus * bus; @@ -1808,15 +1828,6 @@ static ohci_t * hc_alloc_ohci (void * mem_base) ohci->irq = -1; ohci->regs = mem_base; - /* for load ballancing of the interrupt branches */ - for (i = 0; i < NUM_INTS; i++) ohci->ohci_int_load[i] = 0; - for (i = 0; i < NUM_INTS; i++) ohci->hcca.int_table[i] = 0; - - /* end of control and bulk lists */ - ohci->ed_isotail = NULL; - ohci->ed_controltail = NULL; - ohci->ed_bulktail = NULL; - bus = usb_alloc_bus (&sohci_device_operations); if (!bus) { free_pages ((unsigned long) ohci, 1); @@ -1829,6 +1840,7 @@ static ohci_t * hc_alloc_ohci (void * mem_base) return ohci; } + /*-------------------------------------------------------------------------*/ /* De-allocate all resources.. */ @@ -1924,21 +1936,9 @@ static int hc_start_ohci (struct pci_dev * dev) { unsigned long mem_base; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) mem_base = dev->resource[0].start; if (pci_enable_device(dev) < 0) return -ENODEV; -#else - u16 cmd; - - mem_base = dev->base_address[0]; - if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV; - mem_base &= PCI_BASE_ADDRESS_MEM_MASK; - - /* Some Mac firmware will switch memory response off */ - pci_read_config_word(dev, PCI_COMMAND, &cmd); - pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY); -#endif pci_set_master (dev); mem_base = (unsigned long) ioremap_nocache (mem_base, 4096); @@ -1998,15 +1998,47 @@ static int handle_pm_event (struct pm_dev *dev, pm_request_t rqst, void *data) if (ohci) { switch (rqst) { case PM_SUSPEND: - dbg("USB-Bus suspend: %p", ohci->regs); - if (ohci->bus->root_hub) - usb_disconnect (&ohci->bus->root_hub); - hc_reset (ohci); + /* act as if usb suspend can always be used */ + dbg("USB suspend: %p", ohci->regs); + ohci->hc_control = OHCI_USB_SUSPEND; + writel (ohci->hc_control, &ohci->regs->control); + wait_ms (10); break; + case PM_RESUME: - dbg("USB-Bus resume: %p", ohci->regs); - if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) - err ("can't restart controller, %d", temp); + /* did we suspend, or were we powered off? */ + ohci->hc_control = readl (&ohci->regs->control); + temp = ohci->hc_control & OHCI_CTRL_HCFS; + switch (temp) { + + case OHCI_USB_RESET: // lost power + dbg("USB reset: %p", ohci->regs); + ohci->disabled = 1; + if (ohci->bus->root_hub) + usb_disconnect (&ohci->bus->root_hub); + hc_reinit_ohci (ohci); + if ((temp = hc_reset (ohci)) < 0 + || (temp = hc_start (ohci)) < 0) { + ohci->disabled = 1; + err ("can't restart, %d", temp); + } + dbg ("reset done"); + break; + + case OHCI_USB_SUSPEND: // host wakeup + case OHCI_USB_RESUME: // remote wakeup + dbg("USB resume: %p", ohci->regs); + ohci->hc_control = OHCI_USB_RESUME; + writel (ohci->hc_control, &ohci->regs->control); + wait_ms (20); + + ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; + writel (ohci->hc_control, &ohci->regs->control); + break; + + default: + warn ("odd PM_RESUME"); + } break; } } |