Linux内核USB3.0驱动框架分析--USB Hub代码分析

一、Linux 下USB Hub热插拔处理

1.1 Linux下USB HUB的驱动的实现和分析:
USB设备是热插拔,因此在hub_probe函数中调用hub_configure函数来配置hub,在这个函数中主要是利用函数usb_alloc_urb函数来分配一个urb,利用usb_fill_int_urb来初始化这个urb结构,包括hub的中断服务程序hub_irq的,查询的周期等。
每当有设备连接到USB接口时,USB总线在查询hub状态信息的时候会触发hub的中断服务程序hub_irq, 在该函数中置位event_bits,运行工作队列。进入hub_event函数,该函数用来处理端口变化的事件。然后通过一个for循环来检测每个端口的状态信息。利用usb_port_status获取端口信息,如果发生变化就调用hub_port_connect_change函数来配置端口等。

在系统初始化的时候在usb_init函数中调用usb_hub_init函数,就进入了hub的初始化。

代码路径:drivers\usb\core\hub.c

在usb_hub_init函数中完成了注册hub驱动,并且利用函数alloc_workqueue创建一个工作队列。

1.2 初始化
这里我们主要分析khub的工作原理: 硬件层次是hub的工作,如何和host及其设备间通信及相应事件
hub的驱动定义为hub_driver,也是一个usb_driver结构体。hub驱动的匹配方式由hub_id_table定义,可以根据PID、VID、接口类型匹配。
[usb/core/hub.c ]

int usb_hub_init(void)
{
   
    if (usb_register(&hub_driver) < 0) {
    //注册usb HUB设备
        printk(KERN_ERR "%s: can't register hub driver\n",
            usbcore_name);
        return -1;
    }

    /*
     * The workqueue needs to be freezable to avoid interfering with
     * USB-PERSIST port handover. Otherwise it might see that a full-speed
     * device was gone before the EHCI controller had handed its port
     * over to the companion full-speed controller.
     */
    /* 工作队列需要是可冻结的,以避免干扰usb持续的端口切换。
    否则它可能会看到全速设备在EHCI控制器把端口交给全速控制器之前就消失了 */
    hub_wq = alloc_workqueue("usb_hub_wq", WQ_FREEZABLE, 0);  //创建工作队列
    if (hub_wq)
        return 0;
}
[drivers/usb/core/hub.c]
static const struct usb_device_id hub_id_table[] = {
   
    {
    .match_flags = USB_DEVICE_ID_MATCH_VENDOR
                   | USB_DEVICE_ID_MATCH_PRODUCT
                   | USB_DEVICE_ID_MATCH_INT_CLASS,
      .idVendor = USB_VENDOR_SMSC,
      .idProduct = USB_PRODUCT_USB5534B,
      .bInterfaceClass = USB_CLASS_HUB,
      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
    {
    .match_flags = USB_DEVICE_ID_MATCH_VENDOR
                   | USB_DEVICE_ID_MATCH_PRODUCT,
      .idVendor = USB_VENDOR_CYPRESS,
      .idProduct = USB_PRODUCT_CY7C65632,
      .driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
    {
    .match_flags = USB_DEVICE_ID_MATCH_VENDOR
			| USB_DEVICE_ID_MATCH_INT_CLASS,
      .idVendor = USB_VENDOR_GENESYS_LOGIC,
      .bInterfaceClass = USB_CLASS_HUB,
      .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
    {
    .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
      .bDeviceClass = USB_CLASS_HUB},
    {
    .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
      .bInterfaceClass = USB_CLASS_HUB},
    {
    }						/* Terminating entry */
};

MODULE_DEVICE_TABLE(usb, hub_id_table);
static struct usb_driver hub_driver = {
   
	.name                 =	    "hub",
	.probe                =	    hub_probe,
	.disconnect           =	    hub_disconnect,
	.suspend              =	    hub_suspend,
	.resume               =	    hub_resume,
	.reset_resume         =		hub_reset_resume,
	.pre_reset            =		hub_pre_reset,
	.post_reset           =		hub_post_reset,
	.unlocked_ioctl       = 	hub_ioctl,
	.id_table             =		hub_id_table,
	.supports_autosuspend =		1,
};

hub驱动匹配和初始化过程如下图所示,主要的工作流程有:

当注册root hub时,会调用device_add注册设备。内核调用usb_hub_init函数初始化hub,此时会调用usb_register_driver注册hub驱动hub_driver。hub设备或驱动注册时都会调用usb_device_match匹配到对方,若匹配成功,则hub_probe函数被调用,进入hub的初始化流程。
hub_probe函数中做了两件事,第一件是初始化轮询hub所用的工作队列和定时器,hub_event比较重要,用于处理USB设备连接、断开、低功耗模式等,后续会介绍,第二件是配置hub,具体的工作如下:
获取hub描述符,hub有专用的描述。
初始化用于事务分割的工作队列。主要是将USB2.0事物转换成USB1.0或USB1.1。
通过请求获取hub的信息和状态。
分配hub中断传输的urb,用以查询hub状态。
填充hub中断传输的urb,回调函数为hub_irq。
给hub的每个port创建usb_port数据结构。
使能hub,主要是给port上电,检查port状态、提交之前设置的中断传输urb,用于查询hub的状态;最后调度处理hub事件的工作队列,当有事件发生时会调用hub_event处理。

然后进入hub的probe函数,主要是一些工作的初始化和hub的配置,我这里化简了

static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤舟簔笠翁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值