vserver 1.9.3
[linux-2.6.git] / drivers / usb / host / ohci-q.c
index 99b156d..1afd40f 100644 (file)
@@ -22,6 +22,7 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
                }
        }
 
+       list_del (&urb_priv->pending);
        kfree (urb_priv);
 }
 
@@ -135,7 +136,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
 
        for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
                struct ed       **prev = &ohci->periodic [i];
-               u32             *prev_p = &ohci->hcca->int_table [i];
+               __le32          *prev_p = &ohci->hcca->int_table [i];
                struct ed       *here = *prev;
 
                /* sorting each branch by period (slow before fast)
@@ -155,7 +156,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)
                                ed->hwNextED = *prev_p;
                        wmb ();
                        *prev = ed;
-                       *prev_p = cpu_to_le32p (&ed->dma);
+                       *prev_p = cpu_to_le32(ed->dma);
                        wmb();
                }
                ohci->load [i] += ed->load;
@@ -169,9 +170,12 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
 {       
        int     branch;
 
+       if (ohci->hcd.state == USB_STATE_QUIESCING)
+               return -EAGAIN;
+
        ed->state = ED_OPER;
-       ed->ed_prev = 0;
-       ed->ed_next = 0;
+       ed->ed_prev = NULL;
+       ed->ed_next = NULL;
        ed->hwNextED = 0;
        wmb ();
 
@@ -253,7 +257,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)
        for (i = ed->branch; i < NUM_INTS; i += ed->interval) {
                struct ed       *temp;
                struct ed       **prev = &ohci->periodic [i];
-               u32             *prev_p = &ohci->hcca->int_table [i];
+               __le32          *prev_p = &ohci->hcca->int_table [i];
 
                while (*prev && (temp = *prev) != ed) {
                        prev_p = &temp->hwNextED;
@@ -317,7 +321,7 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
                        if (!ed->hwNextED) {
                                ohci->hc_control &= ~OHCI_CTRL_CLE;
                                writel (ohci->hc_control, &ohci->regs->control);
-                               // a readl() later syncs CLE with the HC
+                               // a ohci_readl() later syncs CLE with the HC
                        } else
                                writel (le32_to_cpup (&ed->hwNextED),
                                        &ohci->regs->ed_controlhead);
@@ -329,7 +333,7 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
                if (ohci->ed_controltail == ed) {
                        ohci->ed_controltail = ed->ed_prev;
                        if (ohci->ed_controltail)
-                               ohci->ed_controltail->ed_next = 0;
+                               ohci->ed_controltail->ed_next = NULL;
                } else if (ed->ed_next) {
                        ed->ed_next->ed_prev = ed->ed_prev;
                }
@@ -341,7 +345,7 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
                        if (!ed->hwNextED) {
                                ohci->hc_control &= ~OHCI_CTRL_BLE;
                                writel (ohci->hc_control, &ohci->regs->control);
-                               // a readl() later syncs BLE with the HC
+                               // a ohci_readl() later syncs BLE with the HC
                        } else
                                writel (le32_to_cpup (&ed->hwNextED),
                                        &ohci->regs->ed_bulkhead);
@@ -353,7 +357,7 @@ static void ed_deschedule (struct ohci_hcd *ohci, struct ed *ed)
                if (ohci->ed_bulktail == ed) {
                        ohci->ed_bulktail = ed->ed_prev;
                        if (ohci->ed_bulktail)
-                               ohci->ed_bulktail->ed_next = 0;
+                               ohci->ed_bulktail->ed_next = NULL;
                } else if (ed->ed_next) {
                        ed->ed_next->ed_prev = ed->ed_prev;
                }
@@ -408,7 +412,7 @@ static struct ed *ed_get (
                if (!td) {
                        /* out of memory */
                        ed_free (ohci, ed);
-                       ed = 0;
+                       ed = NULL;
                        goto done;
                }
                ed->dummy = td;
@@ -419,24 +423,25 @@ static struct ed *ed_get (
        }
 
        /* NOTE: only ep0 currently needs this "re"init logic, during
-        * enumeration (after set_address, or if ep0 maxpacket >8).
+        * enumeration (after set_address).
         */
        if (ed->state == ED_IDLE) {
                u32     info;
+               __le32  hw_info;
 
                info = usb_pipedevice (pipe);
                info |= (ep >> 1) << 7;
                info |= usb_maxpacket (udev, pipe, is_out) << 16;
-               info = cpu_to_le32 (info);
+               hw_info = cpu_to_le32 (info);
                if (udev->speed == USB_SPEED_LOW)
-                       info |= ED_LOWSPEED;
+                       hw_info |= ED_LOWSPEED;
                /* only control transfers store pids in tds */
                if (type != PIPE_CONTROL) {
-                       info |= is_out ? ED_OUT : ED_IN;
+                       hw_info |= is_out ? ED_OUT : ED_IN;
                        if (type != PIPE_BULK) {
                                /* periodic transfers... */
                                if (type == PIPE_ISOCHRONOUS)
-                                       info |= ED_ISO;
+                                       hw_info |= ED_ISO;
                                else if (interval > 32) /* iso can be bigger */
                                        interval = 32;
                                ed->interval = interval;
@@ -447,7 +452,7 @@ static struct ed *ed_get (
                                                / 1000;
                        }
                }
-               ed->hwINFO = info;
+               ed->hwINFO = hw_info;
        }
 
 done:
@@ -470,14 +475,14 @@ static void start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed)
 
        /* rm_list is just singly linked, for simplicity */
        ed->ed_next = ohci->ed_rm_list;
-       ed->ed_prev = 0;
+       ed->ed_prev = NULL;
        ohci->ed_rm_list = ed;
 
        /* enable SOF interrupt */
        writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
        writel (OHCI_INTR_SF, &ohci->regs->intrenable);
        // flush those writes, and get latest HCCA contents
-       (void) readl (&ohci->regs->control);
+       (void) ohci_readl (&ohci->regs->control);
 
        /* SF interrupt might get delayed; record the frame counter value that
         * indicates when the HC isn't looking at it, so concurrent unlinks
@@ -593,6 +598,7 @@ static void td_submit_urb (
        }
 
        urb_priv->td_cnt = 0;
+       list_add (&urb_priv->pending, &ohci->pending);
 
        if (data_len)
                data = urb->transfer_dma;
@@ -746,12 +752,6 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 
                cc = TD_CC_GET (tdINFO);
 
-               /* control endpoints only have soft stalls */
-               if (type != PIPE_CONTROL && cc == TD_CC_STALL)
-                       usb_endpoint_halt (urb->dev,
-                               usb_pipeendpoint (urb->pipe),
-                               usb_pipeout (urb->pipe));
-
                /* update packet status if needed (short is normally ok) */
                if (cc == TD_DATAUNDERRUN
                                && !(urb->transfer_flags & URB_SHORT_NOT_OK))
@@ -790,7 +790,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
        struct urb              *urb = td->urb;
        struct ed               *ed = td->ed;
        struct list_head        *tmp = td->td_list.next;
-       u32                     toggle = ed->hwHeadP & ED_C;
+       __le32                  toggle = ed->hwHeadP & ED_C;
 
        /* clear ed halt; this is the td that caused it, but keep it inactive
         * until its urb->complete() has a chance to clean up.
@@ -805,7 +805,7 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
         */
        while (tmp != &ed->td_list) {
                struct td       *next;
-               u32             info;
+               __le32          info;
 
                next = list_entry (tmp, struct td, td_list);
                tmp = next->td_list.next;
@@ -865,9 +865,6 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
        u32             td_dma;
        struct td       *td_rev = NULL;
        struct td       *td = NULL;
-       unsigned long   flags;
-
-       spin_lock_irqsave (&ohci->lock, flags);
 
        td_dma = le32_to_cpup (&ohci->hcca->done_head);
        ohci->hcca->done_head = 0;
@@ -899,15 +896,11 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
                td_rev = td;
                td_dma = le32_to_cpup (&td->hwNextTD);
        }       
-       spin_unlock_irqrestore (&ohci->lock, flags);
        return td_rev;
 }
 
 /*-------------------------------------------------------------------------*/
 
-/* wrap-aware logic stolen from <linux/jiffies.h> */
-#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)
-
 /* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
 static void
 finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
@@ -918,12 +911,12 @@ rescan_all:
        for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) {
                struct list_head        *entry, *tmp;
                int                     completed, modified;
-               u32                     *prev;
+               __le32                  *prev;
 
                /* only take off EDs that the HC isn't using, accounting for
                 * frame counter wraps and EDs with partially retired TDs
                 */
-               if (likely (HCD_IS_RUNNING(ohci->hcd.state))) {
+               if (likely (regs && HCD_IS_RUNNING(ohci->hcd.state))) {
                        if (tick_before (tick, ed->tick)) {
 skip_ed:
                                last = &ed->ed_next;
@@ -936,7 +929,7 @@ skip_ed:
 
                                td = list_entry (ed->td_list.next, struct td,
                                                        td_list);
-                               head = cpu_to_le32 (ed->hwHeadP) & TD_MASK;
+                               head = le32_to_cpu (ed->hwHeadP) & TD_MASK;
 
                                /* INTR_WDH may need to clean up first */
                                if (td->td_dma != head)
@@ -949,7 +942,7 @@ skip_ed:
                 * entries (which we'd ignore), but paranoia won't hurt.
                 */
                *last = ed->ed_next;
-               ed->ed_next = 0;
+               ed->ed_next = NULL;
                modified = 0;
 
                /* unlink urbs as requested, but rescan the list after
@@ -967,7 +960,7 @@ rescan_this:
                        struct td       *td;
                        struct urb      *urb;
                        urb_priv_t      *urb_priv;
-                       u32             savebits;
+                       __le32          savebits;
 
                        td = list_entry (entry, struct td, td_list);
                        urb = td->urb;
@@ -1013,7 +1006,9 @@ rescan_this:
        }
 
        /* maybe reenable control and bulk lists */ 
-       if (HCD_IS_RUNNING(ohci->hcd.state) && !ohci->ed_rm_list) {
+       if (HCD_IS_RUNNING(ohci->hcd.state)
+                       && ohci->hcd.state != USB_STATE_QUIESCING
+                       && !ohci->ed_rm_list) {
                u32     command = 0, control = 0;
 
                if (ohci->ed_controltail) {
@@ -1053,11 +1048,10 @@ rescan_this:
  * scanning the (re-reversed) donelist as this does.
  */
 static void
-dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs)
+dl_done_list (struct ohci_hcd *ohci, struct pt_regs *regs)
 {
-       unsigned long   flags;
+       struct td       *td = dl_reverse_done_list (ohci);
 
-       spin_lock_irqsave (&ohci->lock, flags);
        while (td) {
                struct td       *td_next = td->next_dl_td;
                struct urb      *urb = td->urb;
@@ -1098,5 +1092,4 @@ dl_done_list (struct ohci_hcd *ohci, struct td *td, struct pt_regs *regs)
 
                td = td_next;
        }  
-       spin_unlock_irqrestore (&ohci->lock, flags);
 }