Linux設備驅動的模型,是建立在sysfs設備文件系統和kobject上的,由總線(bus)、設備(device)、驅動(driver)和類(class)所組成的關系結構,在底層,Linux系統中的每個設備都有一個device結構體的實例。struct device已在上一博文中介紹,下面按順序詳細介紹device的主要API。
1.device_create
source位於:drivers\base\Core.c。向sysfs注冊一個device,提供了強大的格式化注冊接口。
1 /** 2 * device_create - creates a device and registers it with sysfs 3 * @class: pointer to the struct class that this device should be registered to 4 * @parent: pointer to the parent struct device of this new device, if any 5 * @devt: the dev_t for the char device to be added 6 * @drvdata: the data to be added to the device for callbacks 7 * @fmt: string for the device's name 8 * 9 * This function can be used by char device classes. A struct device 10 * will be created in sysfs, registered to the specified class. 11 * 12 * A "dev" file will be created, showing the dev_t for the device, if 13 * the dev_t is not 0,0. 14 * If a pointer to a parent struct device is passed in, the newly created 15 * struct device will be a child of that device in sysfs. 16 * The pointer to the struct device will be returned from the call. 17 * Any further sysfs files that might be required can be created using this 18 * pointer. 19 * 20 * Returns &struct device pointer on success, or ERR_PTR() on error. 21 * 22 * Note: the struct class passed to this function must have previously 23 * been created with a call to class_create(). 24 */ 25 struct device *device_create(struct class *class, struct device *parent, 26 dev_t devt, void *drvdata, const char *fmt, ...) 27 { 28 va_list vargs; 29 struct device *dev; 30 31 va_start(vargs, fmt); 32 dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs); 33 va_end(vargs); 34 return dev; 35 }
1.1device_create_vargs
上面API只是為了提供完善的接口,下面API這個才是真正工作的。所做的工作:
1)新建一個設備並kzalloc struct device,初步初始化部分結構體成員。
2)注冊設備device
1 /** 2 * device_create_vargs - creates a device and registers it with sysfs 3 * @class: pointer to the struct class that this device should be registered to 4 * @parent: pointer to the parent struct device of this new device, if any 5 * @devt: the dev_t for the char device to be added 6 * @drvdata: the data to be added to the device for callbacks 7 * @fmt: string for the device's name 8 * @args: va_list for the device's name 9 * 10 * This function can be used by char device classes. A struct device 11 * will be created in sysfs, registered to the specified class. 12 * 13 * A "dev" file will be created, showing the dev_t for the device, if 14 * the dev_t is not 0,0. 15 * If a pointer to a parent struct device is passed in, the newly created 16 * struct device will be a child of that device in sysfs. 17 * The pointer to the struct device will be returned from the call. 18 * Any further sysfs files that might be required can be created using this 19 * pointer. 20 * 21 * Returns &struct device pointer on success, or ERR_PTR() on error. 22 * 23 * Note: the struct class passed to this function must have previously 24 * been created with a call to class_create(). 25 */ 26 struct device *device_create_vargs(struct class *class, struct device *parent, 27 dev_t devt, void *drvdata, const char *fmt, 28 va_list args) 29 { 30 struct device *dev = NULL; 31 int retval = -ENODEV; 32 33 if (class == NULL || IS_ERR(class)) 34 goto error; 35 36 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 37 if (!dev) { 38 retval = -ENOMEM; 39 goto error; 40 } 41 42 dev->devt = devt; 43 dev->class = class; 44 dev->parent = parent; 45 dev->release = device_create_release; 46 dev_set_drvdata(dev, drvdata); 47 48 retval = kobject_set_name_vargs(&dev->kobj, fmt, args);//kobject相關知識,暫且跳過,后續介紹 49 if (retval) 50 goto error; 51 52 retval = device_register(dev); 53 if (retval) 54 goto error; 55 56 return dev; 57 58 error: 59 put_device(dev); 60 return ERR_PTR(retval); 61 }
2 device_register
真正注冊設備device。
1 /** 2 * device_register - register a device with the system. 3 * @dev: pointer to the device structure 4 * 5 * This happens in two clean steps - initialize the device 6 * and add it to the system. The two steps can be called 7 * separately, but this is the easiest and most common. 8 * I.e. you should only call the two helpers separately if 9 * have a clearly defined need to use and refcount the device 10 * before it is added to the hierarchy. 11 * 12 * For more information, see the kerneldoc for device_initialize() 13 * and device_add(). 14 * 15 * NOTE: _Never_ directly free @dev after calling this function, even 16 * if it returned an error! Always use put_device() to give up the 17 * reference initialized in this function instead. 18 */ 19 int device_register(struct device *dev) 20 { 21 device_initialize(dev); 22 return device_add(dev); 23 }
3 device_initialize
1 /** 2 * device_initialize - init device structure. 3 * @dev: device. 4 * 5 * This prepares the device for use by other layers by initializing 6 * its fields. 7 * It is the first half of device_register(), if called by 8 * that function, though it can also be called separately, so one 9 * may use @dev's fields. In particular, get_device()/put_device() 10 * may be used for reference counting of @dev after calling this 11 * function. 12 * 13 * All fields in @dev must be initialized by the caller to 0, except 14 * for those explicitly set to some other value. The simplest 15 * approach is to use kzalloc() to allocate the structure containing 16 * @dev. 17 * 18 * NOTE: Use put_device() to give up your reference instead of freeing 19 * @dev directly once you have called this function. 20 */ 21 void device_initialize(struct device *dev) 22 { 23 dev->kobj.kset = devices_kset;//所有的dev都有公共的device_set,在系統初始化的時候動態申請的,具體的回掉函數show,store,release還是要由dev里的release或dev_type里的release或從屬的class里的dev_release來清除 24 kobject_init(&dev->kobj, &device_ktype);//初始化kobject 25 INIT_LIST_HEAD(&dev->dma_pools);//初始化鏈表 26 mutex_init(&dev->mutex);//避免被打擾,加鎖 27 lockdep_set_novalidate_class(&dev->mutex); 28 spin_lock_init(&dev->devres_lock); 29 INIT_LIST_HEAD(&dev->devres_head);//將此device加入鏈表中 30 device_pm_init(dev);//電源管理的初始化 31 set_dev_node(dev, -1); 32 }
4 device_add
1 /**
2 * device_add - add device to device hierarchy.
3 * @dev: device.
4 *
5 * This is part 2 of device_register(), though may be called
6 * separately _iff_ device_initialize() has been called separately.
7 *
8 * This adds @dev to the kobject hierarchy via kobject_add(), adds it
9 * to the global and sibling lists for the device, then
10 * adds it to the other relevant subsystems of the driver model.
11 *
12 * Do not call this routine or device_register() more than once for
13 * any device structure. The driver model core is not designed to work
14 * with devices that get unregistered and then spring back to life.
15 * (Among other things, it's very hard to guarantee that all references
16 * to the previous incarnation of @dev have been dropped.) Allocate
17 * and register a fresh new struct device instead.
18 *
19 * NOTE: _Never_ directly free @dev after calling this function, even
20 * if it returned an error! Always use put_device() to give up your
21 * reference instead.
22 */
23 int device_add(struct device *dev)
24 {
25 struct device *parent = NULL;
26 struct kobject *kobj;
27 struct class_interface *class_intf;
28 int error = -EINVAL;
29
30 dev = get_device(dev);//增加設備的引用計數 dev->kobj->kref
31 if (!dev)
32 goto done;
33
34 if (!dev->p) {
35 error = device_private_init(dev);//私有數據沒有的話申請並初始化,這個數據很重要,它是連接所屬bus,parent,對應驅動等的重要連接點.
36 if (error)
37 goto done;
38 }
39
40 /*
41 * for statically allocated devices, which should all be converted
42 * some day, we need to initialize the name. We prevent reading back
43 * the name, and force the use of dev_name()
44 */
45 if (dev->init_name) {
46 dev_set_name(dev, "%s", dev->init_name);//用dev的init_name初始化dev-kobject->name,實際就是目錄名。
47 dev->init_name = NULL;
48 }
49
50 /* subsystems can specify simple device enumeration */
51 if (!dev_name(dev) && dev->bus && dev->bus->dev_name)//dev的init_name不存在且dev-kobject->name也不存在,則使用bus的dev_name和dev_id來設置目錄名
52 dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);
53
54 if (!dev_name(dev)) //如果上面幾個步驟都還沒找到可設的目錄名,則失敗返回,設備必須要放在某個目錄下。
55 error = -EINVAL;
56 goto name_error;
57 }
58
59 pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
60
61 parent = get_device(dev->parent);//父節點引用計數加1
62 kobj = get_device_parent(dev, parent);//拿到父節點
63 if (kobj)
64 dev->kobj.parent = kobj;//拿到的父節點賦值給本dev->kobj.parent,確定設備父子關系,也確定了sysfs中的目錄關系
65
66 /* use parent numa_node */
67 if (parent)
68 set_dev_node(dev, dev_to_node(parent));//設置該設備節點為-1,一般未注冊前在device_initialize已經初始化為-1
69
70 /* first, register with generic layer. */
71 /* we require the name to be set before, and pass NULL */
72 error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);//把內嵌的kobject注冊到設備模型中將設備加入到kobject模型中,創建sys相關目錄,目錄名字為kobj->name
73 if (error)
74 goto Error;
75
76 /* notify platform of device entry */
77 if (platform_notify)
78 platform_notify(dev);
79 /*創建sys目錄下設備的uevent屬性文件,通過它可以查看設備的uevent事件,主要是在/sys/devices/.../中添加dev的uevent屬性文件*/
80 error = device_create_file(dev, &uevent_attr);
81 if (error)
82 goto attrError;
83 /* 主設備號存在,則產生dev屬性,並在/dev目錄下產生設備節點文件 */
84 if (MAJOR(dev->devt)) {
/*創建sys目錄下設備的設備號屬性,即major和minor /主要是在sys/devices/...中添加dev屬性文件*/
85 error = device_create_file(dev, &devt_attr);
86 if (error)
87 goto ueventattrError;
88 /*在/sys/dev/char/或者/sys/dev/block/創建devt的屬性的連接文件,形如10:45,由主設備號和次設備號構成,指向/sys/devices/.../的具體設備目錄*/
89 error = device_create_sys_dev_entry(dev);//該鏈接文件只具備讀屬性,顯示主設備號:次設備號,如10:45,用戶空間udev響應uevent事件時,將根據設備號在/dev下創建節點文件
90 if (error)
91 goto devtattrError;
92
93 devtmpfs_create_node(dev);
94 }
95 /*實際創建的kobject都是在device下面,其他class,bus之類的里面的具體設備都是device目錄下設備的符號鏈接,這里是在class下創建符號鏈接 */
96 error = device_add_class_symlinks(dev);
97 if (error)
98 goto SymlinkError;
99 error = device_add_attrs(dev);//創建sys目錄下設備其他屬性文件(添加設備屬性文件)
100 if (error)
101 goto AttrsError;
102 error = bus_add_device(dev);//添加設備的總線屬性,將設備加入到管理它的bus總線的設備連表上,創建subsystem鏈接文件,鏈接class下的具體的子系統文件夾 將設備添加到其總線的設備列表中。
103 if (error)
104 goto BusError;
105 error = dpm_sysfs_add(dev);//把設備增加到sysfs電源管理power目錄(組)下,如果該設備設置電源管理相關的內容
106 if (error)
107 goto DPMError;
108 device_pm_add(dev);//設備添加到電源管理相關的設備列表中
109
110 /* Notify clients of device addition. This call must come
111 * after dpm_sysfs_add() and before kobject_uevent().
112 */
113 if (dev->bus)//通知客戶端,有新設備加入
114 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
115 BUS_NOTIFY_ADD_DEVICE, dev);
116 /*產生一個內核uevent事件(這里是有設備加入),可以是helper,也可是通過netlink機制和用戶空間通信該事件可以被內核以及應用層捕獲,屬於linux設備模型中熱插拔機制*/
117 kobject_uevent(&dev->kobj, KOBJ_ADD);
118 bus_probe_device(dev);//給設備探測尋找相對應的驅動,在bus上找dev對應的drv,主要執行__device_attach,主要進行match,sys_add,執行probe函數和綁定等操作
119 if (parent)
120 klist_add_tail(&dev->p->knode_parent,//添加新設備到父設備的子列表中
121 &parent->p->klist_children);
122
123 if (dev->class) {//如果改dev有所屬類,則將dev的添加到類的設備列表里面
124 mutex_lock(&dev->class->p->mutex);//要使用class的互斥鎖
125 /* tie the class to the device */
126 klist_add_tail(&dev->knode_class,//dev添加到class的klist_device鏈表(對driver也有klist_driver鏈表)
127 &dev->class->p->klist_devices);
128 /*通知有新設備加入,執行該dev的class_intf->add_dev(),好處是只有設備匹配注冊成功了,才進行其它的注冊工作(如字符設備的注冊,生成/dev/***節點文件)以及部分初始化工作。*/
129 /* notify any interfaces that the device is here */
130 list_for_each_entry(class_intf,
131 &dev->class->p->interfaces, node)
132 if (class_intf->add_dev)
133 class_intf->add_dev(dev, class_intf);
134 mutex_unlock(&dev->class->p->mutex);
135 }
136 done:
137 put_device(dev);
138 return error;
139 DPMError:
140 bus_remove_device(dev);
141 BusError:
142 device_remove_attrs(dev);
143 AttrsError:
144 device_remove_class_symlinks(dev);
145 SymlinkError:
146 if (MAJOR(dev->devt))
147 devtmpfs_delete_node(dev);
148 if (MAJOR(dev->devt))
149 device_remove_sys_dev_entry(dev);
150 devtattrError:
151 if (MAJOR(dev->devt))
152 device_remove_file(dev, &devt_attr);
153 ueventattrError:
154 device_remove_file(dev, &uevent_attr);
155 attrError:
156 kobject_uevent(&dev->kobj, KOBJ_REMOVE);
157 kobject_del(&dev->kobj);
158 Error:
159 cleanup_device_parent(dev);
160 if (parent)
161 put_device(parent);
162 name_error:
163 kfree(dev->p);
164 dev->p = NULL;
165 goto done;
166 }
5 device_private_init
初始化私有數據,很重要的一個數據,它是連接所屬bus、parent和對應驅動等的重要連接橋梁。
1 int device_private_init(struct device *dev) 2 { 3 dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); 4 if (!dev->p) 5 return -ENOMEM; 6 dev->p->device = dev;//暫時只明確它是那個設備,先把自己綁定進去,后面再加如bus,driver之類 7 klist_init(&dev->p->klist_children, klist_children_get, 8 klist_children_put); 9 INIT_LIST_HEAD(&dev->p->deferred_probe); 10 return 0; 11 }
6 bus_add_device
將新建設備添加到對應的bus上。
1 /** 2 * bus_add_device - add device to bus 3 * @dev: device being added 4 * 5 * - Add device's bus attributes. 6 * - Create links to device's bus. 7 * - Add the device to its bus's list of devices. 8 */ 9 int bus_add_device(struct device *dev) 10 { 11 struct bus_type *bus = bus_get(dev->bus);//拿到device對應的總線,且把總線引用計數加1 12 int error = 0; 13 14 if (bus) { 15 pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev)); 16 error = device_add_attrs(bus, dev);//創建添加相應屬性 17 if (error) 18 goto out_put; 19 error = sysfs_create_link(&bus->p->devices_kset->kobj, 20 &dev->kobj, dev_name(dev));//在sys/bus/總線類型/devices/目錄下,創建名字為dev_name的符號鏈接,指向sys/devices/相同設備名字(前面創建了class目錄下的,這創建bus目錄下的符號鏈接) 21 if (error) 22 goto out_id; 23 error = sysfs_create_link(&dev->kobj,//在sys/devices/分類/設備名字/目錄下創建目錄名字為subsystem的符號鏈接,並且指向在sys/bus/總線類型 24 &dev->bus->p->subsys.kobj, "subsystem"); 25 if (error) 26 goto out_subsys; 27 klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);//設備加到總線鏈表中 28 } 29 return 0; 30 31 out_subsys: 32 sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev)); 33 out_id: 34 device_remove_attrs(bus, dev); 35 out_put: 36 bus_put(dev->bus); 37 return error; 38 }
7 bus_probe_device
1 /** 2 * bus_probe_device - probe drivers for a new device 3 * @dev: device to probe 4 * 5 * - Automatically probe for a driver if the bus allows it. 6 */ 7 void bus_probe_device(struct device *dev) 8 { 9 struct bus_type *bus = dev->bus; 10 struct subsys_interface *sif; 11 int ret; 12 13 if (!bus) 14 return;//確定總線存在,否則出錯返回 15 /*drivers_autoprobe是一個bit變量,為l則允許本條總線上的device注冊時自動匹配driver,drivers_autoprobe默認總是為1,除非用戶空間修改*/ 16 if (bus->p->drivers_autoprobe) { 17 ret = device_attach(dev);//匹配設備和驅動 18 WARN_ON(ret < 0); 19 } 20 21 mutex_lock(&bus->p->mutex); 22 list_for_each_entry(sif, &bus->p->interfaces, node) 23 if (sif->add_dev) 24 sif->add_dev(dev, sif); 25 mutex_unlock(&bus->p->mutex); 26 }
8 device_attach
兩種情況:
1)默認注冊的device自帶有驅動,只需要調用device_bind_driver綁定,不需要匹配。
2)如果沒有帶有驅動,則需要后面遍歷總線,調用匹配函數__device_attach分析匹配對應的驅動
1 /** 2 * device_attach - try to attach device to a driver. 3 * @dev: device. 4 * 5 * Walk the list of drivers that the bus has and call 6 * driver_probe_device() for each pair. If a compatible 7 * pair is found, break out and return. 8 * 9 * Returns 1 if the device was bound to a driver; 10 * 0 if no matching driver was found; 11 * -ENODEV if the device is not registered. 12 * 13 * When called for a USB interface, @dev->parent lock must be held. 14 */ 15 int device_attach(struct device *dev) 16 { 17 int ret = 0; 18 19 device_lock(dev); 20 if (dev->driver) {//driver已經放在device了(初始化device,時,手動添加的driver) 21 if (klist_node_attached(&dev->p->knode_driver)) { 22 ret = 1; 23 goto out_unlock; 24 } 25 ret = device_bind_driver(dev);//driver放在device里了,但還沒真正的綁定 ,則執行這個函數綁定 26 if (ret == 0) 27 ret = 1; 28 else { 29 dev->driver = NULL; 30 ret = 0; 31 } 32 } else {//剛注冊的device,沒有添加對應的driver,需要查找匹配對應的驅動 33 ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);//遍歷總線上的driver鏈表,一個一個進行匹配 34 pm_request_idle(dev); 35 } 36 out_unlock: 37 device_unlock(dev); 38 return ret; 39 }
8.1 device_bind_driver
device上有driver,只需綁定即可。
1 /**
2 * device_bind_driver - bind a driver to one device.
3 * @dev: device.
4 *
5 * Allow manual attachment of a driver to a device.
6 * Caller must have already set @dev->driver.
7 *
8 * Note that this does not modify the bus reference count
9 * nor take the bus's rwsem. Please verify those are accounted
10 * for before calling this. (It is ok to call with no other effort
11 * from a driver's probe() method.)
12 *
13 * This function must be called with the device lock held.
14 */
15 int device_bind_driver(struct device *dev)
16 {
17 int ret;
18
19 ret = driver_sysfs_add(dev);//把dev和driver鏈接起來
20 if (!ret)
21 driver_bound(dev);//device里面私有的driver節點掛接到driver的設備鏈表(一個driver可能對應多個device)
22 return ret;
23 }
24
25 static int driver_sysfs_add(struct device *dev)
26 {
27 int ret;
28
29 if (dev->bus)
30 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,//通知其它總線將要綁定driver 到device
31 BUS_NOTIFY_BIND_DRIVER, dev);
32
33 ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,
34 kobject_name(&dev->kobj));//在driver目錄下創建device目錄的符號鏈接,名字為設備的名字
35 if (ret == 0) {
36 ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,
37 "driver");//在device目錄下創建driver的目錄,名字為driver
38 if (ret)
39 sysfs_remove_link(&dev->driver->p->kobj,
40 kobject_name(&dev->kobj));
41 }
42 return ret;
43 }
44
45 static void driver_bound(struct device *dev)
46 {
47 if (klist_node_attached(&dev->p->knode_driver)) {//再次檢查,確定沒綁定
48 printk(KERN_WARNING "%s: device %s already bound\n",
49 __func__, kobject_name(&dev->kobj));
50 return;
51 }
52
53 pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev),
54 __func__, dev->driver->name);
55 /* 綁定!!!!!! 把device私有的p里的knode_driver,綁定到driver里面的klist_device鏈表上 */
56 klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices);
57
58 /*
59 * Make sure the device is no longer in one of the deferred lists and
60 * kick off retrying all pending devices
61 */
62 driver_deferred_probe_del(dev);
63 driver_deferred_probe_trigger();
64
65 if (dev->bus)//通知其它子模塊以及綁定成功
66 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
67 BUS_NOTIFY_BOUND_DRIVER, dev);
68 }
8.2 bus_for_each_drv(dev->bus, NULL, dev, __device_attach)
如果設備沒有對應的驅動,則需要遍歷總線上的driver鏈表,一個一個進行匹配。
1 /** 2 * bus_for_each_drv - driver iterator 3 * @bus: bus we're dealing with. 4 * @start: driver to start iterating on. 5 * @data: data to pass to the callback. 6 * @fn: function to call for each driver. 7 * 8 * This is nearly identical to the device iterator above. 9 * We iterate over each driver that belongs to @bus, and call 10 * @fn for each. If @fn returns anything but 0, we break out 11 * and return it. If @start is not NULL, we use it as the head 12 * of the list. 13 * 14 * NOTE: we don't return the driver that returns a non-zero 15 * value, nor do we leave the reference count incremented for that 16 * driver. If the caller needs to know that info, it must set it 17 * in the callback. It must also be sure to increment the refcount 18 * so it doesn't disappear before returning to the caller. 19 */ 20 int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, 21 void *data, int (*fn)(struct device_driver *, void *)) 22 { 23 struct klist_iter i; 24 struct device_driver *drv; 25 int error = 0; 26 27 if (!bus) 28 return -EINVAL; 29 30 klist_iter_init_node(&bus->p->klist_drivers, &i, 31 start ? &start->p->knode_bus : NULL); 32 while ((drv = next_driver(&i)) && !error) 33 error = fn(drv, data); 34 klist_iter_exit(&i); 35 return error; 36 } 37 38 static int __device_attach(struct device_driver *drv, void *data) 39 { 40 struct device *dev = data; 41 42 if (!driver_match_device(drv, dev)) 43 return 0; 44 45 return driver_probe_device(drv, dev); 46 }
8.3 __device_attach
1 static int __device_attach(struct device_driver *drv, void *data) 2 { 3 struct device *dev = data; 4 5 if (!driver_match_device(drv, dev))//確認匹配成功 6 return 0; 7 8 return driver_probe_device(drv, dev);//調用probe函數 9 } 10 11 static inline int driver_match_device(struct device_driver *drv, 12 struct device *dev) 13 { 14 return drv->bus->match ? drv->bus->match(dev, drv) : 1; 15 } 16 17 /** 18 * driver_probe_device - attempt to bind device & driver together 19 * @drv: driver to bind a device to 20 * @dev: device to try to bind to the driver 21 * 22 * This function returns -ENODEV if the device is not registered, 23 * 1 if the device is bound successfully and 0 otherwise. 24 * 25 * This function must be called with @dev lock held. When called for a 26 * USB interface, @dev->parent lock must be held as well. 27 */ 28 int driver_probe_device(struct device_driver *drv, struct device *dev) 29 { 30 int ret = 0; 31 32 if (!device_is_registered(dev))//通過查看在sysfs中的狀態判斷是都已經注冊 33 return -ENODEV; 34 35 pr_debug("bus: '%s': %s: matched device %s with driver %s\n", 36 drv->bus->name, __func__, dev_name(dev), drv->name); 37 38 pm_runtime_barrier(dev); 39 ret = really_probe(dev, drv);//真正的probe函數 40 pm_request_idle(dev); 41 42 return ret; 43 }
8.4 really_probe
source code位於:drivers\base\dd.c
1 static int really_probe(struct device *dev, struct device_driver *drv) 2 { 3 int ret = 0; 4 int local_trigger_count = atomic_read(&deferred_trigger_count); 5 6 atomic_inc(&probe_count); 7 pr_debug("bus: '%s': %s: probing driver %s with device %s\n", 8 drv->bus->name, __func__, drv->name, dev_name(dev)); 9 WARN_ON(!list_empty(&dev->devres_head)); 10 11 dev->driver = drv;//匹配好后的驅動信息記錄到設備內部 12 13 /* If using pinctrl, bind pins now before probing */ 14 ret = pinctrl_bind_pins(dev); 15 if (ret) 16 goto probe_failed; 17 18 if (driver_sysfs_add(dev)) {//driver加入sysfs(其實就是創建各種符號鏈接,前面device默認綁定有driver那里已經分析過了) 19 printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", 20 __func__, dev_name(dev)); 21 goto probe_failed; 22 } 23 24 if (dev->bus->probe) {//如果總線上定義probe函數則調用 25 ret = dev->bus->probe(dev); 26 if (ret) 27 goto probe_failed; 28 } else if (drv->probe) {//否則調用驅動上的probe函數 29 ret = drv->probe(dev); 30 if (ret) 31 goto probe_failed; 32 } 33 34 driver_bound(dev);//將設備加入到驅動支持的設備鏈表中,一個設備需要一個驅動,一個驅動支持多個設備,前面device默認綁定driver那里已經分析過了 35 ret = 1; 36 pr_debug("bus: '%s': %s: bound device %s to driver %s\n", 37 drv->bus->name, __func__, dev_name(dev), drv->name); 38 goto done; 39 40 probe_failed: 41 devres_release_all(dev); 42 driver_sysfs_remove(dev); 43 dev->driver = NULL; 44 dev_set_drvdata(dev, NULL); 45 46 if (ret == -EPROBE_DEFER) { 47 /* Driver requested deferred probing */ 48 dev_info(dev, "Driver %s requests probe deferral\n", drv->name); 49 driver_deferred_probe_add(dev); 50 /* Did a trigger occur while probing? Need to re-trigger if yes */ 51 if (local_trigger_count != atomic_read(&deferred_trigger_count)) 52 driver_deferred_probe_trigger(); 53 } else if (ret != -ENODEV && ret != -ENXIO) { 54 /* driver matched but the probe failed */ 55 printk(KERN_WARNING 56 "%s: probe of %s failed with error %d\n", 57 drv->name, dev_name(dev), ret); 58 } else { 59 pr_debug("%s: probe of %s rejects match %d\n", 60 drv->name, dev_name(dev), ret); 61 } 62 /* 63 * Ignore errors returned by ->probe so that the next driver can try 64 * its luck. 65 */ 66 ret = 0; 67 done: 68 atomic_dec(&probe_count); 69 wake_up(&probe_waitqueue); 70 return ret; 71 }
2總結
上面API的一層層的嵌套,看完之后有點蒙,最后整體總結下,整體的調用過程如下:
device_create()
device_create_vargs();//新建結構體dev
kobject_set_name_vargs();
device_register();
device_initialize();
device_add();
device_register(struct device *dev)
device_initialize(); /* 初始化通用數據結構 */
device_add(); /* 加入到該dev所屬bus上 */
device_initialize(struct device *dev)
kobject_init();
INIT_LIST_HEAD(&dev->dma_pools);
INIT_LIST_HEAD(&dev->devres_head);
device_pm_init();
set_dev_node();
device_add()//把設備加到對應的bus上
get_device();
device_private_init();
dev_set_name();//用dev的init_name初始化dev-kobject->name即目錄名
!dev_name(dev) && dev->bus && dev->bus->dev_name;
get_device(dev->parent);//父節點的引用計數加1
get_device_parent();//找到其父類
kobject_add();//把內嵌的kobject注冊到設備模型中,在sys下建目錄kobj->name
platform_notify();//如果platform_notify定義的話,通知平台設備,一般不用
device_create_file();//創建sys目錄下設備的uevent屬性文件
device_create_file();//創建sys目錄下設備的設備號屬性,即major和minor /主要是在sys/devices/...中添加dev屬性文件.
device_create_sys_dev_entry();//在/sys/dev/char/或者/sys/dev/block/創建devt的屬性的連接文件,形如10:45,由主設備號和次設備號構成,指向/sys/devices/.../的具體設備目錄,該鏈接文件只具備讀屬性,顯示主設備號:次設備號,如10:45,用戶空間udev響應uevent事件時,將根據設備號在/dev下創建節點文件
device_add_class_symlinks();//實際創建的kobject都是在device下面,其他class,bus之類的里面的具體設備都是device目錄下設備的符號鏈接,這里是在class下創建符號鏈接.
device_add_attrs();//創建sys目錄下設備其他屬性文件(添加設備屬性文件)
bus_add_device();//添加設備的總線屬性 將設備加入到管理它的bus總線的設備連表上 創建subsystem鏈接文件,鏈接class下的具體的子系統文件夾 將設備添加到其總線的設備列表中。
dpm_sysfs_add();//把設備增加到sysfs電源管理power目錄(組)下,如果該設備設置電源管理相關的內容.
device_pm_add();//設備添加到電源管理相關的設備列表中
blocking_notifier_call_chain();//通知客戶端,有新設備加入
kobject_uevent();//產生一個內核uevent事件(這里是有設備加入),可以是helper,也可是通過netlink機制和用戶空間通信該事件可以被內核以及應用層捕獲,屬於linux設備模型中熱插拔機制.
bus_probe_device();在bus上匹配dev對應的drv。
klist_add_tail();//將設備添加到其父設備的子列表中
klist_add_tail()//將dev添加到class的klist_device鏈表(對driver有klist_driver鏈表)
list_for_each_entry();
add_dev(dev, class_intf);//通知有新設備加入,執行該dev的class_intf->add_dev(),只有設備匹配注冊成功了,才進行其它的注冊工作(如字符設備的注冊,生成/dev/***節點文件)以及部分初始化工作.
device_private_init(struct device *dev)
kzalloc(dev->p);
klist_init();
INIT_LIST_HEAD();
bus_add_device(struct device *dev)
bus_get();//對總線的引用計數加1
device_add_attrs(); //創建相應的屬性文件
device_add_groups();//增加到組中,就是再加一層目錄封裝
sysfs_create_link();//在sys/bus/總線類型/devices/目錄下,創建名字為devname(d)指向sys/devices/相同設備名字的符號鏈接(前面創建了class目錄下的,這創建bus目錄下的符號鏈接)
sysfs_create_link();//在sys/devices/分類/設備名字/目錄下創建目錄名字為 subsystem 並且指向在sys/bus/總線類型 的符號鏈接
klist_add_tail();//把設備加入到總線的設備鏈中
bus_probe_device(struct device *dev)
device_attach();//if (bus->p->drivers_autoprobe),drivers_autoprobe是一個bit變量,為l則允許本條總線上的device注冊時自動匹配driver。drivers_autoprobe默認總是為1,除非用戶空間修改 */
list_for_each_entry();
add_dev();
device_attach(struct device *dev)
klist_node_attached();
device_bind_driver();
driver_sysfs_add(dev);//把dev和driver鏈接起來
blocking_notifier_call_chain();//通知其它總線將要綁定driver 到device
sysfs_create_link(&dev->driver->p->kobj,&dev->kobj,kobject_name(&dev->kobj);在driver目錄下創建device目錄的符號鏈接,名字為設備的名字
sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,"driver");//在device目錄下創建driver的目錄,名字為driver
driver_bound(dev);//device里面私有的driver節點掛接到driver的設備鏈表,一個driver可能對應多個device
klist_add_tail();//把device私有的p里的knode_driver,綁定到driver里面的klist_device鏈表上
blocking_notifier_call_chain();//通知其它子模塊以及綁定成功
bus_for_each_drv();
__device_attach();
driver_match_device();//drv和dev匹配成功的話,才會往下執行的probe函數
drv->bus->match(dev, drv) ;//drv對應的bus存在的話,call此bus的match函數
driver_probe_device();
device_is_registered();//確定設備已注冊
pm_runtime_barrier();//電源管理
really_probe();//調用驅動的probe函數
dev->driver = drv;//匹配好后的驅動信息記錄到設備內部
driver_sysfs_add(); //driver加入sysfs,就是創建各種符號鏈接
dev->bus->probe(); //若bus的probe函數存在,則執行bus的probe drv->probe();// 否則,指向device的probe函數
driver_bound();//將設備加入到驅動支持的設備鏈表中,一個設備需要一個驅動,一個驅動支持多個設備,前面device默認綁定driver那里已經分析過了 */
pm_request_idle();
pm_request_idle(dev);
參考博文:https://blog.csdn.net/qq_16777851/java/article/details/81437352