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