xHCI驱动学习(0) 模块启动

最近在学习Linux内核中USB相关内容的实现,读完了fudan_abc大神师兄的《USB那些事儿之我是USB Core》,感觉荡气回肠,因为大神不仅教给我们代码的奥义,也教给我们读代码的奥义。于是接下来尝试用学到的“鱼”和“渔”,从USB Core“启下”,自己学习xHCI驱动的代码。

xHCI是USB 3.x的host controller规范,首先进入drivers/usb/host目录浏览一下,其实从文件名就可以知道,跟xHCI关系最密切的必然是xhci.c。保险起见还是看一下KConfig:

config USB_XHCI_HCD
	tristate "xHCI HCD (USB 3.0) support"
	---help---
	  The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
	  "SuperSpeed" host controller hardware.

	  To compile this driver as a module, choose M here: the
	  module will be called xhci-hcd.

if USB_XHCI_HCD

config USB_XHCI_PCI
       tristate
       depends on PCI
       default y

config USB_XHCI_PLATFORM
	tristate

config USB_XHCI_MVEBU
	tristate "xHCI support for Marvell Armada 375/38x"
	select USB_XHCI_PLATFORM
	depends on ARCH_MVEBU || COMPILE_TEST
	---help---
	  Say 'Y' to enable the support for the xHCI host controller
	  found in Marvell Armada 375/38x ARM SOCs.

config USB_XHCI_RCAR
	tristate "xHCI support for Renesas R-Car SoCs"
	select USB_XHCI_PLATFORM
	depends on ARCH_SHMOBILE || COMPILE_TEST
	---help---
	  Say 'Y' to enable the support for the xHCI host controller
	  found in Renesas R-Car ARM SoCs.

endif # USB_XHCI_HCD

主要配置项叫做USB_XHCI_HCD,另外还有USB_XHCI_PCI和USB_XHCI_PLATFORM。再看Makefile,直接搜索XHCI有关的内容:

xhci-hcd-y := xhci.o xhci-mem.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
xhci-hcd-y += xhci-trace.o

xhci-plat-hcd-y := xhci-plat.o
ifneq ($(CONFIG_USB_XHCI_MVEBU), )
	xhci-plat-hcd-y		+= xhci-mvebu.o
endif
ifneq ($(CONFIG_USB_XHCI_RCAR), )
	xhci-plat-hcd-y		+= xhci-rcar.o
endif

obj-$(CONFIG_USB_XHCI_PCI)	+= xhci-pci.o
obj-$(CONFIG_USB_XHCI_PLATFORM) += xhci-plat-hcd.o

obj-$(CONFIG_USB_XHCI_HCD)	+= xhci-hcd.o

果然,CONFIG_USB_XHCI_HCD需要xhci.o,另外还有一堆xhci-xxx.o。先打开xhci.c,这个文件有5033行(Linux 4.1)。直接搜索module_init找到模块入口,发现是定义在文件末尾的xhci_hcd_init函数:

static int __init xhci_hcd_init(void)
{
	/*
	 * Check the compiler generated sizes of structures that must be laid
	 * out in specific ways for hardware access.
	 */
	BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
	BUILD_BUG_ON(sizeof(struct xhci_slot_ctx) != 8*32/8);
	BUILD_BUG_ON(sizeof(struct xhci_ep_ctx) != 8*32/8);
	/* xhci_device_control has eight fields, and also
	 * embeds one xhci_slot_ctx and 31 xhci_ep_ctx
	 */
	BUILD_BUG_ON(sizeof(struct xhci_stream_ctx) != 4*32/8);
	BUILD_BUG_ON(sizeof(union xhci_trb) != 4*32/8);
	BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8);
	BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 7*32/8);
	BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8);
	/* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */
	BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
	return 0;
}

/*
 * If an init function is provided, an exit function must also be provided
 * to allow module unload.
 */
static void __exit xhci_hcd_fini(void) { }

module_init(xhci_hcd_init);
module_exit(xhci_hcd_fini);

xhci_hcd_init和xhci_hcd_fini这两个函数有点坑爹,居然什么实质性的事情都没有做!看来要对另外两个模块下手。

USB_XHCI_PCI,顾名思义,是xHCI驱动和PCI总线驱动之间的“接口”(内核开发者称这种“接口”为glue,有没有感觉黏黏的:D)。USB控制器大多是PCI设备,若控制器连接到PCI总线上,那么自然是先由PCI驱动发现该设备,识别之后才能交给xHCI驱动处理。所以实际上,作为glue的xhci-pci模块代码要早于xhci-hcd模块代码开始工作,因此关键的初始化过程放在前者中也就不奇怪了。

从Makefile中知道(不看也知道),CONFIG_USB_XHCI_PCI需要xhci-pci.o,因此打开xhci-pci.c搜索module_init:

static int __init xhci_pci_init(void)
{
	xhci_init_driver(&xhci_pci_hc_driver, xhci_pci_setup);
#ifdef CONFIG_PM
	xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend;
	xhci_pci_hc_driver.pci_resume = xhci_pci_resume;
#endif
	return pci_register_driver(&xhci_pci_driver);
}
module_init(xhci_pci_init);

子曰:好戏开始了。


你可能感兴趣的:(Linux设备驱动)