要開始系統學習LINUX USB驅動了(通用的驅動流程)

以USB串口驅動pl2303爲例子分析。


首先是要有一個總管usb設備的驅動,就是定義在generic.c中的 usb_device_driver;該結構在usb.c中註冊:

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; 
    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;
    new_udriver->drvwrap.driver.remove = usb_unbind_device;
    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_register_device_driver(&usb_generic_driver, THIS_MODULE) -> driver_register(這是usb device驅動,for_devices = 1);

記住,整個usb驅動架構中就註冊了一個這樣的設備驅動。


其次是具體設備的usb驅動usb_driver(如PL2303),他們都是用usb_register ->usb_register_driver -> driver_register來註冊的(這是註冊USB interface驅動,for_devices = 0):

int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
            const char *mod_name)
{
    int retval = 0;

    if (usb_disabled())
        return -ENODEV;

    new_driver->drvwrap.for_devices = 0;
    new_driver->drvwrap.driver.name = (char *) new_driver->name;
    new_driver->drvwrap.driver.bus = &usb_bus_type;
    new_driver->drvwrap.driver.probe = usb_probe_interface;
    new_driver->drvwrap.driver.remove = usb_unbind_interface;
    new_driver->drvwrap.driver.owner = owner;                                                                                                                  
    new_driver->drvwrap.driver.mod_name = mod_name;
    spin_lock_init(&new_driver->dynids.lock);
    INIT_LIST_HEAD(&new_driver->dynids.list);

    retval = driver_register(&new_driver->drvwrap.driver);
    if (retval)
        goto out;

    usbfs_update_special();

    retval = usb_create_newid_file(new_driver);
    if (retval)
        goto out_newid;

    retval = usb_create_removeid_file(new_driver);
    if (retval)
        goto out_removeid;
............................................................

這樣,driver就已經添加到USB總線上來。但是還沒有device;這是因爲deivce是動態創建加載的。USB子系統加載後,會啓動一個內核線程:kthread_run(hub_thread, NULL, "khubd")來監控usb設備的熱拔插事件,其發現設備的大體流程是:

hub_events -> hub_port_connect_change -> usb_alloc_dev -> 創建udev,並且賦值:

    dev->dev.bus = &usb_bus_type;
    dev->dev.type = &usb_device_type;//這是以後匹配device_driver的依據
    dev->dev.groups = usb_device_groups;

                                                                             ->usb_new_device(udev) -> device_add,這樣,就將檢測到的USB設備添加到USB總線usb_bus_type上了。

而接着在device_add -> bus_probe_device中會用bus_for_each_drv遍歷前面註冊在usb總線上的驅動,這個時候總線上有很多device_driver,但是我們要調用前面usb_register_device_driver註冊的通用設備描述符解析驅動。

這是如何匹配到的呢?進入USB總線usb_bus_type的match函數看看匹配規則就知道了:

static int usb_device_match(struct device *dev, struct device_driver *drv)                                                                                     
{
    /* devices and interfaces are handled separately */
    if (is_usb_device(dev)) {

        /* interface drivers never match devices */
        if (!is_usb_device_driver(drv))
            return 0;

        /* TODO: Add real matching code */
        return 1;

    } else if (is_usb_interface(dev)) {
        struct usb_interface *intf;
        struct usb_driver *usb_drv;
        const struct usb_device_id *id; 

        /* device drivers never match interfaces */
        if (is_usb_device_driver(drv))
            return 0;

        intf = to_usb_interface(dev);
        usb_drv = to_usb_driver(drv);

        id = usb_match_id(intf, usb_drv->id_table);
        if (id) 
            return 1;

        id = usb_match_dynamic_id(intf, usb_drv);
        if (id) 
            return 1;
    }    

    return 0;
}

可以猜想,現在要匹配的是設備驅動,而不是接口驅動,而is_usb_device函數的定義爲:

static inline int is_usb_device(const struct device *dev)                                                                                                      
{
    return dev->type == &usb_device_type;
}

根據前面usb_alloc_dev的賦值,該條件已經符合;接着is_usb_device_driver函數的定義:

static inline int is_usb_device_driver(struct device_driver *drv)                                                                                              
{           
    return container_of(drv, struct usbdrv_wrap, driver)->
            for_devices;
} 

剛好這裏for_devices前面賦值爲1,這樣usb_device_match就匹配成功了,找到了new_driver->drvwrap.driver這個device_driver,並調用他的probe方法->usb_probe_device:

static int usb_probe_device(struct device *dev)                                                                                                                
{
.......
        error = udriver->probe(udev);
.......
}

做一些簡單的判斷然後調用generic.c的usb_device_driver結構體的probe。再次強調,這是通用的配置描述符驅動是根據上述分,所有的usb插入設備都析的規則找到它,並調用他的probe方法來獲得配置描述符:

static int generic_probe(struct usb_device *udev)
{                                                                                                                                                              
    int err, c;

    /* Choose and set the configuration.  This registers the interfaces
     * with the driver core and lets interface drivers bind to them.
     */
    if (usb_device_is_owned(udev))
        ;       /* Don't configure if the device is owned */
    else if (udev->authorized == 0)
        dev_err(&udev->dev, "Device is not authorized for usage\n");
    else {
        c = usb_choose_configuration(udev);
        if (c >= 0) {
            err = usb_set_configuration(udev, c); 
            if (err) {
                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中,它根據選擇到的配置描述符,設置到設備中,使該配置下的接口生效,並將每個接口抽象成一個device,用device_add(&intf->dev)添加到USB總線上去。重要的代碼片段如下:

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;
。。。。。。
 new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
。。。。。。
        for (; n < nintf; ++n) {
            new_interfaces[n] = kzalloc(
                    sizeof(struct usb_interface),
                    GFP_NOIO);
。。。。。。
        usb_enable_interface(dev, intf, true);
        intf->dev.parent = &dev->dev;
        intf->dev.driver = NULL;
        intf->dev.bus = &usb_bus_type;
        intf->dev.type = &usb_if_device_type;
        intf->dev.groups = usb_interface_groups;
        intf->dev.dma_mask = dev->dev.dma_mask;
        INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
。。。。。。
    for (i = 0; i < nintf; ++i) {
        struct usb_interface *intf = cp->interface[i];

        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);
。。。。。。

這一次device_add又將匹配總線上的那個device_driver呢?回去看前面的match方法可知:

static inline int is_usb_interface(const struct device *dev)                                                                                                   
{
    return dev->type == &usb_if_device_type;
}

這個條件成立,調用usb_match_id(intf, usb_drv->id_table)和usb_match_dynamic_id匹配,這樣說吧,這裏是把從USB設備讀取道德PID,VID和驅動中定義的進行匹配,如果有則匹配成功。我們PL2303的id_table定義了很多,如果還要添加新的ID,則在該id_table添加即可。

匹配成功後,調用通用的usb_probe_interface:

static int usb_probe_interface(struct device *dev)
{
。。。。。。
    if (intf->needs_altsetting0) {
        error = usb_set_interface(udev, intf->altsetting[0].
                desc.bInterfaceNumber, 0);
。。。。。。
    error = driver->probe(intf, id);

。。。。。。

調用具體驅動的probe,這裏就是PL2303的probe了:

static struct usb_driver pl2303_driver = {                                                                                                                     
    .name =     "pl2303",
    .probe =    usb_serial_probe,
    .disconnect =   usb_serial_disconnect,
    .id_table = id_table,
    .suspend =      usb_serial_suspend,
    .resume =       usb_serial_resume,
    .no_dynamic_id =    1,
    .supports_autosuspend = 1,
};

usb_serial_probe,這裏看到有趣的事情,usb-serial.c 中的probe也指向usb_serial_probe,按理說應該是先找到usb-serial.c 的porbe,然後再通過它找到pl2303的probe。這裏可能是usb-serial.c 作爲一個通用的函數接口代碼,並沒有定義PID,VID;但是USB核心的匹配規則偏偏是匹配該ID,所以爲了迎合USB的架構,usb serial也沒有別的好辦法,只好把PL2303的probe指向了usb-serial.c 的porbe,在該probe中統一處理端點描述符。

從上面可以看出,USB子系統已經爲我們實現了大部分架構,我們驅動要做的事情只要實現接口描述符(interface descriptor)的處理即可,這就要求根據USB協議規則和具體的USB芯片手冊來操作。

下一篇就來分析常用的USB協議和一個具體的接口描述符驅動。










發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章