Linux USB 3.0驱动分析(四)—— USB Core分析

一.拓扑结构

·之所以要规定这个树形拓扑结构是为了避免环形连接。

·一条USB总线有且只有一个USBHost,对应一个RootHub

·USB设备分为两类,Hub和Functions,Hub通过端口Port连接更多USB设备,Functions即USB外接从设备。

·层次最多7层,且第7层不能有Hub,只能有functions。

·CompoundDevice-一个Hub上接多个设备组成一个小设备。

·CompositeDevice-一个USB外接设备具有多个复用功能。



二.USBCore

1.USB子系统结构

HCD(Host Controller Device): USB主控制器设备

协议里说,HCD提供主控制器驱动的硬件抽象,它只对USBCore一个负责,USBCore将用户的请求映射到相关的HCD,用户不能直接访问HCD。换句话说,USBCore就是HCD与USB设备唯一的桥梁。


2.USB子系统的初始化

USBcore源码位于./drivers/usb/core,其中的Makefile摘要如下,

usbcore这个模块代表的不是某一个设备,而是所有USB设备赖以生存的模块,它就是USB子系统。


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

static int __init usb_init(void)
{
    retval = usb_debugfs_init();	//1.usb debugfs初始化
	if (retval)
		goto out;
    retval = bus_register(&usb_bus_type); //注册USB总线,也就是USB子系统
    if (retval)
        goto bus_register_failed;
    retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb); //注册内核通知链,用于设备和接口注册的通知
    if (retval)
        goto bus_notifier_failed;
    retval = usb_major_init(); //usb主设备号初始化
    if (retval)
        goto major_init_failed;
    retval = usb_register(&usbfs_driver); //注册usb文件系统
    if (retval)
        goto driver_register_failed;
    retval = usb_devio_init();  //usb设备字符设备初始化 
    if (retval)
        goto usb_devio_init_failed;
    retval = usb_hub_init(); //usb hub初始化 
    if (retval)
        goto hub_init_failed;
    retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE); //注册一个USB设备(不是接口)驱动程序
    if (!retval)
        goto out;
}

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


3. usb_debugfs_init --usb debugfs初始化

static int usb_debugfs_init(void)  
{  
    usb_debug_root = debugfs_create_dir("usb", NULL);   //创建"$(debugfs)/usb"   
    if (!usb_debug_root)  
        return -ENOENT;   
    //创建"$(debugfs)/usb/device",捆绑usbfs_devices_fops结构体,位置 /sys/kernel/debug/usb/device,打印所有总线下的设备
    usb_debug_devices = debugfs_create_file("devices", 0444,usb_debug_root, NULL,&usbfs_devices_fops);  
}  


4.usb总线的注册

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


5.注册usb总线通知链

int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)  
{  
    return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);  
}  

当总线添加删除设备的时候会调用usb_bus_nb指定的notifier_cal方法,既usb_bus_notify

static int usb_bus_notify(struct notifier_block *nb, unsigned long action,void *data)  
{  
    struct device *dev = data;  
    switch (action) {  
    case BUS_NOTIFY_ADD_DEVICE: //添加设备   
        if (dev->type == &usb_device_type)   //usb设备   
            (void) usb_create_sysfs_dev_files(to_usb_device(dev)); //生成sysfs节点/sys/devices/platform/soc@0/38100000.usb/xhci-hcd.0.auto/usb1
        else if (dev->type == &usb_if_device_type)   //usb接口   
            (void) usb_create_sysfs_intf_files(to_usb_interface(dev));  
        break;  
    case BUS_NOTIFY_DEL_DEVICE: //删除设备   
        if (dev->type == &usb_device_type)   //usb设备   
            usb_remove_sysfs_dev_files(to_usb_device(dev));  
        else if (dev->type == &usb_if_device_type)   //usb接口   
            usb_remove_sysfs_intf_files(to_usb_interface(dev));  
        break;  
    }  
    return 0;  
}  


6.初始化usb主控器字符设备,USB_MAJOR=180

int usb_major_init(void)  
{  
    int error;  
    error = register_chrdev(USB_MAJOR, "usb", &usb_fops);   //注册usb控制器字符设备,捆绑usb_fops   
    if (error)  
        printk(KERN_ERR "Unable to get major %d for usb devices\n",USB_MAJOR);  
    return error;  
}  

捆绑usb_fops

static const struct file_operations usb_fops = {  
    .owner =    THIS_MODULE,  
    .open = usb_open,  
    .llseek =   noop_llseek,  
};  


7.注册usbfs_driver

usb_register(&usbfs_driver); //通过usb_register()将usbfs驱动提交个设备模型,添加到USB总线的驱动链表里。

/* use a define to avoid include chaining to get THIS_MODULE & friends */
//其实是调用usb_register_driver,注册一个usb接口驱动
#define usb_register(driver) \
    usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)

struct usb_driver usbfs_driver = {  
    .name = "usbfs",  //在/sys/bus/usb/drivers/usbfs
    .probe =    driver_probe,  
    .disconnect = driver_disconnect,  
    .suspend = driver_suspend,  
    .resume =   driver_resume,  
};  


8.usb_devio_init     USB_DEVICE_DEV=189

//用于应用程序直接访问usb设备

int __init usb_devio_init(void)
{
    int retval;

    retval = register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,
                    "usb_device"); //分配设备号
    if (retval) {
        printk(KERN_ERR "Unable to register minors for usb_device\n");
        goto out;
    }
    cdev_init(&usb_device_cdev, &usbdev_file_operations); //字符设备初始化
    retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX); //添加字符设备
    if (retval) {
        printk(KERN_ERR "Unable to get usb_device major %d\n",
              USB_DEVICE_MAJOR);
        goto error_cdev;
    }
    usb_register_notify(&usbdev_nb); //注册设备通知链
}

usb注册的通知链

void usb_register_notify(struct notifier_block *nb)  
{  
    blocking_notifier_chain_register(&usb_notifier_list, nb);  
}  

usb通知链表头为usb_notifier_list

在/drivers/usb/core/notify.c文件中,有四个函数()对usb_notifier_list中发送通知,这四个函数如下:

usb_notify_add_device    //有设备添加
usb_notify_remove_device    //有设备移除
usb_notify_add_bus    //总线添加
usb_notify_remove_bus    //总线移除

当这些事件发生后会调用usbdev_nb指定的notifier_cal方法,既usbdev_notify

static int usbdev_notify(struct notifier_block *self,
                   unsigned long action, void *dev)
{
    switch (action) {
    case USB_DEVICE_ADD:
        break;
    case USB_DEVICE_REMOVE:
        usbdev_remove(dev);
        break;
    }
    return NOTIFY_OK;
}


8.usb hub初始化
后续详细分析


9. 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设备(非接口)驱动。

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,
};

对应到root hub,流程会转入到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总线

注册USB总线通过bus_register(&usb_bus_type);

struct bus_type usb_bus_type={

    .name="usb",

    .match=usb_device_match,//这是个很重要的函数,用来匹配USB设备和驱动。

    .uevent=usb_uevent,.pm=&usb_bus_pm_ops,

};

下面总结下USB设备和驱动匹配的全过程,


->step1-usb device driver

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盘驱动程序,鼠标驱动程序等等。


->step2-usb driver

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


->step3-usb device

USB设备连接在Hub上,Hub检测到有设备连接进来,为设备分配一个struct usb_device结构体对象,并将设备添加到USB总线的设备列表里。


->step4-usb interface

USB设备各个配置的详细信息在USB core里的漫漫旅途中已经被获取并存放在相关的几个成员里。

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



参考:

    二、usb子系统初始化_jixianghao的博客-CSDN博客

    USB在Linux里的结构框架是什么样的?USB Core和Hub是什么?

    Linux设备驱动之USB hub驱动_cosmoslhf的专栏-CSDN博客


posted @ 2021-01-15 14:30  luoyuna  阅读(5848)  评论(0编辑  收藏  举报