Felipe:

We've been talking about this for a long time.  Here at last is an
initial attempt at splitting ehci-hcd up into a library module and
multiple platform driver modules.

The first patch is just preparation.  It moves a few items between .c 
and .h files, adds a generic ehci_hc_driver structure, and exports a 
bunch of formerly private routines.

The second patch converts ehci-pci.c to a separate module, as an
example to show how the whole thing is meant to work.  The same
approach should be usable for almost all the other platform drivers
(ehci-tegra will be problematic).  I did ehci-pci first because that's 
the only one I can test.  :-)

This isn't exactly what you had in mind because it doesn't introduce 
another struct device layer.  Still, the end result is what you want -- 
we will be able to build all the EHCI platform drivers into a single 
kernel.

What do you think?

Alan Stern



Index: usb-3.6/drivers/usb/host/ehci.h
===================================================================
--- usb-3.6.orig/drivers/usb/host/ehci.h
+++ usb-3.6/drivers/usb/host/ehci.h
@@ -761,26 +761,73 @@ static inline u32 hc32_to_cpup (const st
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef CONFIG_PCI
-
-/* For working around the MosChip frame-index-register bug */
-static unsigned ehci_read_frame_index(struct ehci_hcd *ehci);
+#define ehci_dbg(ehci, fmt, args...) \
+       dev_dbg(ehci_to_hcd(ehci)->self.controller , fmt , ## args )
+#define ehci_err(ehci, fmt, args...) \
+       dev_err(ehci_to_hcd(ehci)->self.controller , fmt , ## args )
+#define ehci_info(ehci, fmt, args...) \
+       dev_info(ehci_to_hcd(ehci)->self.controller , fmt , ## args )
+#define ehci_warn(ehci, fmt, args...) \
+       dev_warn(ehci_to_hcd(ehci)->self.controller , fmt , ## args )
 
+#ifdef VERBOSE_DEBUG
+#define ehci_vdbg ehci_dbg
 #else
-
-static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
-{
-       return ehci_readl(ehci, &ehci->regs->frame_index);
-}
-
+       static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {}
 #endif
 
-/*-------------------------------------------------------------------------*/
-
 #ifndef DEBUG
 #define STUB_DEBUG_FILES
 #endif /* DEBUG */
 
 /*-------------------------------------------------------------------------*/
 
+/* Declarations of things exported for use by ehci platform drivers */
+
+extern const struct hc_driver  ehci_hc_driver;
+
+extern irqreturn_t             ehci_irq(struct usb_hcd *hcd);
+
+extern int     ehci_setup(struct usb_hcd *hcd);
+extern int     ehci_run(struct usb_hcd *hcd);
+extern void    ehci_stop(struct usb_hcd *hcd);
+extern void    ehci_shutdown(struct usb_hcd *hcd);
+
+extern int     ehci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+                               gfp_t mem_flags);
+extern int     ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+                               int status);
+extern void    ehci_endpoint_disable(struct usb_hcd *hcd,
+                               struct usb_host_endpoint *ep);
+extern void    ehci_endpoint_reset(struct usb_hcd *hcd,
+                               struct usb_host_endpoint *ep);
+
+extern int     ehci_get_frame(struct usb_hcd *hcd);
+
+extern int     ehci_hub_status_data(struct usb_hcd *hcd, char *buf);
+extern int     ehci_hub_control(struct usb_hcd *hcd, u16 typeReq,
+                               u16 wValue, u16 wIndex,
+                               char *buf, u16 wLength);
+extern void    ehci_relinquish_port(struct usb_hcd *hcd, int portnum);
+extern int     ehci_port_handed_over(struct usb_hcd *hcd, int portnum);
+extern void    ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
+                               struct usb_host_endpoint *ep);
+
+extern void    ehci_port_power(struct ehci_hcd *ehci, int is_on);
+
+#ifdef CONFIG_PM
+extern int     ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
+extern int     ehci_resume(struct usb_hcd *hcd, bool hibernated);
+extern int     ehci_bus_suspend(struct usb_hcd *hcd);
+extern int     ehci_bus_resume(struct usb_hcd *hcd);
+
+#else
+
+#define ehci_bus_suspend       NULL
+#define ehci_bus_resume                NULL
+#endif /* CONFIG_PM */
+
+extern int ehci_lpm_set_da(struct ehci_hcd *ehci, int dev_addr, int port_num);
+extern int ehci_lpm_check(struct ehci_hcd *ehci, int port);
+
 #endif /* __LINUX_EHCI_HCD_H */
Index: usb-3.6/drivers/usb/host/ehci-hcd.c
===================================================================
--- usb-3.6.orig/drivers/usb/host/ehci-hcd.c
+++ usb-3.6/drivers/usb/host/ehci-hcd.c
@@ -118,9 +118,24 @@ MODULE_PARM_DESC(hird, "host initiated r
 /*-------------------------------------------------------------------------*/
 
 #include "ehci.h"
-#include "ehci-dbg.c"
 #include "pci-quirks.h"
 
+#ifdef CONFIG_PCI
+
+/* For working around the MosChip frame-index-register bug */
+static unsigned ehci_read_frame_index(struct ehci_hcd *ehci);
+
+#else
+
+static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
+{
+       return ehci_readl(ehci, &ehci->regs->frame_index);
+}
+
+#endif
+
+#include "ehci-dbg.c"
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -338,7 +353,7 @@ static void ehci_silence_controller(stru
  * This forcibly disables dma and IRQs, helping kexec and other cases
  * where the next system software may expect clean state.
  */
-static void ehci_shutdown(struct usb_hcd *hcd)
+void ehci_shutdown(struct usb_hcd *hcd)
 {
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 
@@ -352,8 +367,9 @@ static void ehci_shutdown(struct usb_hcd
 
        hrtimer_cancel(&ehci->hrtimer);
 }
+EXPORT_SYMBOL_GPL(ehci_shutdown);
 
-static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
+void ehci_port_power(struct ehci_hcd *ehci, int is_on)
 {
        unsigned port;
 
@@ -370,6 +386,7 @@ static void ehci_port_power (struct ehci
        ehci_readl(ehci, &ehci->regs->command);
        msleep(20);
 }
+EXPORT_SYMBOL_GPL(ehci_port_power);
 
 /*-------------------------------------------------------------------------*/
 
@@ -411,7 +428,7 @@ static void ehci_work (struct ehci_hcd *
 /*
  * Called when the ehci_hcd module is removed.
  */
-static void ehci_stop (struct usb_hcd *hcd)
+void ehci_stop(struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
 
@@ -451,6 +468,7 @@ static void ehci_stop (struct usb_hcd *h
        dbg_status (ehci, "ehci_stop completed",
                    ehci_readl(ehci, &ehci->regs->status));
 }
+EXPORT_SYMBOL_GPL(ehci_stop);
 
 /* one-time init, only for memory state */
 static int ehci_init(struct usb_hcd *hcd)
@@ -575,7 +593,7 @@ static int ehci_init(struct usb_hcd *hcd
 }
 
 /* start HC running; it's halted, ehci_init() has been run (once) */
-static int ehci_run (struct usb_hcd *hcd)
+int ehci_run(struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        u32                     temp;
@@ -659,8 +677,9 @@ static int ehci_run (struct usb_hcd *hcd
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ehci_run);
 
-static int ehci_setup(struct usb_hcd *hcd)
+int ehci_setup(struct usb_hcd *hcd)
 {
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        int retval;
@@ -691,10 +710,11 @@ static int ehci_setup(struct usb_hcd *hc
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ehci_setup);
 
 /*-------------------------------------------------------------------------*/
 
-static irqreturn_t ehci_irq (struct usb_hcd *hcd)
+irqreturn_t ehci_irq(struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        u32                     status, masked_status, pcd_status = 0, cmd;
@@ -842,6 +862,7 @@ dead:
                usb_hcd_poll_rh_status(hcd);
        return IRQ_HANDLED;
 }
+EXPORT_SYMBOL_GPL(ehci_irq);
 
 /*-------------------------------------------------------------------------*/
 
@@ -857,7 +878,7 @@ dead:
  * NOTE:  control, bulk, and interrupt share the same code to append TDs
  * to a (possibly active) QH, and the same QH scanning code.
  */
-static int ehci_urb_enqueue (
+int ehci_urb_enqueue(
        struct usb_hcd  *hcd,
        struct urb      *urb,
        gfp_t           mem_flags
@@ -893,12 +914,12 @@ static int ehci_urb_enqueue (
                        return sitd_submit (ehci, urb, mem_flags);
        }
 }
+EXPORT_SYMBOL_GPL(ehci_urb_enqueue);
 
 /* remove from hardware lists
  * completions normally happen asynchronously
  */
-
-static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        struct ehci_qh          *qh;
@@ -963,13 +984,13 @@ done:
        spin_unlock_irqrestore (&ehci->lock, flags);
        return rc;
 }
+EXPORT_SYMBOL_GPL(ehci_urb_dequeue);
 
 /*-------------------------------------------------------------------------*/
 
 // bulk qh holds the data toggle
 
-static void
-ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+void ehci_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        unsigned long           flags;
@@ -1040,9 +1061,9 @@ idle_timeout:
        ep->hcpriv = NULL;
        spin_unlock_irqrestore (&ehci->lock, flags);
 }
+EXPORT_SYMBOL_GPL(ehci_endpoint_disable);
 
-static void
-ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+void ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        struct ehci_qh          *qh;
@@ -1081,12 +1102,14 @@ ehci_endpoint_reset(struct usb_hcd *hcd,
        }
        spin_unlock_irqrestore(&ehci->lock, flags);
 }
+EXPORT_SYMBOL_GPL(ehci_endpoint_reset);
 
-static int ehci_get_frame (struct usb_hcd *hcd)
+int ehci_get_frame(struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        return (ehci_read_frame_index(ehci) >> 3) % ehci->periodic_size;
 }
+EXPORT_SYMBOL_GPL(ehci_get_frame);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1096,7 +1119,7 @@ static int ehci_get_frame (struct usb_hc
 
 /* These routines handle the generic parts of controller suspend/resume */
 
-static int __maybe_unused ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
+int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
 
@@ -1119,9 +1142,10 @@ static int __maybe_unused ehci_suspend(s
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(ehci_suspend);
 
 /* Returns 0 if power was preserved, 1 if power was lost */
-static int __maybe_unused ehci_resume(struct usb_hcd *hcd, bool hibernated)
+int ehci_resume(struct usb_hcd *hcd, bool hibernated)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
 
@@ -1182,11 +1206,64 @@ static int __maybe_unused ehci_resume(st
 
        return 1;
 }
+EXPORT_SYMBOL_GPL(ehci_resume);
 
 #endif
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * Generic structure; platform drivers can copy this and override individual
+ * entries as needed.
+ */
+
+const struct hc_driver ehci_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "EHCI Host Controller",
+       .hcd_priv_size =        sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ehci_irq,
+       .flags =                HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset =                ehci_init,
+       .start =                ehci_run,
+       .stop =                 ehci_stop,
+       .shutdown =             ehci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ehci_urb_enqueue,
+       .urb_dequeue =          ehci_urb_dequeue,
+       .endpoint_disable =     ehci_endpoint_disable,
+       .endpoint_reset =       ehci_endpoint_reset,
+       .clear_tt_buffer_complete =     ehci_clear_tt_buffer_complete,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ehci_hub_status_data,
+       .hub_control =          ehci_hub_control,
+       .bus_suspend =          ehci_bus_suspend,
+       .bus_resume =           ehci_bus_resume,
+       .relinquish_port =      ehci_relinquish_port,
+       .port_handed_over =     ehci_port_handed_over,
+};
+EXPORT_SYMBOL_GPL(ehci_hc_driver);
+
+/*-------------------------------------------------------------------------*/
+
 /*
  * The EHCI in ChipIdea HDRC cannot be a separate module or device,
  * because its registers (and irq) are shared between host/gadget/otg
Index: usb-3.6/drivers/usb/host/ehci-hub.c
===================================================================
--- usb-3.6.orig/drivers/usb/host/ehci-hub.c
+++ usb-3.6/drivers/usb/host/ehci-hub.c
@@ -33,15 +33,6 @@
 
 #ifdef CONFIG_PM
 
-static int ehci_hub_control(
-       struct usb_hcd  *hcd,
-       u16             typeReq,
-       u16             wValue,
-       u16             wIndex,
-       char            *buf,
-       u16             wLength
-);
-
 /* After a power loss, ports that were owned by the companion must be
  * reset so that the companion can still own them.
  */
@@ -205,7 +196,7 @@ static void ehci_adjust_port_wakeup_flag
        spin_unlock_irq(&ehci->lock);
 }
 
-static int ehci_bus_suspend (struct usb_hcd *hcd)
+int ehci_bus_suspend(struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        int                     port;
@@ -335,10 +326,11 @@ static int ehci_bus_suspend (struct usb_
        hrtimer_cancel(&ehci->hrtimer);
        return 0;
 }
+EXPORT_SYMBOL_GPL(ehci_bus_suspend);
 
 
 /* caller has locked the root hub, and should reset/reinit on error */
-static int ehci_bus_resume (struct usb_hcd *hcd)
+int ehci_bus_resume(struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
        u32                     temp;
@@ -463,11 +455,7 @@ static int ehci_bus_resume (struct usb_h
        spin_unlock_irq(&ehci->lock);
        return -ESHUTDOWN;
 }
-
-#else
-
-#define ehci_bus_suspend       NULL
-#define ehci_bus_resume                NULL
+EXPORT_SYMBOL_GPL(ehci_bus_resume);
 
 #endif /* CONFIG_PM */
 
@@ -556,8 +544,7 @@ static int check_reset_complete (
 
 /* build "status change" packet (one or two bytes) from HC registers */
 
-static int
-ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
+int ehci_hub_status_data(struct usb_hcd *hcd, char *buf)
 {
        struct ehci_hcd *ehci = hcd_to_ehci (hcd);
        u32             temp, status;
@@ -627,6 +614,7 @@ ehci_hub_status_data (struct usb_hcd *hc
        spin_unlock_irqrestore (&ehci->lock, flags);
        return status ? retval : 0;
 }
+EXPORT_SYMBOL_GPL(ehci_hub_status_data);
 
 /*-------------------------------------------------------------------------*/
 
@@ -665,7 +653,7 @@ ehci_hub_descriptor (
 
 /*-------------------------------------------------------------------------*/
 
-static int ehci_hub_control (
+int ehci_hub_control(
        struct usb_hcd  *hcd,
        u16             typeReq,
        u16             wValue,
@@ -1087,9 +1075,9 @@ error_exit:
        spin_unlock_irqrestore (&ehci->lock, flags);
        return retval;
 }
+EXPORT_SYMBOL_GPL(ehci_hub_control);
 
-static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd,
-               int portnum)
+void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
 
@@ -1097,9 +1085,9 @@ static void __maybe_unused ehci_relinqui
                return;
        set_owner(ehci, --portnum, PORT_OWNER);
 }
+EXPORT_SYMBOL_GPL(ehci_relinquish_port);
 
-static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd,
-               int portnum)
+int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
        u32 __iomem             *reg;
@@ -1109,3 +1097,4 @@ static int __maybe_unused ehci_port_hand
        reg = &ehci->regs->port_status[portnum - 1];
        return ehci_readl(ehci, reg) & PORT_OWNER;
 }
+EXPORT_SYMBOL_GPL(ehci_port_handed_over);
Index: usb-3.6/drivers/usb/host/ehci-q.c
===================================================================
--- usb-3.6.orig/drivers/usb/host/ehci-q.c
+++ usb-3.6/drivers/usb/host/ehci-q.c
@@ -141,7 +141,7 @@ qh_refresh (struct ehci_hcd *ehci, struc
 
 static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
 
-static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
+void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
                struct usb_host_endpoint *ep)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
@@ -155,6 +155,7 @@ static void ehci_clear_tt_buffer_complet
                qh_link_async(ehci, qh);
        spin_unlock_irqrestore(&ehci->lock, flags);
 }
+EXPORT_SYMBOL_GPL(ehci_clear_tt_buffer_complete);
 
 static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh,
                struct urb *urb, u32 token)
Index: usb-3.6/drivers/usb/host/ehci-lpm.c
===================================================================
--- usb-3.6.orig/drivers/usb/host/ehci-lpm.c
+++ usb-3.6/drivers/usb/host/ehci-lpm.c
@@ -17,8 +17,7 @@
 */
 
 /* this file is part of ehci-hcd.c */
-static int __maybe_unused ehci_lpm_set_da(struct ehci_hcd *ehci,
-       int dev_addr, int port_num)
+int ehci_lpm_set_da(struct ehci_hcd *ehci, int dev_addr, int port_num)
 {
        u32 __iomem portsc;
 
@@ -33,12 +32,13 @@ static int __maybe_unused ehci_lpm_set_d
        ehci_writel(ehci, portsc, &ehci->regs->port_status[port_num-1]);
        return 0;
 }
+EXPORT_SYMBOL_GPL(ehci_lpm_set_da);
 
 /*
  * this function is used to check if the device support LPM
  * if yes, mark the PORTSC register with PORT_LPM bit
  */
-static int __maybe_unused ehci_lpm_check(struct ehci_hcd *ehci, int port)
+int ehci_lpm_check(struct ehci_hcd *ehci, int port)
 {
        u32 __iomem     *portsc ;
        u32 val32;
@@ -82,3 +82,4 @@ static int __maybe_unused ehci_lpm_check
 
        return retval;
 }
+EXPORT_SYMBOL_GPL(ehci_lpm_check);
Index: usb-3.6/drivers/usb/host/ehci-sched.c
===================================================================
--- usb-3.6.orig/drivers/usb/host/ehci-sched.c
+++ usb-3.6/drivers/usb/host/ehci-sched.c
@@ -34,8 +34,6 @@
  * pre-calculated schedule data to make appending to the queue be quick.
  */
 
-static int ehci_get_frame (struct usb_hcd *hcd);
-
 #ifdef CONFIG_PCI
 
 static unsigned ehci_read_frame_index(struct ehci_hcd *ehci)
Index: usb-3.6/drivers/usb/host/ehci-dbg.c
===================================================================
--- usb-3.6.orig/drivers/usb/host/ehci-dbg.c
+++ usb-3.6/drivers/usb/host/ehci-dbg.c
@@ -18,21 +18,6 @@
 
 /* this file is part of ehci-hcd.c */
 
-#define ehci_dbg(ehci, fmt, args...) \
-       dev_dbg (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
-#define ehci_err(ehci, fmt, args...) \
-       dev_err (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
-#define ehci_info(ehci, fmt, args...) \
-       dev_info (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
-#define ehci_warn(ehci, fmt, args...) \
-       dev_warn (ehci_to_hcd(ehci)->self.controller , fmt , ## args )
-
-#ifdef VERBOSE_DEBUG
-#      define ehci_vdbg ehci_dbg
-#else
-       static inline void ehci_vdbg(struct ehci_hcd *ehci, ...) {}
-#endif
-
 #ifdef DEBUG
 
 /* check the values in the HCSPARAMS register

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to