linux設備驅動(3)devive_driver 詳解


linux 設備驅動模型中,之前內核直接叫做driver,后來改為device_driver,device和device_drvier 對應,驅動模型中最重要抽象兩個概念。接下一步步分析device_driver的注冊初始化過程。

1driver_register

code位於:drivers\base\Driver.c ,向bus中注冊一個device_driver

 1 /**
 2  * driver_register - register driver with bus
 3  * @drv: driver to register
 4  *
 5  * We pass off most of the work to the bus_add_driver() call,
 6  * since most of the things we have to do deal with the bus
 7  * structures.
 8  */
 9 int driver_register(struct device_driver *drv)
10 {
11     int ret;
12     struct device_driver *other;
13 
14     BUG_ON(!drv->bus->p);//driver的總線必須要有自己的subsys,因為這個才是整個bus連接device和driver的核心
15     /* driver和bus兩種都實現了下面函數,而實際最只能執行一個,所以告警說重復 */
16     if ((drv->bus->probe && drv->probe) ||
17         (drv->bus->remove && drv->remove) ||
18         (drv->bus->shutdown && drv->shutdown))
19         printk(KERN_WARNING "Driver '%s' needs updating - please use "
20             "bus_type methods\n", drv->name);
21     /* 查找驅動是否已經裝載注冊,已經裝載的則直接返回 */
22     other = driver_find(drv->name, drv->bus);
23     if (other) {
24         printk(KERN_ERR "Error: Driver '%s' is already registered, "
25             "aborting...\n", drv->name);
26         return -EBUSY;
27     }
28     /* 把驅動加入總線的驅動鏈表 */
29     ret = bus_add_driver(drv);
30     if (ret)
31         return ret;
32     ret = driver_add_groups(drv, drv->groups);//把驅動加入驅動的group中
33     if (ret) {
34         bus_remove_driver(drv);
35         return ret;
36     }
37     kobject_uevent(&drv->p->kobj, KOBJ_ADD);//向上報告一個增加事件
38 
39     return ret;
40 }

1.1driver_find

查找驅動是否已經裝載注冊,已經裝載的則直接返回
 1 /**
 2  * driver_find - locate driver on a bus by its name.
 3  * @name: name of the driver.
 4  * @bus: bus to scan for the driver.
 5  *
 6  * Call kset_find_obj() to iterate over list of drivers on
 7  * a bus to find driver by name. Return driver if found.
 8  *
 9  * This routine provides no locking to prevent the driver it returns
10  * from being unregistered or unloaded while the caller is using it.
11  * The caller is responsible for preventing this.
12  */
13 struct device_driver *driver_find(const char *name, struct bus_type *bus)
14 {
15     struct kobject *k = kset_find_obj(bus->p->drivers_kset, name);//在bus所管理的driver鏈表中,查找有沒有name這個driver
16     struct driver_private *priv;
17 
18     if (k) {
19         /* Drop reference added by kset_find_obj() */
20         kobject_put(k);//把該driver的kobject引用計數減1,kset_find_obj函數對其+1了
21         priv = to_driver(k);//
22         return priv->driver;//通過driver里面的kobject返回driver
23     }
24     return NULL;
25 }
26 
27 /**
28  * kset_find_obj - search for object in kset.
29  * @kset: kset we're looking in.
30  * @name: object's name.
31  *
32  * Lock kset via @kset->subsys, and iterate over @kset->list,
33  * looking for a matching kobject. If matching object is found
34  * take a reference and return the object.
35  */
36 struct kobject *kset_find_obj(struct kset *kset, const char *name)
37 {//遍歷kset的kobject鏈表中有沒有名為name的kobject
38     struct kobject *k;
39     struct kobject *ret = NULL;
40 
41     spin_lock(&kset->list_lock);
42     /*查找方法很簡單,依次遍歷bus的driver鏈表每個driver的kobject的name,如果有相同的返回對應的kobject*/
43     list_for_each_entry(k, &kset->list, entry) {
44         if (kobject_name(k) && !strcmp(kobject_name(k), name)) {
45             ret = kobject_get_unless_zero(k);//引用計數加1
46             break;
47         }
48     }
49 
50     spin_unlock(&kset->list_lock);
51     return ret;
52 }
1.2 bus_add_driver
把device_driver加入到bus中。source code位於:drivers\base\bus.c
 1 /**
 2  * bus_add_driver - Add a driver to the bus.
 3  * @drv: driver.
 4  */
 5 int bus_add_driver(struct device_driver *drv)
 6 {
 7     struct bus_type *bus;
 8     struct driver_private *priv;
 9     int error = 0;
10 
11     bus = bus_get(drv->bus);//拿到driver所屬的總線
12     if (!bus)
13         return -EINVAL;
14 
15     pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
16     /* bus有自己的private,device有自己的private,driver也有,功能就是負責連接對方 */
17     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
18     if (!priv) {
19         error = -ENOMEM;
20         goto out_put_bus;
21     }
22     klist_init(&priv->klist_devices, NULL, NULL);//初始化klist,以及填充dricer的private里面的內容
23     priv->driver = drv;
24     drv->p = priv;
25     priv->kobj.kset = bus->p->drivers_kset;//driver綁定bus(通過各自里面的privte)
26     error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
27                      "%s", drv->name);
28     if (error)
29         goto out_unregister;
30     /*把driver在bus的節點,加入到bus的driver鏈表的最后一個*/
31     klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
32     if (drv->bus->p->drivers_autoprobe) {
33         error = driver_attach(drv);//driver匹配device
34         if (error)
35             goto out_unregister;
36     }
37     module_add_driver(drv->owner, drv);
38 
39     error = driver_create_file(drv, &driver_attr_uevent);
40     if (error) {
41         printk(KERN_ERR "%s: uevent attr (%s) failed\n",
42             __func__, drv->name);
43     }
44     error = driver_add_attrs(bus, drv);//添加driver的屬性
45     if (error) {
46         /* How the hell do we get out of this pickle? Give up */
47         printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
48             __func__, drv->name);
49     }
50 
51     if (!drv->suppress_bind_attrs) {
52         error = add_bind_files(drv);
53         if (error) {
54             /* Ditto */
55             printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
56                 __func__, drv->name);
57         }
58     }
59 
60     return 0;
61 
62 out_unregister:
63     kobject_put(&priv->kobj);
64     kfree(drv->p);
65     drv->p = NULL;
66 out_put_bus:
67     bus_put(bus);
68     return error;
69 }

1.2.1driver_attach

 1 /**
 2  * driver_attach - try to bind driver to devices.
 3  * @drv: driver.
 4  *
 5  * Walk the list of devices that the bus has on it and try to
 6  * match the driver with each one.  If driver_probe_device()
 7  * returns 0 and the @dev->driver is set, we've found a
 8  * compatible pair.
 9  */
10 int driver_attach(struct device_driver *drv)
11 {
12     return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);//遍歷總線上的dev,調用_driver_attach匹配dev
13 }
14 
15 /**
16  * bus_for_each_dev - device iterator.
17  * @bus: bus type.
18  * @start: device to start iterating from.
19  * @data: data for the callback.
20  * @fn: function to be called for each device.
21  *
22  * Iterate over @bus's list of devices, and call @fn for each,
23  * passing it @data. If @start is not NULL, we use that device to
24  * begin iterating from.
25  *
26  * We check the return of @fn each time. If it returns anything
27  * other than 0, we break out and return that value.
28  *
29  * NOTE: The device that returns a non-zero value is not retained
30  * in any way, nor is its refcount incremented. If the caller needs
31  * to retain this data, it should do so, and increment the reference
32  * count in the supplied callback.
33  */
34 int bus_for_each_dev(struct bus_type *bus, struct device *start,
35              void *data, int (*fn)(struct device *, void *))
36 {
37     struct klist_iter i;
38     struct device *dev;
39     int error = 0;
40 
41     if (!bus || !bus->p)
42         return -EINVAL;
43 
44     klist_iter_init_node(&bus->p->klist_devices, &i,
45                  (start ? &start->p->knode_bus : NULL));
46     while ((dev = next_device(&i)) && !error)
47         error = fn(dev, data);
48     klist_iter_exit(&i);
49     return error;
50 }

1.2.1.1__driver_attach

 1 static int __driver_attach(struct device *dev, void *data)
 2 {
 3     struct device_driver *drv = data;
 4 
 5     /*
 6      * Lock device and try to bind to it. We drop the error
 7      * here and always return 0, because we need to keep trying
 8      * to bind to devices and some drivers will return an error
 9      * simply if it didn't support the device.
10      *
11      * driver_probe_device() will spit a warning if there
12      * is an error.
13      */
14 
15     if (!driver_match_device(drv, dev))//匹配dev,drv和dev匹配成功的話,才會往下執行的probe函數
16         return 0;
17 
18     if (dev->parent)    /* Needed for USB */
19         device_lock(dev->parent);
20     device_lock(dev);
21     if (!dev->driver)
22         driver_probe_device(drv, dev);//執行探針函數
23     device_unlock(dev);
24     if (dev->parent)
25         device_unlock(dev->parent);
26 
27     return 0;
28 }

1.2.1.1.1driver_match_device  driver_probe_device

以下的兩個API和device中一樣,調用的是同一個接口,不再詳述。

static inline int driver_match_device(struct device_driver *drv,
                      struct device *dev)
{
    return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}

/**
 * driver_probe_device - attempt to bind device & driver together
 * @drv: driver to bind a device to
 * @dev: device to try to bind to the driver
 *
 * This function returns -ENODEV if the device is not registered,
 * 1 if the device is bound successfully and 0 otherwise.
 *
 * This function must be called with @dev lock held.  When called for a
 * USB interface, @dev->parent lock must be held as well.
 */
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
    int ret = 0;

    if (!device_is_registered(dev))
        return -ENODEV;

    pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
         drv->bus->name, __func__, dev_name(dev), drv->name);

    pm_runtime_barrier(dev);
    ret = really_probe(dev, drv);
    pm_request_idle(dev);

    return ret;
}

2.總結

總結下整個flow:

driver_register(struct device_driver *drv)

     BUG_ON(!drv->bus->p); //driver的總線必須要有自己的subsys,因為這個才是整個bus連接device和driver的核心

     driver_find();//找到對應的driver   

         kset_find_obj();//在bus所管理的driver鏈表中,查找有沒有name這個driver

              list_for_each_entry()

              kobject_get();//找到的話,引用計數+1

          kobject_put();//把該driver的kobject引用計數減1,kset_find_obj函數對其+1了

          priv = to_driver(); //通過driver中的kobject找到driver

      bus_add_driver();//把驅動加入總線的驅動鏈表

      driver_add_groups();//驅動加到group中

      kobject_uevent();//向上增報告一個增加事件

 

bus_add_driver();//把驅動加入總線的驅動鏈表

     bus_get(drv->bus);//拿到bus

     priv = kzalloc(sizeof(*priv), GFP_KERNEL);//bus/device/ driver都有自己的private指針,負責連接對方

     klist_init();

     kobject_init_and_add();

     klist_add_tail();//把driver在bus的節點,加入到bus的driver鏈表的最后一個

     driver_attach();//否則,同步,直接執行匹配函數

         bus_for_each_dev();

         __driver_attach();

        driver_match_device();//drv和dev匹配成功的話,才會往下執行的probe函數

            return drv->bus->match ? drv->bus->match(dev, drv) : 1;// 調用bus的match函數匹配,bus的match函數不存在,則返回1

        device_lock(dev->parent);//設備的parent鎖定,不能執行睡眠,卸載之類的操作,否則下面driver_probe_device函數如果匹配上指行probe函數,就沒parent了

        device_lock(dev);//要用device,鎖定device。

        driver_probe_device();//同device,call對應的probe函數

        device_unlock(dev);

        device_unlock(dev->parent);

 

driver_probe_device()

     device_is_registered();//判斷設備是都注冊

     really_probe();//真正的probe函數

3. 設備模型框架下驅動開發的基本步驟

在設備模型框架下,設備驅動的開發是一件很簡單的事情,主要包括2個步驟:

步驟1:分配一個struct device類型的變量,填充必要的信息后,把它注冊到內核中。

步驟2:分配一個struct device_driver類型的變量,填充必要的信息后,把它注冊到內核中。

這兩步完成后,內核會在合適的時機,調用struct device_driver變量中的probe、remove、suspend、resume等回調函數,從而觸發或者終結設備驅動的執行。而所有的驅動程序邏輯,都會由這些回調函數實現,此時,驅動開發者眼中便不再有“設備模型”,轉而只關心驅動本身的實現。

以上兩個步驟的補充說明:

(1)一般情況下,Linux驅動開發很少直接使用device和device_driver,因為內核在它們之上又封裝了一層,如soc device、platform device等等,而這些層次提供的接口更為簡單、易用(也正是因為這個原因,本文並不會過多涉及device、device_driver等模塊的實現細節)。

(2)內核提供很多struct device結構的操作接口(具體可以參考include/linux/device.h和drivers/base/core.c的代碼),主要包括初始化(device_initialize)、注冊到內核(device_register)、分配存儲空間+初始化+注冊到內核(device_create)等等,可以根據需要使用。

(3) device和device_driver必須具備相同的名稱,內核才能完成匹配操作,進而調用device_driver中的相應接口。這里的同名,作用范圍是同一個bus下的所有device和device_driver。

(4) device和device_driver必須掛載在一個bus之下,該bus可以是實際存在的,也可以是虛擬的。

(5) driver開發者可以在struct device變量中,保存描述設備特征的信息,如尋址空間、依賴的GPIOs等,因為device指針會在執行probe等接口時傳入,這時driver就可以根據這些信息,執行相應的邏輯操作了。

4. 設備驅動probe的時機

所謂的"probe”,是指在Linux內核中,如果存在相同名稱的device和device_driver(注:還存在其它方式,我們先不關注了),內核就會執行device_driver中的probe回調函數,而該函數就是所有driver的入口,可以執行諸如硬件設備初始化、字符設備注冊、設備文件操作ops注冊等動作("remove”是它的反操作,發生在device或者device_driver任何一方從內核注銷時,其原理類似,就不再單獨說明了)。

設備驅動prove的時機有如下幾種(分為自動觸發和手動觸發):

將struct device類型的變量注冊到內核中時自動觸發(device_register,device_add,device_create_vargs,device_create)
將struct device_driver類型的變量注冊到內核中時自動觸發(driver_register)
手動查找同一bus下的所有device_driver,如果有和指定device同名的driver,執行probe操作(device_attach)
手動查找同一bus下的所有device,如果有和指定driver同名的device,執行probe操作(driver_attach)
自行調用driver的probe接口,並在該接口中將該driver綁定到某個device結構中----即設置dev->driver(device_bind_driver)
注2:probe動作實際是由bus模塊(會在下一篇文章講解)實現的,這不難理解:device和device_driver都是掛載在bus這根線上,因此只有bus最清楚應該為哪些device、哪些driver配對。

注3:每個bus都有一個drivers_autoprobe變量,用於控制是否在device或者driver注冊時,自動probe。該變量默認為1(即自動probe),bus模塊將它開放到sysfs中了,因而可在用戶空間修改,進而控制probe行為。


參考博文:https://blog.csdn.net/qq_16777851/java/article/details/81459931


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM