[RFC 1/2] Convert ehci-hcd to a library

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux