summaryrefslogtreecommitdiffstats
path: root/drivers/usb/usb-ohci.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-05-12 21:05:59 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-05-12 21:05:59 +0000
commitba2dacab305c598cd4c34a604f8e276bf5bab5ff (patch)
tree78670a0139bf4d5ace617b29b7eba82bbc74d602 /drivers/usb/usb-ohci.c
parentb77bf69998121e689c5e86cc5630d39a0a9ee6ca (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.c136
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;
}
}