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