This patch allows attaching both ohci and ehci drivers. 
Currently, either driver can be loaded individually.
But if both were loaded, only the first one is probed
and attached.

It is useful to build only a single driver.
If only low speed devices are to be supported,
only the ohci driver is needed.

If only high speed devices are needed or a transaction 
translating hub that converts low speed devices to high 
speed, only the ehci driver is required.

Signed-off-by: Steve Brown <sbr...@cortland.com>
CC: Hauke Mehrtens <ha...@hauke-m.de>
---

Hauke, thanks for packaging all this for upstream.
I'm not sure how to do this without 100 ifdef's.

There are issues with both the ohci and ehci drivers that, I believe, are 
unrelated
to the ssb code.
 
The ohci driver fails w/ a UE (bus error) doing a stress test on a Prolific 
serial
dongle. There are some recent patches to the serial usb code. I'll see if they 
make 
any difference.

The ehci driver fails clearing the tt buffer on the SMC USB2503 hub chip in the 
wl500v2.
I can't reproduce this with any other tt hub. I found a stand-alone USB2503 hub 
and it fails
in the same way. Again, there are some recent patches that I will test. This 
affects only
low speed devices.

--- linux-2.6.34.1/drivers/usb/host/ohci-ssb.c.orig     2010-08-12 
05:26:09.813110624 -0400
+++ linux-2.6.34.1/drivers/usb/host/ohci-ssb.c  2010-08-12 06:31:14.791991233 
-0400
@@ -17,6 +17,8 @@
  */
 #include <linux/ssb/ssb.h>
 
+extern int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **hcd);
+extern void ssb_ehci_detach(struct ssb_device *dev, struct usb_hcd *hcd);
 
 #define SSB_OHCI_TMSLOW_HOSTMODE       (1 << 29)
 
@@ -24,6 +26,9 @@
        struct ohci_hcd ohci; /* _must_ be at the beginning. */
 
        u32 enable_flags;
+#ifdef CONFIG_USB_EHCI_HCD_SSB
+       struct usb_hcd *ehci_hcd;
+#endif
 };
 
 static inline
@@ -92,6 +97,9 @@
 static void ssb_ohci_detach(struct ssb_device *dev)
 {
        struct usb_hcd *hcd = ssb_get_drvdata(dev);
+#ifdef CONFIG_USB_EHCI_HCD_SSB
+       struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+#endif
 
        if (hcd->driver->shutdown)
                hcd->driver->shutdown(hcd);
@@ -99,6 +107,14 @@
        iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
+
+#ifdef CONFIG_USB_EHCI_HCD_SSB
+       /*
+        * Also detach ehci function
+        */
+       if (dev->id.coreid == SSB_DEV_USB20_HOST)
+               ssb_ehci_detach(dev, ohcidev->ehci_hcd);
+#endif
        ssb_device_disable(dev, 0);
 }
 
@@ -121,6 +137,9 @@
                /*
                 * USB 2.0 special considerations:
                 *
+                * Since the core supports both OHCI and EHCI functions, it must
+                * only be reset once.
+                *
                 * In addition to the standard SSB reset sequence, the Host
                 * Control Register must be programmed to bring the USB core
                 * and various phy components out of reset.
@@ -175,6 +194,15 @@
 
        ssb_set_drvdata(dev, hcd);
 
+#ifdef CONFIG_USB_EHCI_HCD_SSB
+       /*
+        *  attach ehci function in this core
+        */
+       if (dev->id.coreid == SSB_DEV_USB20_HOST)
+               err = ssb_ehci_attach(dev, &(ohcidev->ehci_hcd));
+#endif
+
+
        return err;
 
 err_iounmap:

--- linux-2.6.34.1/drivers/usb/host/ehci-ssb.c.orig     2010-08-12 
05:26:01.394985679 -0400
+++ linux-2.6.34.1/drivers/usb/host/ehci-ssb.c  2010-08-12 06:40:53.900991452 
-0400
@@ -106,10 +106,17 @@
        iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
+#ifndef CONFIG_USB_OHCI_HCD_SSB
        ssb_device_disable(dev, 0);
+#endif
 }
+EXPORT_SYMBOL_GPL(ssb_ehci_detach);
 
+#ifndef CONFIG_USB_OHCI_HCD_SSB
 static int ssb_ehci_attach(struct ssb_device *dev)
+#else
+static int ssb_ehci_attach(struct ssb_device *dev, struct usb_hcd **ehci_hcd)
+#endif
 {
        struct ssb_ehci_device *ehcidev;
        struct usb_hcd *hcd;
@@ -120,6 +127,7 @@
            dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
                return -EOPNOTSUPP;
 
+#ifndef CONFIG_USB_OHCI_HCD_SSB
        /*
         * USB 2.0 special considerations:
         *
@@ -155,6 +163,7 @@
                tmp |= 0x1;
                ssb_write32(dev, 0x89c, tmp);
        }
+#endif
 
        hcd = usb_create_hcd(&ssb_ehci_hc_driver, dev->dev,
                             dev_name(dev->dev));
@@ -175,7 +184,11 @@
        if (err)
                goto err_iounmap;
 
+#ifndef CONFIG_USB_OHCI_HCD_SSB
        ssb_set_drvdata(dev, hcd);
+#else
+       *ehci_hcd = hcd;
+#endif
 
        return err;
 
@@ -187,7 +200,9 @@
        ssb_device_disable(dev, 0);
        return err;
 }
+EXPORT_SYMBOL_GPL(ssb_ehci_attach);
 
+#ifndef CONFIG_USB_OHCI_HCD_SSB
 static int ssb_ehci_probe(struct ssb_device *dev,
                const struct ssb_device_id *id)
 {
@@ -238,6 +253,7 @@
 #define ssb_ehci_suspend       NULL
 #define ssb_ehci_resume        NULL
 #endif /* CONFIG_PM */
+#endif /* !CONFIG_USB_OHCI_HCD_SSB */
 
 static const struct ssb_device_id ssb_ehci_table[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
@@ -245,6 +261,8 @@
 };
 MODULE_DEVICE_TABLE(ssb, ssb_ehci_table);
 
+
+#ifndef CONFIG_USB_OHCI_HCD_SSB
 static struct ssb_driver ssb_ehci_driver = {
        .name           = KBUILD_MODNAME,
        .id_table       = ssb_ehci_table,
@@ -253,3 +271,4 @@
        .suspend        = ssb_ehci_suspend,
        .resume         = ssb_ehci_resume,
 };
+#endif

--- linux-2.6.34.1/drivers/usb/host/ehci-hcd.c.orig     2010-08-12 
07:27:38.018110911 -0400
+++ linux-2.6.34.1/drivers/usb/host/ehci-hcd.c  2010-08-12 07:32:31.676991207 
-0400
@@ -1221,17 +1221,21 @@
                goto clean3;
 #endif
 
+#ifndef CONFIG_USB_OHCI_HCD_SSB
 #ifdef SSB_EHCI_DRIVER
        retval = ssb_driver_register(&SSB_EHCI_DRIVER);
        if (retval < 0)
                goto clean4;
 #endif
+#endif /* !CONFIG_USB_OHCI_HCD_SSB */
        return retval;
 
+#ifndef CONFIG_USB_OHCI_HCD_SSB
 #ifdef SSB_EHCI_DRIVER
        /* ssb_driver_unregister(&SSB_EHCI_DRIVER); */
 clean4:
 #endif
+#endif /* !CONFIG_USB_OHCI_HCD_SSB */
 #ifdef OF_PLATFORM_DRIVER
        of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
 clean3:
@@ -1260,9 +1264,11 @@
 
 static void __exit ehci_hcd_cleanup(void)
 {
+#ifndef CONFIG_USB_OHCI_HCD_SSB
 #ifdef SSB_EHCI_DRIVER
        ssb_driver_unregister(&SSB_EHCI_DRIVER);
 #endif
+#endif /* !CONFIG_USB_OHCI_HCD_SSB */
 #ifdef OF_PLATFORM_DRIVER
        of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
 #endif








_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to