歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux設備模型之bus,device,driver分析

Linux設備模型之bus,device,driver分析

日期:2017/2/28 15:58:19   编辑:Linux教程
內核的開發者將總線,設備,驅動這三者用軟件思想抽象了出來,巧妙的建立了其間的關系,使之更形象化。結合前面所學的知識,總的來說其三者間的關系為bus有兩條鏈表,分別用於掛接設備和驅動,指定了其自身bus的device或者driver最後都會分別連接到對應bus的這兩條鏈表上,而總線又有其始端,為bus_kset,一個driver可以對應於幾個設備,因此driver同樣有其設備鏈表,用於掛接可以操作的設備,其自身也有bus掛接點,用於將自身掛接到對應bus(每個driver只屬於一條總線),而對於device,一個設備只屬於一條總線,只能有一個driver與其對應,因此對於device,都是單一的,一個driver掛接點,一個bus掛接點,device與bus相同的是都有始端,device為devices_kset,因此device的注冊同時會出現在對應的bus目錄和device總目錄下。好了,下面就以源碼為例分別分析一下bus,device,driver的注冊過程。

一、bus的注冊

bus的注冊比較簡單,首先來看一下bus的結構:

[cpp]

  1. struct bus_type {
  2. const char *name; //名字
  3. struct bus_attribute *bus_attrs; //bus屬性集
  4. struct device_attribute *dev_attrs; //device屬性集
  5. struct driver_attribute *drv_attrs; //driver屬性集
  6. int (*match)(struct device *dev, struct device_driver *drv);
  7. int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
  8. int (*probe)(struct device *dev);
  9. int (*remove)(struct device *dev);
  10. void (*shutdown)(struct device *dev);
  11. int (*suspend)(struct device *dev, pm_message_t state);
  12. int (*resume)(struct device *dev);
  13. const struct dev_pm_ops *pm;
  14. struct bus_type_private *p; //bus的私有成員
  15. };
  16. //其中重點看一下私有成員結構體:
  17. struct bus_type_private {
  18. struct kset subsys; //bus內嵌的kset,代表其自身
  19. struct kset *drivers_kset;
  20. struct kset *devices_kset;
  21. struct klist klist_devices; //包含devices鏈表及其操作函數
  22. struct klist klist_drivers; //driver鏈表及其操作函數
  23. struct blocking_notifier_head bus_notifier;
  24. unsigned int drivers_autoprobe:1; //匹配成功自動初始化標志
  25. struct bus_type *bus;
  26. };

無論是bus,driver,還是device其本身特征都放在私有成員裡,其注冊時,都會申請並填充這個結構體,下面具體分析一下bus的注冊流程,從bus_register開始:

[cpp]

  1. int bus_register(struct bus_type *bus)
  2. {
  3. int retval;
  4. struct bus_type_private *priv;
  5. priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL); //進入時bus_type->bus_type_private為NULL
  6. if (!priv) //該函數主要是對其的設置
  7. return -ENOMEM;
  8. priv->bus = bus; //私有成員的bus回指該bus
  9. bus->p = priv; //初始化bus->p,即其私有屬性
  10. BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
  11. retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); //設置該bus的名字,bus是kset的封裝
  12. if (retval)
  13. goto out;
  14. //bus_kset即為所有bus的總起始端點
  15. //圍繞bus內嵌的kset初始化,和kset的初始化時圍繞
  16. priv->subsys.kobj.kset = bus_kset; //kobj相似,沒有parent時,就會用kset的kobj,此處即是
  17. priv->subsys.kobj.ktype = &bus_ktype; //屬性操作級別統一為bus_ktype
  18. priv->drivers_autoprobe = 1; //設置該標志,當有driver注冊時,會自動匹配devices
  19. //上的設備並用probe初始化,
  20. //當有device注冊時也同樣找到 driver並會初始化
  21. retval = kset_register(&priv->subsys); //注冊kset,創建目錄結構,以及層次關系
  22. if (retval)
  23. goto out;
  24. retval = bus_create_file(bus, &bus_attr_uevent); //當前bus目錄下生成bus_attr_uevent屬性文件
  25. if (retval)
  26. goto bus_uevent_fail;
  27. priv->devices_kset = kset_create_and_add("devices", NULL, //初始化bus目錄下的devices目錄,裡面級聯了該bus下設備,
  28. &priv->subsys.kobj); //仍然以kset為原型
  29. if (!priv->devices_kset) {
  30. retval = -ENOMEM;
  31. goto bus_devices_fail;
  32. }
  33. priv->drivers_kset = kset_create_and_add("drivers", NULL, //初始化bus目錄下的drivers目錄,裡面級聯了該bus下設備的driver
  34. &priv->subsys.kobj);
  35. if (!priv->drivers_kset) {
  36. retval = -ENOMEM;
  37. goto bus_drivers_fail;
  38. }
  39. klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); //初始化klist_devices裡的操作函數成員
  40. klist_init(&priv->klist_drivers, NULL, NULL); //klist_drivers裡的操作函數置空
  41. retval = add_probe_files(bus); //增加bus_attr_drivers_probe和bus_attr_drivers_autoprobe
  42. if (retval) //屬性文件
  43. goto bus_probe_files_fail;
  44. retval = bus_add_attrs(bus); //增加默認的屬性文件
  45. if (retval)
  46. goto bus_attrs_fail;
  47. pr_debug("bus: '%s': registered/n", bus->name);
  48. return 0;
  49. bus_attrs_fail: //以下為錯誤處理
  50. remove_probe_files(bus);
  51. bus_probe_files_fail:
  52. kset_unregister(bus->p->drivers_kset);
  53. bus_drivers_fail:
  54. kset_unregister(bus->p->devices_kset);
  55. bus_devices_fail:
  56. bus_remove_file(bus, &bus_attr_uevent);
  57. bus_uevent_fail:
  58. kset_unregister(&bus->p->subsys);
  59. out:
  60. kfree(bus->p);
  61. bus->p = NULL;
  62. return retval;
  63. }

由此可見,bus又是kset的封裝,bus_register主要完成了其私有成員bus_type_private的初始化,並初始化了其下的兩個目錄devices和drivers,及其屬性文件,bus有個自己的根目錄也就是bus有個起始端點,是bus_kset,經過此番的注冊,bus目錄下將會出現我們注冊的bus,並且其下會有device和driver兩個子目錄,代表它下面的driver和device鏈表。

二、driver的注冊

下面看一下driver是怎麼和bus關聯起來的,首先看下driver的結構:

[cpp]

  1. struct device_driver {
  2. const char *name; //名字
  3. struct bus_type *bus; //其所在的bus
  4. struct module *owner;
  5. const char *mod_name; /* used for built-in modules */
  6. bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
  7. #if defined(CONFIG_OF)
  8. const struct of_device_id *of_match_table;
  9. #endif
  10. int (*probe) (struct device *dev); //匹配成功時可能會調用到的函數
  11. int (*remove) (struct device *dev);
  12. void (*shutdown) (struct device *dev);
  13. int (*suspend) (struct device *dev, pm_message_t state);
  14. int (*resume) (struct device *dev);
  15. const struct attribute_group **groups;
  16. const struct dev_pm_ops *pm;
  17. struct driver_private *p; //私有成員,表示driver
  18. };
  19. //重點看下driver的私有成員
  20. struct driver_private {
  21. struct kobject kobj; //代表driver自身
  22. struct klist klist_devices; //可以操控的設備鏈表
  23. struct klist_node knode_bus; //掛接到bus的節點
  24. struct module_kobject *mkobj; //模塊相關
  25. struct device_driver *driver; //回指該driver
  26. };

如同bus一樣,重點的仍是可以代表其自身的私有屬性,下面具體看一下driver的注冊過程,從driver_register開始:

[cpp]

  1. int driver_register(struct device_driver *drv)
  2. {
  3. int ret;
  4. struct device_driver *other;
  5. BUG_ON(!drv->bus->p);
  6. if ((drv->bus->probe && drv->probe) || //driver和bus的同名操作函數如果同時存在,會出現警告
  7. (drv->bus->remove && drv->remove) || //並且會優先選用bus的
  8. (drv->bus->shutdown && drv->shutdown))
  9. printk(KERN_WARNING "Driver '%s' needs updating - please use "
  10. "bus_type methods/n", drv->name);
  11. other = driver_find(drv->name, drv->bus); //進入bus的driver鏈表,確認該driver是否已經注冊
  12. if (other) {
  13. put_driver(other); //找到了再減少引用計數,並且報錯退出
  14. printk(KERN_ERR "Error: Driver '%s' is already registered, "
  15. "aborting.../n", drv->name);
  16. return -EBUSY;
  17. }
  18. ret = bus_add_driver(drv); //如果沒有注冊,那麼把該driver加入所在bus
  19. if (ret)
  20. return ret;
  21. ret = driver_add_groups(drv, drv->groups);
  22. if (ret)
  23. bus_remove_driver(drv);
  24. return ret;
  25. }
  26. /****************************************************
  27. × 跟蹤一下driver_find(drv->name, drv->bus)
  28. ****************************************************/
  29. struct device_driver *driver_find(const char *name, struct bus_type *bus)
  30. {
  31. struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); //bus->p->drivers_kset代表bus下
  32. struct driver_private *priv; //的driver目錄,此處會遍歷bus的
  33. //driver鏈表,通過driver內嵌的
  34. if (k) { //kobj名字比較
  35. priv = to_driver(k);
  36. return priv->driver; //如果找到同名的kobj那麼返回該driver
  37. }
  38. return NULL;
  39. }
  40. //看一下kset_find_obj吧:
  41. struct kobject *kset_find_obj(struct kset *kset, const char *name)
  42. {
  43. struct kobject *k;
  44. struct kobject *ret = NULL;
  45. spin_lock(&kset->list_lock);
  46. list_for_each_entry(k, &kset->list, entry) { //遍歷bus下的driver鏈表,如果
  47. if (kobject_name(k) && !strcmp(kobject_name(k), name)) { //找到那麼返回找到的kobj,並且把
  48. ret = kobject_get(k); //該driver的kobj引用計數+1
  49. break;
  50. }
  51. }
  52. spin_unlock(&kset->list_lock);
  53. return ret;
  54. }
  55. /************************************************
  56. × 再來跟蹤一下driver_register裡面的另外一個函數
  57. × bus_add_driver(drv)
  58. ************************************************/
  59. int bus_add_driver(struct device_driver *drv)
  60. {
  61. struct bus_type *bus;
  62. struct driver_private *priv;
  63. int error = 0;
  64. bus = bus_get(drv->bus); //取得其所在bus的指針
  65. if (!bus)
  66. return -EINVAL;
  67. pr_debug("bus: '%s': add driver %s/n", bus->name, drv->name); //開始初始化這個driver的私有成員,
  68. //和bus類似
  69. priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  70. if (!priv) {
  71. error = -ENOMEM;
  72. goto out_put_bus;
  73. }
  74. klist_init(&priv->klist_devices, NULL, NULL); //設備操作函數清空,設備鏈表初始化
  75. priv->driver = drv;
  76. drv->p = priv;
  77. priv->kobj.kset = bus->p->drivers_kset; //kset指定到bus下面
  78. error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, //建立層次結構和屬性文件
  79. "%s", drv->name);
  80. if (error)
  81. goto out_unregister;
  82. if (drv->bus->p->drivers_autoprobe) { //bus的自動匹配如果設置為真,
  83. error = driver_attach(drv); //那麼到bus的devices上去匹配設備
  84. if (error)
  85. goto out_unregister;
  86. }
  87. klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); //把driver掛接到bus的driver鏈表
  88. module_add_driver(drv->owner, drv);
  89. error = driver_create_file(drv, &driver_attr_uevent); //以下添加該driver相關屬性文件
  90. if (error) {
  91. printk(KERN_ERR "%s: uevent attr (%s) failed/n",
  92. __func__, drv->name);
  93. }
  94. error = driver_add_attrs(bus, drv);
  95. if (error) {
  96. /* How the hell do we get out of this pickle? Give up */
  97. printk(KERN_ERR "%s: driver_add_attrs(%s) failed/n",
  98. __func__, drv->name);
  99. }
  100. if (!drv->suppress_bind_attrs) {
  101. error = add_bind_files(drv);
  102. if (error) {
  103. /* Ditto */
  104. printk(KERN_ERR "%s: add_bind_files(%s) failed/n",
  105. __func__, drv->name);
  106. }
  107. }
  108. kobject_uevent(&priv->kobj, KOBJ_ADD);
  109. return 0;
  110. out_unregister:
  111. kobject_put(&priv->kobj);
  112. kfree(drv->p);
  113. drv->p = NULL;
  114. out_put_bus:
  115. bus_put(bus);
  116. return error;
  117. }
  118. /****************************************************************
  119. × 接下來就剩下最終要的匹配函數driver_attach(drv)了,我們來看一下:
  120. ****************************************************************/
  121. int driver_attach(struct device_driver *drv) //遍歷bus的設備鏈表找到
  122. { //合適的設備就調用__driver_attach,
  123. return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); //NULL表示從頭開始遍歷
  124. }
  125. //============
  126. int bus_for_each_dev(struct bus_type *bus, struct device *start,
  127. void *data, int (*fn)(struct device *, void *))
  128. {
  129. struct klist_iter i;
  130. struct device *dev;
  131. int error = 0;
  132. if (!bus)
  133. return -EINVAL;
  134. klist_iter_init_node(&bus->p->klist_devices, &i, //進入bus的devices鏈表
  135. (start ? &start->p->knode_bus : NULL));
  136. while ((dev = next_device(&i)) && !error) //設備存在則調用fn即__driver_attach
  137. error = fn(dev, data); //進行匹配
  138. klist_iter_exit(&i);
  139. return error;
  140. }
  141. /*********************************************
  142. × 接著看一下__driver_attach這個函數
  143. *********************************************/
  144. static int __driver_attach(struct device *dev, void *data)
  145. {
  146. struct device_driver *drv = data;
  147. if (!driver_match_device(drv, dev)) //進行匹配
  148. return 0;
  149. if (dev->parent) /* Needed for USB */
  150. device_lock(dev->parent);
  151. device_lock(dev);
  152. if (!dev->driver) //如果設備沒有指定driver
  153. driver_probe_device(drv, dev); //那麼需要初始化匹配到的這個設備
  154. device_unlock(dev);
  155. if (dev->parent)
  156. device_unlock(dev->parent);
  157. return 0;
  158. }
  159. /*********************************************
  160. × 又遇到兩個分支,囧,先看一下driver_match_device
  161. *********************************************/
  162. static inline int driver_match_device(struct device_driver *drv, //bus的match存在就用bus的
  163. struct device *dev) //,否則就直接匹配成功...
  164. { //match通常實現為首先掃描
  165. return drv->bus->match ? drv->bus->match(dev, drv) : 1; //driver支持的id設備表,如果
  166. } //為NULL就用名字進行匹配
  167. /************************************
  168. × 再來看一下driver_probe_device這個函數
  169. ************************************/
  170. int driver_probe_device(struct device_driver *drv, struct device *dev)
  171. {
  172. int ret = 0;
  173. if (!device_is_registered(dev)) //判斷該設備是否已經注冊
  174. return -ENODEV;
  175. pr_debug("bus: '%s': %s: matched device %s with driver %s/n",
  176. drv->bus->name, __func__, dev_name(dev), drv->name);
  177. pm_runtime_get_noresume(dev);
  178. pm_runtime_barrier(dev);
  179. ret = really_probe(dev, drv); //調用really_probe
  180. pm_runtime_put_sync(dev);
  181. return ret;
  182. }
  183. /************************************
  184. × 看一下device_is_registered
  185. ************************************/
  186. static inline int device_is_registered(struct device *dev)
  187. {
  188. return dev->kobj.state_in_sysfs; //在sysfs中表示已經注冊
  189. }
  190. /************************************
  191. × 再看really_probe
  192. ************************************/
  193. static int really_probe(struct device *dev, struct device_driver *drv)
  194. {
  195. int ret = 0;
  196. atomic_inc(&probe_count);
  197. pr_debug("bus: '%s': %s: probing driver %s with device %s/n",
  198. drv->bus->name, __func__, drv->name, dev_name(dev));
  199. WARN_ON(!list_empty(&dev->devres_head));
  200. dev->driver = drv; //device的driver初始化成該driver
  201. if (driver_sysfs_add(dev)) {
  202. printk(KERN_ERR "%s: driver_sysfs_add(%s) failed/n",
  203. __func__, dev_name(dev));
  204. goto probe_failed;
  205. }
  206. //利用probe初始化設備
  207. if (dev->bus->probe) { //如果bus的probe存在就用bus的,
  208. ret = dev->bus->probe(dev); //如果bus的不存在driver的存在
  209. if (ret) //再用driver的
  210. goto probe_failed;
  211. } else if (drv->probe) {
  212. ret = drv->probe(dev);
  213. if (ret)
  214. goto probe_failed;
  215. }
  216. driver_bound(dev); //調用driver_bound進行綁定
  217. ret = 1;
  218. pr_debug("bus: '%s': %s: bound device %s to driver %s/n",
  219. drv->bus->name, __func__, dev_name(dev), drv->name);
  220. goto done;
  221. probe_failed:
  222. devres_release_all(dev);
  223. driver_sysfs_remove(dev);
  224. dev->driver = NULL;
  225. if (ret != -ENODEV && ret != -ENXIO) {
  226. /* driver matched but the probe failed */
  227. printk(KERN_WARNING
  228. "%s: probe of %s failed with error %d/n",
  229. drv->name, dev_name(dev), ret);
  230. }
  231. /*
  232. * Ignore errors returned by ->probe so that the next driver can try
  233. * its luck.
  234. */
  235. ret = 0;
  236. done:
  237. atomic_dec(&probe_count);
  238. wake_up(&probe_waitqueue);
  239. return ret;
  240. }
  241. /**********************************
  242. * 最後跟一下driver_bound(dev)這個函數
  243. **********************************/
  244. static void driver_bound(struct device *dev)
  245. {
  246. if (klist_node_attached(&dev->p->knode_driver)) { //判斷是否已經綁定
  247. printk(KERN_WARNING "%s: device %s already bound/n",
  248. __func__, kobject_name(&dev->kobj));
  249. return;
  250. }
  251. pr_debug("driver: '%s': %s: bound to device '%s'/n", dev_name(dev),
  252. __func__, dev->driver->name);
  253. klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); //將設備添加
  254. //到driver的鏈表
  255. if (dev->bus)
  256. blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
  257. BUS_NOTIFY_BOUND_DRIVER, dev);
  258. }
  259. //all end

總結一下,driver的注冊,主要涉及將自身掛接到bus的driver鏈表,並將匹配到的設備加入自己的device鏈表,並且將匹配到的device的driver成員初始化為該driver,私有屬性的driver節點也掛到driver的設備鏈表下,其中匹配函數是利用利用bus的match函數,該函數通常判斷如果driver有id表,就查表匹配,如果沒有就用driver和device名字匹配。當匹配成功後如果自動初始化標志允許則調用初始化函數probe,bus的probe優先級始終高於driver的。另外注意一點driver是沒有總的起始端點的,driver不是可具體描述的事物。

由於篇幅比較長,device的分析放到下一篇《linux設備模型之bus,device,driver分析<二>》 ^_^!

Copyright © Linux教程網 All Rights Reserved