]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/usb/host/ohci-hcd.c
Merge branch 'linux-2.6'
[linux-2.6-omap-h63xx.git] / drivers / usb / host / ohci-hcd.c
index d673cb9c36b155a025b9b0aa88c0baa7f70e4d9c..ddd4ee1f2413633bccd1ae9d9309a2a7a86b9e32 100644 (file)
@@ -80,7 +80,10 @@ static const char    hcd_name [] = "ohci_hcd";
 static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
+
+#if defined(CONFIG_PM) || defined(CONFIG_PCI)
 static int ohci_restart (struct ohci_hcd *ohci);
+#endif
 
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
@@ -117,7 +120,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
  */
 static int ohci_urb_enqueue (
        struct usb_hcd  *hcd,
-       struct usb_host_endpoint *ep,
        struct urb      *urb,
        gfp_t           mem_flags
 ) {
@@ -130,11 +132,11 @@ static int ohci_urb_enqueue (
        int             retval = 0;
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "SUB", usb_pipein (pipe));
+       urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
 #endif
 
        /* every endpoint has a ed, locate and maybe (re)initialize it */
-       if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+       if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
                return -ENOMEM;
 
        /* for the private part of the URB we need the number of TDs (size) */
@@ -199,22 +201,17 @@ static int ohci_urb_enqueue (
                retval = -ENODEV;
                goto fail;
        }
-
-       /* in case of unlink-during-submit */
-       spin_lock (&urb->lock);
-       if (urb->status != -EINPROGRESS) {
-               spin_unlock (&urb->lock);
-               urb->hcpriv = urb_priv;
-               finish_urb (ohci, urb);
-               retval = 0;
+       retval = usb_hcd_link_urb_to_ep(hcd, urb);
+       if (retval)
                goto fail;
-       }
 
        /* schedule the ed if needed */
        if (ed->state == ED_IDLE) {
                retval = ed_schedule (ohci, ed);
-               if (retval < 0)
-                       goto fail0;
+               if (retval < 0) {
+                       usb_hcd_unlink_urb_from_ep(hcd, urb);
+                       goto fail;
+               }
                if (ed->type == PIPE_ISOCHRONOUS) {
                        u16     frame = ohci_frame_no(ohci);
 
@@ -238,8 +235,6 @@ static int ohci_urb_enqueue (
        urb->hcpriv = urb_priv;
        td_submit_urb (ohci, urb);
 
-fail0:
-       spin_unlock (&urb->lock);
 fail:
        if (retval)
                urb_free_priv (ohci, urb_priv);
@@ -248,22 +243,26 @@ fail:
 }
 
 /*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status.  reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
  * asynchronously, and we might be dealing with an urb that's
  * partially transferred, or an ED with other urbs being unlinked.
  */
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
        unsigned long           flags;
+       int                     rc;
 
 #ifdef OHCI_VERBOSE_DEBUG
-       urb_print (urb, "UNLINK", 1);
+       urb_print(urb, "UNLINK", 1, status);
 #endif
 
        spin_lock_irqsave (&ohci->lock, flags);
-       if (HC_IS_RUNNING(hcd->state)) {
+       rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+       if (rc) {
+               ;       /* Do nothing */
+       } else if (HC_IS_RUNNING(hcd->state)) {
                urb_priv_t  *urb_priv;
 
                /* Unless an IRQ completed the unlink while it was being
@@ -281,10 +280,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
                 * any more ... just clean up every urb's memory.
                 */
                if (urb->hcpriv)
-                       finish_urb (ohci, urb);
+                       finish_urb(ohci, urb, status);
        }
        spin_unlock_irqrestore (&ohci->lock, flags);
-       return 0;
+       return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -400,7 +399,7 @@ static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
  */
 static void unlink_watchdog_func(unsigned long _ohci)
 {
-       long            flags;
+       unsigned long   flags;
        unsigned        max;
        unsigned        seen_count = 0;
        unsigned        i;
@@ -733,24 +732,27 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
        struct ohci_regs __iomem *regs = ohci->regs;
        int                     ints;
 
-       /* we can eliminate a (slow) ohci_readl()
-        * if _only_ WDH caused this irq
+       /* Read interrupt status (and flush pending writes).  We ignore the
+        * optimization of checking the LSB of hcca->done_head; it doesn't
+        * work on all systems (edge triggering for OHCI can be a factor).
         */
-       if ((ohci->hcca->done_head != 0)
-                       && ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
-                               & 0x01)) {
-               ints =  OHCI_INTR_WDH;
+       ints = ohci_readl(ohci, &regs->intrstatus);
 
-       /* cardbus/... hardware gone before remove() */
-       } else if ((ints = ohci_readl (ohci, &regs->intrstatus)) == ~(u32)0) {
+       /* Check for an all 1's result which is a typical consequence
+        * of dead, unclocked, or unplugged (CardBus...) devices
+        */
+       if (ints == ~(u32)0) {
                disable (ohci);
                ohci_dbg (ohci, "device removed!\n");
                return IRQ_HANDLED;
+       }
+
+       /* We only care about interrupts that are enabled */
+       ints &= ohci_readl(ohci, &regs->intrenable);
 
        /* interrupt for some other device? */
-       } else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
+       if (ints == 0)
                return IRQ_NOTMINE;
-       }
 
        if (ints & OHCI_INTR_UE) {
                // e.g. due to PCI Master/Target Abort
@@ -897,6 +899,8 @@ static void ohci_stop (struct usb_hcd *hcd)
 
 /*-------------------------------------------------------------------------*/
 
+#if defined(CONFIG_PM) || defined(CONFIG_PCI)
+
 /* must not be called from interrupt context */
 static int ohci_restart (struct ohci_hcd *ohci)
 {
@@ -931,9 +935,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
                                        ed, ed->state);
                }
 
-               spin_lock (&urb->lock);
-               urb->status = -ESHUTDOWN;
-               spin_unlock (&urb->lock);
+               if (!urb->unlinked)
+                       urb->unlinked = -ESHUTDOWN;
        }
        finish_unlinks (ohci, 0);
        spin_unlock_irq(&ohci->lock);
@@ -959,6 +962,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
        return 0;
 }
 
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
@@ -992,7 +997,7 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ohci_hcd_lh7a404_driver
 #endif
 
-#ifdef CONFIG_PXA27x
+#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
 #include "ohci-pxa27x.c"
 #define PLATFORM_DRIVER                ohci_hcd_pxa27x_driver
 #endif
@@ -1038,11 +1043,17 @@ MODULE_LICENSE ("GPL");
 #define PS3_SYSTEM_BUS_DRIVER  ps3_ohci_driver
 #endif
 
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER                ssb_ohci_driver
+#endif
+
 #if    !defined(PCI_DRIVER) &&         \
        !defined(PLATFORM_DRIVER) &&    \
        !defined(OF_PLATFORM_DRIVER) && \
        !defined(SA1111_DRIVER) &&      \
-       !defined(PS3_SYSTEM_BUS_DRIVER)
+       !defined(PS3_SYSTEM_BUS_DRIVER) && \
+       !defined(SSB_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
 
@@ -1087,10 +1098,20 @@ static int __init ohci_hcd_mod_init(void)
                goto error_pci;
 #endif
 
+#ifdef SSB_OHCI_DRIVER
+       retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+       if (retval)
+               goto error_ssb;
+#endif
+
        return retval;
 
        /* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
 #ifdef PCI_DRIVER
+       pci_unregister_driver(&PCI_DRIVER);
  error_pci:
 #endif
 #ifdef SA1111_DRIVER
@@ -1115,6 +1136,9 @@ module_init(ohci_hcd_mod_init);
 
 static void __exit ohci_hcd_mod_exit(void)
 {
+#ifdef SSB_OHCI_DRIVER
+       ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
 #ifdef PCI_DRIVER
        pci_unregister_driver(&PCI_DRIVER);
 #endif