VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / usb / host / ehci-hcd.c
index 08fb764..d3bb7b5 100644 (file)
@@ -290,16 +290,17 @@ static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
 {
        if (cap & (1 << 16)) {
                int msec = 500;
+               struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller);
 
                /* request handoff to OS */
-               cap &= 1 << 24;
-               pci_write_config_dword (to_pci_dev(ehci->hcd.self.controller), where, cap);
+               cap |= 1 << 24;
+               pci_write_config_dword(pdev, where, cap);
 
                /* and wait a while for it to happen */
                do {
                        msleep(10);
                        msec -= 10;
-                       pci_read_config_dword (to_pci_dev(ehci->hcd.self.controller), where, &cap);
+                       pci_read_config_dword(pdev, where, &cap);
                } while ((cap & (1 << 16)) && msec);
                if (cap & (1 << 16)) {
                        ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
@@ -414,7 +415,7 @@ static int ehci_start (struct usb_hcd *hcd)
        else                                    // N microframes cached
                ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
 
-       ehci->reclaim = 0;
+       ehci->reclaim = NULL;
        ehci->next_uframe = -1;
 
        /* controller state:  unknown --> reset */
@@ -424,7 +425,6 @@ static int ehci_start (struct usb_hcd *hcd)
                ehci_mem_cleanup (ehci);
                return retval;
        }
-       writel (INTR_MASK, &ehci->regs->intr_enable);
        writel (ehci->periodic_dma, &ehci->regs->frame_list);
 
 #ifdef CONFIG_PCI
@@ -462,7 +462,7 @@ static int ehci_start (struct usb_hcd *hcd)
         * its dummy is used in hw_alt_next of many tds, to prevent the qh
         * from automatically advancing to the next td after short reads.
         */
-       ehci->async->qh_next.qh = 0;
+       ehci->async->qh_next.qh = NULL;
        ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma);
        ehci->async->hw_info1 = cpu_to_le32 (QH_HEAD);
        ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT);
@@ -520,7 +520,7 @@ static int ehci_start (struct usb_hcd *hcd)
 
        /* wire up the root hub */
        bus = hcd_to_bus (hcd);
-       bus->root_hub = udev = usb_alloc_dev (NULL, bus, 0);
+       udev = usb_alloc_dev (NULL, bus, 0);
        if (!udev) {
 done2:
                ehci_mem_cleanup (ehci);
@@ -530,7 +530,8 @@ done2:
        /*
         * Start, enabling full USB 2.0 functionality ... usb 1.1 devices
         * are explicitly handed to companion controller(s), so no TT is
-        * involved with the root hub.
+        * involved with the root hub.  (Except where one is integrated,
+        * and there's no companion controller unless maybe for USB OTG.)
         */
        ehci->reboot_notifier.notifier_call = ehci_reboot;
        register_reboot_notifier (&ehci->reboot_notifier);
@@ -553,16 +554,17 @@ done2:
         * and device drivers may start it running.
         */
        udev->speed = USB_SPEED_HIGH;
-       if (hcd_register_root (hcd) != 0) {
+       if (hcd_register_root (udev, hcd) != 0) {
                if (hcd->state == USB_STATE_RUNNING)
                        ehci_ready (ehci);
                ehci_reset (ehci);
-               bus->root_hub = 0;
                usb_put_dev (udev); 
                retval = -ENODEV;
                goto done2;
        }
 
+       writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+
        create_debug_files (ehci);
 
        return 0;
@@ -573,6 +575,7 @@ done2:
 static void ehci_stop (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
+       u8                      rh_ports, port;
 
        ehci_dbg (ehci, "stop\n");
 
@@ -584,7 +587,16 @@ static void ehci_stop (struct usb_hcd *hcd)
                return;
        }
        del_timer_sync (&ehci->watchdog);
+
+       /* Turn off port power on all root hub ports. */
+       rh_ports = HCS_N_PORTS (ehci->hcs_params);
+       for (port = 1; port <= rh_ports; port++) {
+               ehci_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER,
+                       port, NULL, 0);
+       }
+
        ehci_reset (ehci);
+       writel (0, &ehci->regs->intr_enable);
 
        /* let companion controllers work when we aren't */
        writel (0, &ehci->regs->configured_flag);
@@ -635,7 +647,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
                msleep (100);
 
 #ifdef CONFIG_USB_SUSPEND
-       (void) usb_suspend_device (hcd->self.root_hub);
+       (void) usb_suspend_device (hcd->self.root_hub, state);
 #else
        /* FIXME lock root hub */
        (void) ehci_hub_suspend (hcd);
@@ -704,12 +716,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
 
        status = readl (&ehci->regs->status);
 
-       /* shared irq */
-       if (status == 0) {
-               spin_unlock (&ehci->lock);
-               return IRQ_NONE;
-       }
-
        /* e.g. cardbus physical eject */
        if (status == ~(u32) 0) {
                ehci_dbg (ehci, "device removed\n");
@@ -717,8 +723,10 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
        }
 
        status &= INTR_MASK;
-       if (!status)                    /* irq sharing? */
-               goto done;
+       if (!status) {                  /* irq sharing? */
+               spin_unlock(&ehci->lock);
+               return IRQ_NONE;
+       }
 
        /* clear (just) interrupts */
        writel (status, &ehci->regs->status);
@@ -789,7 +797,6 @@ dead:
 
        if (bh)
                ehci_work (ehci, regs);
-done:
        spin_unlock (&ehci->lock);
        return IRQ_HANDLED;
 }
@@ -978,7 +985,7 @@ idle_timeout:
                        list_empty (&qh->qtd_list) ? "" : "(has tds)");
                break;
        }
-       dev->ep [epnum] = 0;
+       dev->ep[epnum] = NULL;
 done:
        spin_unlock_irqrestore (&ehci->lock, flags);
        return;
@@ -1029,6 +1036,8 @@ static const struct hc_driver ehci_driver = {
         */
        .hub_status_data =      ehci_hub_status_data,
        .hub_control =          ehci_hub_control,
+       .hub_suspend =          ehci_hub_suspend,
+       .hub_resume =           ehci_hub_resume,
 };
 
 /*-------------------------------------------------------------------------*/