linux usb初始化

 一.前言

对于usb的普通驱动,我们了解了不少,但是对于usb的真正核心还是不是太理解。该文中对于usb的初始化进行一定的学习,如有不对之处,请各位多多指教。

 

二.usb子系统初始化。

话说在linux启动之初,就会将usb子系统初始化完成,亦如input子系统和V4L2一样。usb_init就完成了初始化以及启动usb hub守护进程。那来看usb_init中的各个函数的实现。

2.1 ksuspend_usb_init

static int ksuspend_usb_init(void)

{

    ksuspend_usb_wq= create_freezeable_workqueue("ksuspend_usbd");

    if(!ksuspend_usb_wq)

        return-ENOMEM;

    return 0;

}

创建一个名为ksuspend_usbd的工作队列。不过在该函数说明中也说明了,该函数在多CPU中并不能很好的工作。也许大家对这个函数会很奇怪,不知道该工作队列的作用。

这个工作队列如何使用的,将在看usbsuspend和resume时再具体看这个东东具体有什么用。

2.2 bus_register

在usb_init中第二个调用的函数是bus_register(&usb_bus_type);这个应该很熟悉吧,注册一个usb总线,其会在/sys/bus下创建一个usb的文件夹,在其中会创建bus属性文件和drivers和devices文件夹,以后所有的usb设备和usb驱动都会在这两个文件夹下。bus总线需要指明device和driver匹配的规则,例如platform bus以name进行匹配,而usb则以id进行匹配。对于bus_register在前文中讲述多,这里不多此一举了。那主要来看usb bus的特征。

struct bus_type usb_bus_type = {

.name =      "usb",              --定义bus的name,这个也会是在/sys/bus下看见的文件夹得名称。

    .match =    usb_device_match,   --定义bus的device和driver的匹配规则

    .uevent =   usb_uevent,         --usb的触发事件处理。

};

下面来看usb的匹配规则函数。不过有一点需要说明的是一般usb的驱动为usb的interface的驱动,而不是usb设备的驱动。为了方便描述,并没有加以说明,要注意了。

static int usb_device_match(structdevice *dev, struct device_driver *drv)

{

    if(is_usb_device(dev)) {       --判断是否为usbdevice

    if (!is_usb_device_driver(drv)) --判断是否为为usb device的驱动。interface 驱动不能与device匹配。

            return0;

        return1;      --这个不是主要的,下面才是真正的驱动和设备的匹配。

    } else {

        structusb_interface *intf;

        structusb_driver *usb_drv;

        conststruct usb_device_id *id;

        if (is_usb_device_driver(drv))   --usb device driver不能驱动interface。

            return0;

        intf =to_usb_interface(dev);    --取得设备的当前interface

        usb_drv =to_usb_driver(drv);    --取得驱动。

      id = usb_match_id(intf, usb_drv->id_table);  --真正的匹配规则。对于这个函数我们就不加描述。感兴趣的可以去看具体的实现,其实这个函数的额实现也很简单。就是对usb interface中的id如idVendor,idProduct, bDeviceClass等参数进行匹配。

    if (id)

            return1;

        id =usb_match_dynamic_id(intf, usb_drv);

        if (id)

            return1;

    }

    return 0;

}

对于usb match比较好理解,而usb_uevent中,则定义了usb的热插拔的处理函数。这个的作用就是将设备的信息存储到env中,可以供用户空间读。对于设备的信息,我们可以通过在用户空间的程序中读取/proc/bus/usb/下的文件取得这些设备的信息。

static int usb_uevent(struct device*dev, struct kobj_uevent_env *env)

{

    structusb_device *usb_dev;

    if(is_usb_device(dev))

        usb_dev= to_usb_device(dev);

    else{

        structusb_interface *intf = to_usb_interface(dev);

        usb_dev= interface_to_usbdev(intf);

    }

 

    if(usb_dev->devnum < 0) {

            return -ENODEV;

    }

    if(!usb_dev->bus) {

        return -ENODEV;

    }

 

#ifdef  CONFIG_USB_DEVICEFS     --添加设备名称

    if(add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d",

               usb_dev->bus->busnum,usb_dev->devnum))

        return-ENOMEM;

#endif

    if(add_uevent_var(env, "PRODUCT=%x/%x/%x",  --添加设备id

              le16_to_cpu(usb_dev->descriptor.idVendor),

              le16_to_cpu(usb_dev->descriptor.idProduct),

               le16_to_cpu(usb_dev->descriptor.bcdDevice)))

        return-ENOMEM;

    if(add_uevent_var(env, "TYPE=%d/%d/%d",   --添加设备类型。

               usb_dev->descriptor.bDeviceClass,

               usb_dev->descriptor.bDeviceSubClass,

               usb_dev->descriptor.bDeviceProtocol))

        return-ENOMEM;

 

    return0;

}

对于uevent的理解可能比较难懂一点,不过你可以把uevent的操作看成将一些设备和驱动的信息写到/proc下对应的文件中,让usrspcae的用户程序可以读取从而获取设备的信息。

2.3  usb_host_init

也许从这个函数名上看不出这个函数的具体应用是什么,既然看函数名不知道干什么,那我们来看该函数的具体实现。你会发现这个函数好像挺简单的,就是创建一个usb host 类。

int usb_host_init(void)

{

    intretval = 0;

    usb_host_class= class_create(THIS_MODULE, "usb_host");

    if(IS_ERR(usb_host_class))

        retval= PTR_ERR(usb_host_class);

    returnretval;

}

关于这个设备类有什么用,以后再说,咱们还是继续usb init的主线来看usb。

2.4 usb_major_init

注册usb major其实是注册一个以USB_MAJOR为主设备号的cdev。不过其还分配了256个从设备号。提供一个公共的open函数。

int usb_major_init(void)

{

    interror;

 

    error= register_chrdev(USB_MAJOR, "usb", &usb_fops);

    if(error)

        printk(KERN_ERR"Unable to get major %d for usb devices\n",

               USB_MAJOR);

 

    returnerror;

}

对于每一个usb设备的打开都会先调用主设备的open,而后根据不同的设备调用不同的open函数。下面就是cdev的ops操作集。

static const struct file_operationsusb_fops = {

    .owner=    THIS_MODULE,

    .open=     usb_open,

};

static int usb_open(struct inode *inode, struct file * file)

{

    intminor = iminor(inode);

    conststruct file_operations *c;

    interr = -ENODEV;

    conststruct file_operations *old_fops, *new_fops = NULL;

 

    lock_kernel();

    down_read(&minor_rwsem);

    c= usb_minors[minor];  --关于这个全局变量在以后的usb设备注册时会看到,这里先有个底。

    if(!c || !(new_fops = fops_get(c)))

        gotodone;

 

    old_fops= file->f_op;

    file->f_op= new_fops;

    /*Curiouser and curiouser... NULL ->open() as "no device" ? */

    if(file->f_op->open)

        err= file->f_op->open(inode,file);  --调用真正的open

    if(err) {

        fops_put(file->f_op);

        file->f_op= fops_get(old_fops);

    }

    fops_put(old_fops);

 done:

    up_read(&minor_rwsem);

    unlock_kernel();

    returnerr;

}

其实上面的公共的open就是提供一个对于所有的usb 设备的公共接口,真正的open其实是usb_minors中存储的fops->open.

2.5 usb_register

该函数是注册usbfs_driver驱动。不过注册该驱动不知是为什么。

2.6 usb_devio_init

对于这个函数就更加困惑了,这个同样是注册一个以USB_DEVICE_DEV为主设备号的cdev设备。

int __init usb_devio_init(void)

{

    intretval;

    retval= register_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX,

                    "usb_device");

    if(retval) {

        gotoout;

    }

    cdev_init(&usb_device_cdev,&usbdev_file_operations);

    retval= cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);

    if(retval) {

        gotoerror_cdev;

    }

    usb_classdev_class= class_create(THIS_MODULE, "usb_device");

    if(IS_ERR(usb_classdev_class)) {

        gotoout;

    }

    usb_classdev_class->dev_kobj= NULL;

    usb_register_notify(&usbdev_nb);

    returnretval;

}

关于这个函数具体有什么用,以后再看,先跳过。

2.7 usbfs_init

int __init usbfs_init(void)

{

    intretval;

    retval= register_filesystem(&usb_fs_type); --注册filesystem

    if(retval)

        returnretval;

    usb_register_notify(&usbfs_nb);

    usbdir= proc_mkdir("bus/usb", NULL); --为usbfs创建挂载点

    return0;

}

2.8 usb_hub_init

int usb_hub_init(void)

{

    if(usb_register(&hub_driver) < 0) { --注册hub驱动

        printk(KERN_ERR"%s: can't register hub driver\n",

            usbcore_name);

        return-1;

    }

    khubd_task= kthread_run(hub_thread, NULL, "khubd"); --创建hub守护进程

    if(!IS_ERR(khubd_task))

        return0;

    usb_deregister(&hub_driver);

    return-1;

}

2.9 usb_register_device_driver

注册一个通用usb驱动。usb_register_device_driver(&usb_generic_driver,THIS_MODULE);

OK,到此usb init是看完了,不过这里面却有种种的迷雾,让人不解困惑。比如为什么要注册两个usb major,还注册了两个古怪的驱动,这些种种让人不解。不过这些都将会在后面的学习中来了解这些。

三.总结

对于大牛们而言,也许这些东西很简单,不过对于我这个菜鸟而言,却是那么的难弄。在此本文也仅仅是对自己学习的一个记录。

你可能感兴趣的:(linux usb初始化)