vserver 1.9.3
[linux-2.6.git] / drivers / usb / host / uhci-hcd.c
index afe0320..20a42f9 100644 (file)
@@ -82,7 +82,7 @@ static int debug = 1;
 #else
 static int debug = 0;
 #endif
-MODULE_PARM(debug, "i");
+module_param(debug, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug level");
 static char *errbuf;
 #define ERRBUF_LEN    (32 * 1024)
@@ -103,8 +103,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
 static void hc_state_transitions(struct uhci_hcd *uhci);
 
 /* If a transfer is still active after this much time, turn off FSBR */
-#define IDLE_TIMEOUT   (HZ / 20)       /* 50 ms */
-#define FSBR_DELAY     (HZ / 20)       /* 50 ms */
+#define IDLE_TIMEOUT   msecs_to_jiffies(50)
+#define FSBR_DELAY     msecs_to_jiffies(50)
 
 /* When we timeout an idle transfer for FSBR, we'll switch it over to */
 /* depth first traversal. We'll do it in groups of this number of TD's */
@@ -232,7 +232,7 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
 /*
  * Inserts a td into qh list at the top.
  */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, u32 breadth)
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, __le32 breadth)
 {
        struct list_head *tmp, *head;
        struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
@@ -376,7 +376,7 @@ static void uhci_insert_qh(struct uhci_hcd *uhci, struct uhci_qh *skelqh, struct
 static void uhci_remove_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 {
        struct uhci_qh *pqh;
-       u32 newlink;
+       __le32 newlink;
        unsigned int age;
 
        if (!qh)
@@ -862,7 +862,7 @@ static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb)
        urbp->short_control_packet = 1;
 
        td = list_entry(urbp->td_list.prev, struct uhci_td, list);
-       urbp->qh->element = td->dma_handle;
+       urbp->qh->element = cpu_to_le32(td->dma_handle);
 
        return -EINPROGRESS;
 }
@@ -1120,10 +1120,6 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
 
 td_error:
        ret = uhci_map_status(status, uhci_packetout(td_token(td)));
-       if (ret == -EPIPE)
-               /* endpoint has stalled - mark it halted */
-               usb_endpoint_halt(urb->dev, uhci_endpoint(td_token(td)),
-                               uhci_packetout(td_token(td)));
 
 err:
        /* 
@@ -1344,7 +1340,7 @@ static struct urb *uhci_find_urb_ep(struct uhci_hcd *uhci, struct urb *urb)
 
 static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
 {
-       int ret = -EINVAL;
+       int ret;
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        unsigned long flags;
        struct urb *eurb;
@@ -1352,7 +1348,8 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, int mem_flags)
 
        spin_lock_irqsave(&uhci->schedule_lock, flags);
 
-       if (urb->status != -EINPROGRESS)        /* URB already unlinked! */
+       ret = urb->status;
+       if (ret != -EINPROGRESS)                /* URB already unlinked! */
                goto out;
 
        eurb = uhci_find_urb_ep(uhci, urb);
@@ -1611,6 +1608,7 @@ static void stall_callback(unsigned long ptr)
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
        struct list_head list, *tmp, *head;
        unsigned long flags;
+       int called_uhci_finish_completion = 0;
 
        INIT_LIST_HEAD(&list);
 
@@ -1619,6 +1617,7 @@ static void stall_callback(unsigned long ptr)
            uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
                uhci_remove_pending_urbps(uhci);
                uhci_finish_completion(hcd, NULL);
+               called_uhci_finish_completion = 1;
        }
 
        head = &uhci->urb_list;
@@ -1635,17 +1634,14 @@ static void stall_callback(unsigned long ptr)
                if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
                        uhci_fsbr_timeout(uhci, u);
 
-               /* Check if the URB timed out */
-               if (u->timeout && u->status == -EINPROGRESS &&
-                       time_after_eq(jiffies, up->inserttime + u->timeout)) {
-                       u->status = -ETIMEDOUT;
-                       list_move_tail(&up->urb_list, &list);
-               }
-
                spin_unlock(&u->lock);
        }
        spin_unlock_irqrestore(&uhci->schedule_lock, flags);
 
+       /* Wake up anyone waiting for an URB to complete */
+       if (called_uhci_finish_completion)
+               wake_up_all(&uhci->waitqh);
+
        head = &list;
        tmp = head->next;
        while (tmp != head) {
@@ -1676,7 +1672,7 @@ static int init_stall_timer(struct usb_hcd *hcd)
        init_timer(&uhci->stall_timer);
        uhci->stall_timer.function = stall_callback;
        uhci->stall_timer.data = (unsigned long)hcd;
-       uhci->stall_timer.expires = jiffies + (HZ / 10);
+       uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100);
        add_timer(&uhci->stall_timer);
 
        return 0;
@@ -1756,7 +1752,7 @@ static void uhci_remove_pending_urbps(struct uhci_hcd *uhci)
 static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 {
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-       unsigned int io_addr = uhci->io_addr;
+       unsigned long io_addr = uhci->io_addr;
        unsigned short status;
        struct list_head *tmp, *head;
        unsigned int age;
@@ -1829,24 +1825,28 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 
 static void reset_hc(struct uhci_hcd *uhci)
 {
-       unsigned int io_addr = uhci->io_addr;
+       unsigned long io_addr = uhci->io_addr;
+
+       /* Turn off PIRQ, SMI, and all interrupts.  This also turns off
+        * the BIOS's USB Legacy Support.
+        */
+       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
+       outw(0, uhci->io_addr + USBINTR);
 
        /* Global reset for 50ms */
        uhci->state = UHCI_RESET;
        outw(USBCMD_GRESET, io_addr + USBCMD);
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout((HZ*50+999) / 1000);
+       msleep(50);
        outw(0, io_addr + USBCMD);
 
        /* Another 10ms delay */
-       set_current_state(TASK_UNINTERRUPTIBLE);
-       schedule_timeout((HZ*10+999) / 1000);
+       msleep(10);
        uhci->resume_detect = 0;
 }
 
 static void suspend_hc(struct uhci_hcd *uhci)
 {
-       unsigned int io_addr = uhci->io_addr;
+       unsigned long io_addr = uhci->io_addr;
 
        dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
        uhci->state = UHCI_SUSPENDED;
@@ -1856,7 +1856,7 @@ static void suspend_hc(struct uhci_hcd *uhci)
 
 static void wakeup_hc(struct uhci_hcd *uhci)
 {
-       unsigned int io_addr = uhci->io_addr;
+       unsigned long io_addr = uhci->io_addr;
 
        switch (uhci->state) {
                case UHCI_SUSPENDED:            /* Start the resume */
@@ -1865,7 +1865,7 @@ static void wakeup_hc(struct uhci_hcd *uhci)
                        /* Global resume for >= 20ms */
                        outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
                        uhci->state = UHCI_RESUMING_1;
-                       uhci->state_end = jiffies + (20*HZ+999) / 1000;
+                       uhci->state_end = jiffies + msecs_to_jiffies(20);
                        break;
 
                case UHCI_RESUMING_1:           /* End global resume */
@@ -1896,7 +1896,7 @@ static void wakeup_hc(struct uhci_hcd *uhci)
 
 static int ports_active(struct uhci_hcd *uhci)
 {
-       unsigned int io_addr = uhci->io_addr;
+       unsigned long io_addr = uhci->io_addr;
        int connection = 0;
        int i;
 
@@ -1908,7 +1908,7 @@ static int ports_active(struct uhci_hcd *uhci)
 
 static int suspend_allowed(struct uhci_hcd *uhci)
 {
-       unsigned int io_addr = uhci->io_addr;
+       unsigned long io_addr = uhci->io_addr;
        int i;
 
        if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL)
@@ -1973,7 +1973,7 @@ static void hc_state_transitions(struct uhci_hcd *uhci)
 
 static void start_hc(struct uhci_hcd *uhci)
 {
-       unsigned int io_addr = uhci->io_addr;
+       unsigned long io_addr = uhci->io_addr;
        int timeout = 1000;
 
        /*
@@ -1990,7 +1990,9 @@ static void start_hc(struct uhci_hcd *uhci)
                }
        }
 
-       /* Turn on all interrupts */
+       /* Turn on PIRQ and all interrupts */
+       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+                       USBLEGSUP_DEFAULT);
        outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
                io_addr + USBINTR);
 
@@ -2054,15 +2056,10 @@ static int uhci_reset(struct usb_hcd *hcd)
 
        uhci->io_addr = (unsigned long) hcd->regs;
 
-       /* Turn off all interrupts */
-       outw(0, uhci->io_addr + USBINTR);
-
-       /* Maybe kick BIOS off this hardware.  Then reset, so we won't get
+       /* Kick BIOS off this hardware and reset, so we won't get
         * interrupts from any previous setup.
         */
        reset_hc(uhci);
-       pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-                       USBLEGSUP_DEFAULT);
        return 0;
 }
 
@@ -2178,7 +2175,7 @@ static int uhci_start(struct usb_hcd *hcd)
 
        uhci->rh_numports = port;
 
-       hcd->self.root_hub = udev = usb_alloc_dev(NULL, &hcd->self, 0);
+       udev = usb_alloc_dev(NULL, &hcd->self, 0);
        if (!udev) {
                dev_err(uhci_dev(uhci), "unable to allocate root hub\n");
                goto err_alloc_root_hub;
@@ -2251,16 +2248,22 @@ static int uhci_start(struct usb_hcd *hcd)
                        irq = 7;
 
                /* Only place we don't use the frame list routines */
-               uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+               uhci->fl->frame[i] = UHCI_PTR_QH |
+                               cpu_to_le32(uhci->skelqh[irq]->dma_handle);
        }
 
+       /*
+        * Some architectures require a full mb() to enforce completion of
+        * the memory writes above before the I/O transfers in start_hc().
+        */
+       mb();
        start_hc(uhci);
 
        init_stall_timer(hcd);
 
        udev->speed = USB_SPEED_FULL;
 
-       if (usb_register_root_hub(udev, uhci_dev(uhci)) != 0) {
+       if (hcd_register_root(udev, &uhci->hcd) != 0) {
                dev_err(uhci_dev(uhci), "unable to start root hub\n");
                retval = -ENOMEM;
                goto err_start_root_hub;
@@ -2288,7 +2291,6 @@ err_alloc_skelqh:
 
 err_alloc_term_td:
        usb_put_dev(udev);
-       hcd->self.root_hub = NULL;
 
 err_alloc_root_hub:
        dma_pool_destroy(uhci->qh_pool);
@@ -2369,14 +2371,18 @@ static int uhci_resume(struct usb_hcd *hcd)
                /*
                 * Some systems don't maintain the UHCI register values
                 * during a PM suspend/resume cycle, so reinitialize
-                * the Frame Number, the Framelist Base Address, and the
-                * Interrupt Enable registers.
+                * the Frame Number, Framelist Base Address, Interrupt
+                * Enable, and Legacy Support registers.
                 */
+               pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+                               0);
                outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);
                outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
                outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
                                USBINTR_SP, uhci->io_addr + USBINTR);
                uhci->resume_detect = 1;
+               pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+                               USBLEGSUP_DEFAULT);
        } else {
                reset_hc(uhci);
                start_hc(uhci);
@@ -2518,7 +2524,7 @@ static int __init uhci_hcd_init(void)
        }
 
 #ifdef CONFIG_PROC_FS
-       uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, 0);
+       uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, NULL);
        if (!uhci_proc_root)
                goto proc_failed;
 #endif
@@ -2541,7 +2547,7 @@ init_failed:
 up_failed:
 
 #ifdef CONFIG_PROC_FS
-       remove_proc_entry("driver/uhci", 0);
+       remove_proc_entry("driver/uhci", NULL);
 
 proc_failed:
 #endif
@@ -2561,7 +2567,7 @@ static void __exit uhci_hcd_cleanup(void)
                warn("not all urb_priv's were freed!");
 
 #ifdef CONFIG_PROC_FS
-       remove_proc_entry("driver/uhci", 0);
+       remove_proc_entry("driver/uhci", NULL);
 #endif
 
        if (errbuf)