linux設備驅動(2)device詳解


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


免責聲明!

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



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