Linux内核USB3.0驱动框架分析--USB Core分析

1.概述

如下图所示,Linux内核中USB主机体系结构由五部分组成,分别为Application Software、USB Class Driver、USB Core(USB Driver)、USB Host Controller Driver、USB Host Controller。应用程序处于用户空间,通过系统调用访问Class Driver,从而间接的访问USB设备,如主机端的应用程序aplay、arecord可以访问USB音频设备。Class Driver是某一类设备驱动,不同类设备会匹配不同的Class Driver,如USB音频设备会匹配Audio驱动,USB存储设备会匹配Mass Storage驱动,鼠标和键盘会匹配HID驱动。USB Core(USB Driver)是内核设计的一个抽象层,目的是将Class Driver和USB Host Controller Driver分隔开,使两者都依赖一个稳定的中间层;USB Core(USB Driver)向上提供通信接口,向下统一管理USB设备,同时完成USB设备和USB Class Driver的匹配工作。USB Host Controller目前有4种不同的硬件级接口标准,分别为OHCI、UHCI、EHCI、xHCI,OHCI和UHCI实现了USB1.1,EHCI实现了USB2.0,xHCI实现了USB3.2,不同的接口标准都有对应的USB Host Controller Driver,如xHCI对应于xhci-hcd驱动,向下兼容OHCI和EHCI。最底层是USB Host Controller硬件。下面将分别介绍Linux内核中USB主机体系结构USB Class Driver、USB Core(USB Driver)、USB Host Controller Driver四个部分。
在这里插入图片描述

2. USB子系统结构
USBcore源码位于./drivers/usb/core,usbcore这个模块代表的不是某一个设备,而是所有USB设备赖以生存的模块,它就是USB子系统。USB Core(USB Driver)有三个功能,第一是向USB Class Driver提供通信接口,第二是匹配驱动,第三是管理USB Device。

在./drivers/usb/core/usb.c里实现了初始化,源代码如下,

static int __init usb_init(void)
{
  
    retval = bus_register(&usb_bus_type); //注册USB总线,也就是USB子系统
   
    retval = usb_hub_init(); //usb hub初始化 
   
    retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); //注册一个USB设备(不是接口)驱动程序
   
}

usbcore注册了USB总线,USB文件系统,USBHub以及USB的设备驱动usb generic driver等。

2.1 usb总线的注册

struct bus_type usb_bus_type = {  
    .name = "usb",  //总线名   
    .match =    usb_device_match,   //匹配方法,应该用于usb驱动id_table的匹配   
    .uevent =   usb_uevent, //事件处理   
};  

USB Class Driver和USB设备接口、USB设备和USB Core(USB Driver)都是通过struct usb_device_id中的信息进行匹配。struct usb_device_id定义了4中匹配方式,第一种是产品信息匹配,通常情况使用VID和PID;第二种是根据设备类信息进行匹配;第三种根据接口的类信息进行匹配,第四种根据厂家自定义的接口进行匹配。具体使用那种匹配方式,由match_flags决定,内核定义了USB_DEVICE_ID_xx开头的宏,用来设置match_flags。USB Class Driver和USB设备接口、USB设备和USB Core(USB Driver)的匹配工作由usb_bus_type中的usb_device_match函数完成,该函数会进一步调用usb_match_id进行匹配。

2.2 usb注册通用设备驱动

int usb_register_device_driver(struct usb_device_driver *new_udriver,struct module *owner)  

{  
    int retval = 0;  
    if (usb_disabled())  
        return -ENODEV;  
    new_udriver->drvwrap.for_devices = 1;    //usb设备   
    new_udriver->drvwrap.driver.name = (char *) new_udriver->name;    //设备名   
    new_udriver->drvwrap.driver.bus = &usb_bus_type; //总线类型   
    new_udriver->drvwrap.driver.probe = usb_probe_device;    //probe方法   
    new_udriver->drvwrap.driver.remove = usb_unbind_device;  //remove方法   
    new_udriver->drvwrap.driver.owner = owner;   //模块所有者   
    retval = driver_register(&new_udriver->drvwrap.driver);  //注册设备驱动   
    if (!retval) {  
        pr_info("%s: registered new device driver %s\n",usbcore_name, new_udriver->name);  
        usbfs_update_special();  
    } else {  
        printk(KERN_ERR "%s: error %d registering device driver %s\n",usbcore_name, retval, new_udriver->name);  
    }  
    return retval;  
}  

usb_device_driver结构体是usb_driver的简化版本,这里注册的是usb设备(非接口)驱动。

struct usb_driver定义的USB Class Driver驱动和USB设备的接口匹配,而struct usb_device_driver定义的驱动和USB设备匹配,使用usb_register_device_driver和usb_deregister_device_driver函数注册和注销struct usb_device_driver。内核提供了通用的struct usb_device_driver,即usb_generic_driver,在USB子系统初始化的时候注册到系统中,通常情况下USB Class Driver无需再提供struct usb_device_driver。

usb总线的match方法对usb设备和usb接口做了区分处理,针对usb设备,直接match的,(分析match时候再细化)

然后调用usb设备驱动的probe方法

static int usb_probe_device(struct device *dev)  
{  
    struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);  
    struct usb_device *udev = to_usb_device(dev);  
    int error = 0;  
    dev_dbg(dev, "%s\n", __func__);  
    if (!udriver->supports_autosuspend)  //条件成立   
        error = usb_autoresume_device(udev);  
    if (!error)  
        error = udriver->probe(udev);    //调用usb_device_driver的probe方法   
    return error;  
}  

接着调用usb_generic_driver的probe方法

struct usb_device_driver usb_generic_driver = {
    .name =    "usb",
    .probe = generic_probe,
    .disconnect = generic_disconnect,
#ifdef    CONFIG_PM
    .suspend = generic_suspend,
    .resume = generic_resume,
#endif
    .supports_autosuspend = 1,
};

注册根hub设备后,由于在usb子系统初始化函数中注册了usb通用设备驱动usb_generic_driver,这样就会执行usb_generic_driver的probe函数,即generic_probe:流程会转入到generic_probe().代码如下:

static int generic_probe(struct usb_device *udev)
{
    /* Choose and set the configuration.  This registers the interfaces
     * with the driver core and lets interface drivers bind to them.
     */
    if (udev->authorized == 0) //至于udev->authorized,在root hub的初始化中,是会将其初始化为1的.后面的逻辑就更简单了.为root hub 选择一个配置然后再设定这个配置.
        dev_err(&udev->dev, "Device is not authorized for usage\n");
    else {
        c = usb_choose_configuration(udev); //Usb2.0 spec上规定,对于hub设备,只能有一个config,一个interface,一个endpoint.实际上,在这里,对hub的选择约束不大,反正就一个配置,不管怎么样,选择和设定都是这个配置.
        if (c >= 0) {
            err = usb_set_configuration(udev, c);
            if (err && err != -ENODEV) {
                dev_err(&udev->dev, "can't set config #%d, error %d\n",
                    c, err);
                /* This need not be fatal.  The user can try to
                 * set other configurations. */
            }
        }
    }
    /* USB device state == configured ... usable */
    usb_notify_add_device(udev);
    return 0;
}

usb_set_configuration定义在drivers/usb/core/message.c

int usb_set_configuration(struct usb_device *dev, int configuration)
{
        int i, ret;
        struct usb_host_config *cp = NULL;
        struct usb_interface **new_interfaces = NULL;
        struct usb_hcd *hcd = bus_to_hcd(dev->bus);
        int n, nintf;

        if (dev->authorized == 0 || configuration == -1)
                configuration = 0;
        else {
                for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {  // 遍历每一个配置
                        if (dev->config[i].desc.bConfigurationValue ==      //  从配置描述符中获取配置值,配置值保存的是该配置在dev->config中的索引
                                        configuration) {
                                cp = &dev->config[i];           // 获取当前指定的配置
                                break;
                        }
                }
        }
        if ((!cp && configuration != 0))
                return -EINVAL;

       ......

        /* Now that all the interfaces are set up, register them
         * to trigger binding of drivers to interfaces.  probe()
         * routines may install different altsettings and may
         * claim() any interfaces not yet bound.  Many class drivers
         * need that: CDC, audio, video, etc.
         */
        for (i = 0; i < nintf; ++i) {            // 遍历当前配置的每一个接口
                struct usb_interface *intf = cp->interface[i];    

                if (intf->dev.of_node &&
                    !of_device_is_available(intf->dev.of_node)) {
                        dev_info(&dev->dev, "skipping disabled interface %d\n",
                                 intf->cur_altsetting->desc.bInterfaceNumber);
                        continue;
                }

                dev_dbg(&dev->dev,
                        "adding %s (config #%d, interface %d)\n",
                        dev_name(&intf->dev), configuration,
                        intf->cur_altsetting->desc.bInterfaceNumber);
                device_enable_async_suspend(&intf->dev);
                ret = device_add(&intf->dev);                 // 注册当前接口设备到内核
                if (ret != 0) {
                        dev_err(&dev->dev, "device_add(%s) --> %d\n",
                                dev_name(&intf->dev), ret);
                        continue;
                }
                create_intf_ep_devs(intf);
        }

        usb_autosuspend_device(dev);
        return 0;
}

在usb_set_configuration的尾部,会将usb_device设备指定配置里的每一个接口设备注册到内核中。

在执行device_add后导致总线的匹配函数usb_device_match再次被调用,这次由于是接口设备,设备类型为usb_if_device_type,那么匹配的一定是接口驱动,于是会执行usb_device_match的else分支,去匹配接口驱动。

然后调用device_add将设备加入到设备链表中,在执行device_add后,将执行总线的匹配函数usb_device_match:

device_add
    bus_probe_devic
        device_attach
            bus_for_each_drv
                __device_attach
                    driver_match_device
                        drv->bus->match(dev, drv)
                            usb_device_match

3. USB总线

下面总结下USB设备和驱动匹配的全过程,
在这里插入图片描述
USB子系统初始化的时候就会注册usb_generic_driver,它的结构体类型是usb_device_driver,它是USB世界里唯一的一个USB设备驱动,区别于struct usb_driver USB驱动。

·USB设备驱动(usb device driver)就只有一个,即usb_generice_driver这个对象,所有USB设备都要绑定到usb_generic_driver上,它的使命可以概括为:为USB设备选择一个合适的配置,让设备进入configured状态。

·USB驱动(usb driver)就是USB设备的接口驱动程序,比如adb驱动程序,u盘驱动程序,鼠标驱动程序等等。

在这里插入图片描述
Linux启动时注册USB驱动,在xxx_init()里通过usb_register()将USB驱动提交个设备模型,添加到USB总线的驱动链表里。

在这里插入图片描述
USB设备连接在Hub上,Hub检测到有设备连接进来,为设备分配一个struct usb_device结构体对象,并将设备添加到USB总线的设备列表里。
在这里插入图片描述
USB设备各个配置的详细信息在USB core里的漫漫旅途中已经被获取并存放在相关的几个成员里。

usb_generic_driver得到了USB设备的详细信息,然后把准备好的接口送给设备模型,Linux设备模型将接口添加到设备链表里,然后去轮询USB总线另外一条驱动链表,针对每个找到的驱动去调用USB总线的match函数,完成匹配。

4. 总结
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孤舟簔笠翁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值