赞
踩
虽然Linux内核拥有C语言构建的身体,但它骨子里散发的是面向对象的气质,这一个个的对象就是struct。面对一个内核模块的时候,首先要找出关键的struct和它们之间的关系,才能摸清代码的骨骼脉络。
大致浏览几眼xHCI相关的代码,很容易发现几个貌似重要的struct类型:usb_hcd
、xhci_hcd
和hc_driver
,还有几个全局变量xhci_pci_driver
、xhci_hc_driver
和xhci_pci_hc_driver
,再加上PCI总线相关的类型pci_dev
和pci_driver
。不要被这些眼花缭乱的名字吓到,今天要做的就是把这些结构之间的关系理顺。下面按照相关代码的执行顺序,看一下这些结构是如何被建立和初始化的。
先上图,下面分析的过程结束之后各个结构体就是这种关系:
xhci_pci_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);
}
xhci_pci_init
调用xhci_init_driver
,初始化xhci_pci_hc_driver
变量xhci_init_driver
函数是在xhci.c中定义的,主要作用就是把全局变量xhci_hc_driver
的值一股脑赋给另一个全局变量xhci_pci_hc_driver
。两者都是struct hc_driver
类型,xhci_pci_hc_driver
在xhci-pci.c中定义,是真正起作用的xHCI驱动,但它在定义的时候没有进行任何成员的初始化:
static struct hc_driver __read_mostly xhci_pci_hc_driver;
而xhci_hc_driver在xhci.c中定义,它包揽了所有的脏活累活:
static const struct hc_driver xhci_hc_driver = {
.description = "xhci-hcd",
.product_desc = "xHCI Host Controller",
.hcd_priv_size = sizeof(struct xhci_hcd *),
/*
* generic hardware linkage
*/
.irq = xhci_irq,
.flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED,
/*
* basic lifecycle operations
*/
.reset = NULL, /* set in xhci_init_driver() */
.start = xhci_run,
.stop = xhci_stop,
.shutdown = xhci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,
.free_dev = xhci_free_dev,
.alloc_streams = xhci_alloc_streams,
.free_streams = xhci_free_streams,
.add_endpoint = xhci_add_endpoint,
.drop_endpoint = xhci_drop_endpoint,
.endpoint_reset = xhci_endpoint_reset,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device,
.enable_device = xhci_enable_device,
.update_hub_device = xhci_update_hub_device,
.reset_device = xhci_discover_or_reset_device,
/*
* scheduling support
*/
.get_frame_number = xhci_get_frame,
/*
* root hub support
*/
.hub_control = xhci_hub_control,
.hub_status_data = xhci_hub_status_data,
.bus_suspend = xhci_bus_suspend,
.bus_resume = xhci_bus_resume,
/*
* call back when device connected and addressed
*/
.update_device = xhci_update_device,
.set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm,
.enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout,
.disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout,
.find_raw_port_number = xhci_find_raw_port_number,
};
void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *))
{
BUG_ON(!setup_fn);
*drv = xhci_hc_driver;
drv->reset = setup_fn;
}
xhci_init_driver
函数将xhci_hc_driver
的值赋给xhci_pci_hc_driver
后,前者也就退下了舞台。不信,你看:
(free-electrons是个好网站)
xhci_pci_init
调用pci_register_driver
,将xhci_pci_driver
注册为PCI设备驱动xhci_pci_driver
是xHCI控制器作为PCI设备对应的驱动,符合PCI设备驱动的标准类型struct pci_driver
,在xhci-pci.c中静态定义并初始化:
/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver xhci_pci_driver = {
.name = (char *) hcd_name,
.id_table = pci_ids,
.probe = xhci_pci_probe,
.remove = xhci_pci_remove,
/* suspend and resume implemented later */
.shutdown = usb_hcd_pci_shutdown,
#ifdef CONFIG_PM
.driver = {
.pm = &usb_hcd_pci_pm_ops
},
#endif
};
其中有两个成员需要重点关注,一个是id_table
,一个是probe
。id_table
包含了驱动支持的PCI设备类型,PCI总线就是靠它判断驱动和设备能否配对。这里的id_table
成员设置为pci_ids
,它也是静态定义的全局变量:
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids[] = { {
/* handle any USB 3.0 xHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
.driver_data = (unsigned long) &xhci_pci_hc_driver,
},
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);
注意pci_ids
中唯一一个元素的driver_data
成员指向刚才在xhci_pci_init
中完成初始化的xhci_pci_hc_driver
变量,这就将作为PCI设备驱动的xhci_pci_driver
和作为USB主机控制器设备驱动xhci_pci_hc_driver
联系了起来。本文最开始的图中右半部分画出了它们的关系。
当pci_register_driver
调用完成后,xhci_pci_driver
就被加入了PCI总线的驱动列表,当总线检测到与之匹配的设备,即xHCI控制器的时候,会调用驱动的probe成员函数,而xhci_pci_driver.probe
在初始化时被设置为xhci_pci_probe
函数,因此接下来就顺藤摸瓜考察它。
xhci_pci_probe
函数这个函数也定义在xhci-pci.c中,比较长(所以加了行号),先贴前半部分:
217 static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
218 {
219 int retv
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。