当前位置:   article > 正文

xHCI驱动学习(1) 核心数据结构_xhci协议学习

xhci协议学习

虽然Linux内核拥有C语言构建的身体,但它骨子里散发的是面向对象的气质,这一个个的对象就是struct。面对一个内核模块的时候,首先要找出关键的struct和它们之间的关系,才能摸清代码的骨骼脉络。

大致浏览几眼xHCI相关的代码,很容易发现几个貌似重要的struct类型:usb_hcdxhci_hcdhc_driver,还有几个全局变量xhci_pci_driverxhci_hc_driverxhci_pci_hc_driver,再加上PCI总线相关的类型pci_devpci_driver。不要被这些眼花缭乱的名字吓到,今天要做的就是把这些结构之间的关系理顺。下面按照相关代码的执行顺序,看一下这些结构是如何被建立和初始化的。

先上图,下面分析的过程结束之后各个结构体就是这种关系:
这里写图片描述

1. xhci-pci模块启动,执行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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

1.1 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;
  • 1

而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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

xhci_init_driver函数将xhci_hc_driver的值赋给xhci_pci_hc_driver后,前者也就退下了舞台。不信,你看:
free-electrons是个好网站)
这里写图片描述

1.2 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
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

其中有两个成员需要重点关注,一个是id_table,一个是probeid_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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

注意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函数,因此接下来就顺藤摸瓜考察它。

2. PCI设备配对成功,执行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
  • 1
  • 2
  • 3
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/247152
推荐阅读
相关标签
  

闽ICP备14008679号