自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux 驅(qū)動開發(fā) | 驅(qū)動世界里的宏偉建筑

系統(tǒng) Linux
Linux 的 device model 是一個(gè)旨在統(tǒng)一管理所有設(shè)備驅(qū)動的模型。它猶如一棟規(guī)模宏大的建筑:以 kobject、kset、attribute 等作為基本的建筑材料,構(gòu)造出支撐驅(qū)動世界的 bus、device、driver 三大組件,最后通過 sysfs 在各種基礎(chǔ)的建筑材料之間建立彼此的互聯(lián)層次關(guān)系,并向外界提供了與建筑內(nèi)設(shè)施進(jìn)行互動的文件接口。

[[386924]]

本文轉(zhuǎn)載自微信公眾號「嵌入式Hacker」,作者吳偉東Jack。轉(zhuǎn)載本文請聯(lián)系嵌入式Hacker眾號。  

哈嘍,我是老吳。

是否每一個(gè)上進(jìn)的人都會覺得自己還可以再努力一點(diǎn)?

事情到了最后,只要沒達(dá)成目的,總能把失敗的原因歸為 "沒有再努力一點(diǎn)"。

但是,對努力的最大錯(cuò)誤認(rèn)知就是:時(shí)間越長,過程越痛苦,代表我越努力。

想一想,是否有更合理的努力方式?

以下是正文:

  • 一、什么是 device model?
  • 二、device model 的 3 個(gè)核心概念
  • 三、bus、device、driver 是如何關(guān)聯(lián)的?
  • 四、bus、device、driver 最簡單示例
  • 五、小結(jié)
  • 六、相關(guān)參考

一、什么是 device model?

Linux 的 device model 是一個(gè)旨在統(tǒng)一管理所有設(shè)備驅(qū)動的模型。

它猶如一棟規(guī)模宏大的建筑:

以 kobject、kset、attribute 等作為基本的建筑材料,

構(gòu)造出支撐驅(qū)動世界的 bus、device、driver 三大組件,

最后通過 sysfs 在各種基礎(chǔ)的建筑材料之間建立彼此的互聯(lián)層次關(guān)系,并向外界提供了與建筑內(nèi)設(shè)施進(jìn)行互動的文件接口。

device model 有什么作用?

可以將 device 的硬件描述 和 driver 進(jìn)行分離,提升 driver 的代碼復(fù)用率;

可以對 device 進(jìn)行分類;

可以遍歷 device 和 driver;

可以更好地呈現(xiàn)設(shè)備的拓?fù)潢P(guān)系;

可以通過 sysfs 訪問設(shè)備;

可以讓設(shè)備支持熱插拔;

...

為了控制篇幅,本文將重點(diǎn)放在與驅(qū)動工程師關(guān)系最緊密的 bus、device、driver 3 個(gè) 組件。

二、device model 的 3 個(gè)核心概念

device model 里有 3 個(gè)核心的概念:

  • bus
  • device
  • driver

什么是 bus?

bus 代表一種總線,例如 I2C、SPI、Usb 等。

bus 是 Linux 設(shè)備驅(qū)動模型這種建筑的核心框架,系統(tǒng)中的設(shè)備和驅(qū)動都依附在其周圍。

啟動系統(tǒng)后,可以通過 /sys/bus 可以查看系統(tǒng)里當(dāng)前有哪些總線。

bus 由 struct bus_type 來描述:

  1. struct bus_type { 
  2.  const char *name
  3.  const char *dev_name; 
  4.  struct device *dev_root; 
  5.  const struct attribute_group **bus_groups; 
  6.  const struct attribute_group **dev_groups; 
  7.  const struct attribute_group **drv_groups; 
  8.  
  9.  int (*match)(struct device *dev, struct device_driver *drv); 
  10.  int (*uevent)(struct device *dev, struct kobj_uevent_env *env); 
  11.  int (*probe)(struct device *dev); 
  12.  int (*remove)(struct device *dev); 
  13.  void (*shutdown)(struct device *dev); 
  14.  
  15.  ... 
  16.  struct subsys_private *p; 
  17.  struct lock_class_key lock_key; 
  18. }; 

不需要一下子了解各個(gè)成員的作用,用到的時(shí)候再說明。

重點(diǎn)關(guān)注成員:

  • int (*match)(struct device *dev, struct device_driver *drv),用于判斷掛在該 bus 上的設(shè)備和驅(qū)動是否匹配的回調(diào)函數(shù);
  • int (*probe)(struct device *dev),如果 bus 具有探測設(shè)備的能力,則會提供該回調(diào)函數(shù);
  • struct subsys_private *p,用于管理 bus 上的設(shè)備和驅(qū)動的數(shù)據(jù)結(jié)構(gòu);

注冊 bus 的 api:

  1. int bus_register(struct bus_type *bus); 

什么是 device ?

device 代表了某個(gè)設(shè)備。

由 struct device 來描述:

  1. struct device { 
  2.  struct device *parent; 
  3.  struct device_private *p; 
  4.  struct kobject kobj; 
  5.  const char *init_name; 
  6.  const struct device_type *type; 
  7.  struct mutex mutex; 
  8.  struct bus_type *bus; 
  9.  struct device_driver *driver; 
  10.  void *platform_data; 
  11.  void *driver_data; 
  12.     ... 

重點(diǎn)關(guān)注成員:

  • struct kobject kobj,內(nèi)核對象;
  • struct bus_type *bus,設(shè)備所在的總線;
  • struct device_driver *driver,和設(shè)備綁定在一起的驅(qū)動,如果還沒綁定,則為 NULL;

注冊 device 的 api:

  1. int device_register(struct device *dev) 

什么是 driver?

driver 代表了設(shè)備驅(qū)動。

由 struct device_driver 來描述:

  1. struct device_driver { 
  2.  const char *name
  3.  struct bus_type *bus; 
  4.  
  5.  struct module *owner; 
  6.  const char *mod_name; /* used for built-in modules */ 
  7.  
  8.  bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ 
  9.  enum probe_type probe_type; 
  10.  
  11.  const struct of_device_id *of_match_table; 
  12.  const struct acpi_device_id *acpi_match_table; 
  13.  
  14.  int (*probe) (struct device *dev); 
  15.  int (*remove) (struct device *dev); 
  16.  void (*shutdown) (struct device *dev); 
  17.  int (*suspend) (struct device *dev, pm_message_t state); 
  18.  int (*resume) (struct device *dev); 
  19.  const struct attribute_group **groups; 
  20.  
  21.  const struct dev_pm_ops *pm; 
  22.  
  23.  struct driver_private *p; 
  24. }; 

重點(diǎn)關(guān)注成員:

  • struct bus_type *bus;
  • int (*probe) (struct device *dev);

值得一提的是,總線控制器也是一種設(shè)備。

例如 I2C 總線控制器這個(gè)設(shè)備,對應(yīng)的驅(qū)動為 I2C controller driver。

而掛在 I2C 總線上的設(shè)備,對應(yīng)的驅(qū)動為 I2C device driver。

注冊 driver 的 api:

  1. int driver_register(struct device_driver *drv); 

三、bus、device、driver 是如何關(guān)聯(lián)的?

device model 最核心的工作就是維護(hù)這三類抽象的實(shí)例,以及建立它們之間的關(guān)聯(lián)關(guān)系。

bus 如何管理 device 和 driver ?

在 struct bus_type 中有一個(gè) struct subsys_private *p 指針,它負(fù)責(zé)管理掛在 bus 上的所有設(shè)備和驅(qū)動,其定義如下:

  1. struct subsys_private { 
  2.  struct kset subsys; 
  3.  struct kset *devices_kset; 
  4.  struct list_head interfaces; 
  5.  struct mutex mutex; 
  6.  
  7.  struct kset *drivers_kset; 
  8.  struct klist klist_devices; 
  9.  struct klist klist_drivers; 
  10.  struct blocking_notifier_head bus_notifier; 
  11.  unsigned int drivers_autoprobe:1; 
  12.  struct bus_type *bus; 
  13.  
  14.  struct kset glue_dirs; 
  15.  struct class *class; 
  16. }; 

兩個(gè) klist 成員以鏈表的形式將該總線上所有的驅(qū)動與設(shè)備鏈接到一起。

struct kset *drivers_kset 和 struct kset *devices_kset 是在向系統(tǒng)注冊當(dāng)前新總線時(shí)動態(tài)生成的容納該總線上所有驅(qū)動與設(shè)備的 kset。

在內(nèi)核里,用 kobject 來表示一個(gè)對象,kset 則是 kobject set 的縮寫,即內(nèi)核對象集合。

內(nèi)核用 kobject 和 kset 等數(shù)據(jù)結(jié)構(gòu)作為原材料,以實(shí)現(xiàn)面向?qū)ο蟮姆绞綐?gòu)建了 device model 的框架。

最后,device 和 device_driver 的 bus 成員也會指向總線:

device 和 driver 的綁定

無論是通過 device_register() 注冊一個(gè) device 到 bus 上,

還是通過 driver_register() 注冊一個(gè) device_driver 到 bus 上,

都會導(dǎo)致 bus 嘗試執(zhí)行 device 和 driver 的綁定行為。

1. device_register() 觸發(fā)的綁定

注冊 device 時(shí):

  1. int device_register(struct device *dev); 
  2.  device_add(dev); 
  3.   bus_probe_device(dev); 
  4.    __device_attach(dev, true); 

__device_attach(dev, true) 會為 device 遍歷 bus 上的所有 driver:

  1. bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); 
  2.  driver_match_device(drv, dev); 
  3.   drv->bus->match ? drv->bus->match(dev, drv) : 1; 
  4.  driver_probe_device(drv, dev); 

driver_match_device() 通過 bus 里的 match 函數(shù)來判斷是否 device 和 driver 是否匹配,

是否 match 的判斷標(biāo)準(zhǔn)一般是通過 of_match_table 或者是 id_table 作為衡量的標(biāo)準(zhǔn),

以 i2c bus 的 match 函數(shù)為例:

  1. static int i2c_device_match(struct device *dev, struct device_driver *drv) 
  2.  struct i2c_client *client = i2c_verify_client(dev); 
  3.  struct i2c_driver *driver; 
  4.  
  5.  
  6.  /* Attempt an OF style match */ 
  7.  if (i2c_of_match_device(drv->of_match_table, client)) 
  8.   return 1; 
  9.  
  10.  /* Then ACPI style match */ 
  11.  if (acpi_driver_match_device(dev, drv)) 
  12.   return 1; 
  13.  
  14.  driver = to_i2c_driver(drv); 
  15.  
  16.  /* Finally an I2C match */ 
  17.  if (i2c_match_id(driver->id_table, client)) 
  18.   return 1; 
  19.  
  20.  return 0; 

一旦 match 成功,就會調(diào)用 driver_probe_device() 以觸發(fā)探測設(shè)備的行為:

  1. int driver_probe_device(struct device_driver *drv, struct device *dev); 
  2.  really_probe(dev, drv); 
  3.   if (dev->bus->probe) { 
  4.    ret = dev->bus->probe(dev); 
  5.   } else if (drv->probe) { 
  6.    ret = drv->probe(dev); 
  7.   } 

如果 bus 具有探測設(shè)備的能力的話,例如 pci bus, 則會使用 bus->probe() 探測設(shè)備,

否則,使用 driver->probe() 探測設(shè)備,driver 的 probe 操作跟具體的硬件設(shè)備掛鉤。

2. 由 driver_register() 觸發(fā)的綁定

  1. int driver_register(struct device_driver *drv); 
  2.  bus_add_driver(drv); 
  3.   driver_attach(drv); 

driver_attach(drv) 會為 driver 遍歷 bus 上的所有 device:

  1. int driver_attach(struct device_driver *drv); 
  2.  bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); 
  3.   __driver_attach(); 
  4.    driver_match_device(drv, dev); 
  5.    driver_probe_device(drv, dev); 

和 device_register() 一樣,最終都會調(diào)用 driver_match_device(drv, dev),

進(jìn)而通過 bus 里的 match 函數(shù)來判斷是否 device 和 driver 是否匹配。

同樣地,一旦 match 成功,就會調(diào)用 driver_probe_device() 以觸發(fā)探測設(shè)備的行為,后續(xù)的操作和注冊設(shè)備時(shí)是一模一樣的。

3. device 和 drvier 的綁定關(guān)系

前面說了綁定是如何被觸發(fā)的,現(xiàn)在來明確一下綁定的具體操作。

對于能成功匹配的 device 和 driver,兩者之間的關(guān)系是 N 對 1,即可以有多個(gè) device 和 1 個(gè) driver 綁定在一起。

對于 device:

其 driver 成員指向已綁定的 device_driver。

  1. int driver_probe_device(struct device_driver *drv, struct device *dev) 
  2.  really_probe(dev, drv); 
  3.   dev->driver = drv; 

對于 driver:

在 device_driver 里鏈表 klist_devices 保存了該 driver 上已綁定的所有 device。

  1. int driver_probe_device(struct device_driver *drv, struct device *dev) 
  2.  really_probe(dev, drv); 
  3.   driver_bound(dev); 
  4.    klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); 

在 /driver/base/driver.c 中,提供了一些 api,用于遍歷處理 driver 上綁定的所有 device:

  • int driver_for_each_device()
  • struct device *driver_find_device()

四、bus、device、driver 最簡單示例

下面的例子,

構(gòu)造了一個(gè)名為 "simple_bus" 的 bus 實(shí)例。

  1. static int sb_match(struct device *dev, struct device_driver *driver) 
  2.  return !strncmp(dev_name(dev), driver->name, strlen(driver->name)); 
  3.  
  4. struct bus_type sb_bus_type = { 
  5.  .name = "sb"
  6.  .match = sb_match, 
  7. }; 
  8.  
  9. static ssize_t version_show(struct bus_type *bus, char *buf) 
  10.  return snprintf(buf, PAGE_SIZE, "%s\n", Version); 
  11.  
  12. static BUS_ATTR_RO(version); 
  13.  
  14. static void sb_dev_release(struct device *dev) 
  15. { } 
  16.  
  17. int register_sb_device(struct sb_device *sbdev) 
  18.     sbdev->dev.bus = &sb_bus_type; 
  19.  sbdev->dev.release = sb_dev_release; 
  20.     dev_set_name(&sbdev->dev, sbdev->name); 
  21.     return device_register(&sbdev->dev); 
  22. EXPORT_SYMBOL(register_sb_device); 
  23.  
  24. void unregister_sb_device(struct sb_device *sbdev) 
  25.  device_unregister(&sbdev->dev); 
  26. EXPORT_SYMBOL(unregister_sb_device); 
  27.  
  28. static int sb_drv_probe(struct device *dev) 
  29.  printk(KERN_INFO"sb_drv probe %s\n", dev_name(dev)); 
  30.  return 0; 
  31.  
  32. int register_sb_driver(struct sb_driver *sdrv) 
  33.  sdrv->driver.bus = &sb_bus_type; 
  34.  sdrv->driver.probe = &sb_drv_probe; 
  35.  return driver_register(&sdrv->driver); 
  36. EXPORT_SYMBOL(register_sb_driver); 
  37.  
  38. void unregister_sb_driver(struct sb_driver *driver) 
  39.  driver_unregister(&driver->driver); 
  40. EXPORT_SYMBOL(unregister_sb_driver); 
  41.  
  42. static int __init sb_bus_init(void) 
  43.  int ret; 
  44.  
  45.  ret = bus_register(&sb_bus_type); 
  46.  if (ret) { 
  47.   printk(KERN_ERR "Unable to register sb bus, failure was %d\n",ret); 
  48.   return ret; 
  49.  } 
  50.  if (bus_create_file(&sb_bus_type, &bus_attr_version)) 
  51.   printk(KERN_ERR "Unable to create version attribute\n"); 
  52.  return 0; 
  53.  
  54. static void sb_bus_exit(void) 
  55.  bus_unregister(&sb_bus_type); 
  56.  
  57. module_init(sb_bus_init); 
  58. module_exit(sb_bus_exit); 

xxx_chip.c:注冊4個(gè)名為 "chipX" 的 device

  1. struct xxx_chip { 
  2.  char devname[20]; 
  3.  struct sb_device sdev; 
  4. }; 
  5.  
  6. int chipdev_num = 4; 
  7. struct xxx_chip *chipdev; 
  8.  
  9. static void chip_register_dev(struct xxx_chip *dev, int index
  10.  snprintf(dev->devname, sizeof(dev->devname), "chip%d"index); 
  11.  dev->sdev.name = dev->devname; 
  12.  dev_set_drvdata(&dev->sdev.dev, dev); 
  13.  register_sb_device(&dev->sdev); 
  14.  
  15. int chip_init(void) 
  16.     int i; 
  17.  
  18.     chipdev = kmalloc(chipdev_num*sizeof (struct xxx_chip), GFP_KERNEL); 
  19.  
  20.     memset(chipdev, 0, chipdev_num*sizeof (struct xxx_chip)); 
  21.     for (i = 0; i < chipdev_num; i++) { 
  22.   chip_register_dev(chipdev + i, i); 
  23.  } 
  24.  
  25.     return 0; 
  26.  
  27. void chip_cleanup(void) 
  28.     int i; 
  29.     for (i = 0; i < chipdev_num; i++) { 
  30.   unregister_sb_device(&chipdev[i].sdev); 
  31.  } 
  32.     kfree(chipdev); 
  33.  
  34. module_init(chip_init); 
  35. module_exit(chip_cleanup); 

xxx_chip_drv.c:注冊1個(gè)名為 "chip" 的 driver

  1. static struct sb_driver sculld_driver = { 
  2.  .driver = { 
  3.   .name = "chip"
  4.  }, 
  5. }; 
  6.  
  7. int xxx_chipdrv_init(void) 
  8.     return register_sb_driver(&sculld_driver); 
  9.  
  10. void xxx_chipdrv_cleanup(void) 
  11.     unregister_sb_driver(&sculld_driver); 
  12.  
  13. module_init(xxx_chipdrv_init); 
  14. module_exit(xxx_chipdrv_cleanup); 

運(yùn)行效果:

  1. root@buildroot:~# insmod simple_bus.ko  
  2. root@buildroot:~# tree /sys/bus/sb 
  3. /sys/bus/sb 
  4. ├── devices 
  5. ├── drivers 
  6. ├── drivers_autoprobe 
  7. ├── drivers_probe 
  8. ├── uevent 
  9. └── version 
  10.  
  11. root@buildroot:~# insmod xxx_chip.ko  
  12. root@buildroot:~# tree /sys/bus/sb 
  13. /sys/bus/sb 
  14. ├── devices 
  15. │   ├── chip0 -> ../../../devices/chip0 
  16. │   ├── chip1 -> ../../../devices/chip1 
  17. │   ├── chip2 -> ../../../devices/chip2 
  18. │   └── chip3 -> ../../../devices/chip3 
  19. ├── drivers 
  20. ├── drivers_autoprobe 
  21. ├── drivers_probe 
  22. ├── uevent 
  23. └── version 
  24.  
  25. root@buildroot:~# insmod xxx_chip_drv.ko 
  26. sb_drv probe chip0 
  27. sb_drv probe chip1 
  28. sb_drv probe chip2 
  29. sb_drv probe chip3 
  30.  
  31. root@buildroot:~# tree /sys/bus/sb 
  32. /sys/bus/sb 
  33. ├── devices 
  34. │   ├── chip0 -> ../../../devices/chip0 
  35. │   ├── chip1 -> ../../../devices/chip1 
  36. │   ├── chip2 -> ../../../devices/chip2 
  37. │   └── chip3 -> ../../../devices/chip3 
  38. ├── drivers 
  39. │   └── chip 
  40. │       ├── bind 
  41. │       ├── chip0 -> ../../../../devices/chip0 
  42. │       ├── chip1 -> ../../../../devices/chip1 
  43. │       ├── chip2 -> ../../../../devices/chip2 
  44. │       ├── chip3 -> ../../../../devices/chip3 
  45. │       ├── uevent 
  46. │       └── unbind 
  47. ├── drivers_autoprobe 
  48. ├── drivers_probe 
  49. ├── uevent 
  50. └── version 

通過打印信息可知,device 和 driver 經(jīng)由 bus 判斷是否 match 之后,執(zhí)行了 driver 的 probe() 函數(shù),符合我們前面的分析。

五、小結(jié)

Linux 的 device model 是個(gè)非常復(fù)雜的系統(tǒng)。

從一個(gè)比較高的層次來看,主要由總線、設(shè)備和驅(qū)動構(gòu)成。

內(nèi)核為了實(shí)現(xiàn)這些組件間的相關(guān)關(guān)系,定義了 kobject 和 kset 這樣的基礎(chǔ)底層數(shù)據(jù)結(jié)構(gòu),然后通過 sysfs 文件系統(tǒng)向用戶空間展示發(fā)生在內(nèi)核空間中的各組件間的互聯(lián)層次關(guān)系,并以文件系統(tǒng)接口的方式為用戶空間程序提供了訪問內(nèi)核對象屬性信息的簡易方法。

為了控制篇幅,本文并沒有涉及到 kojbect 和 sysfs。

如果你感興趣的話,去挖掘一下以下內(nèi)容:

  • device model 的底層數(shù)據(jù)結(jié)構(gòu) kojbect、kset 是如何工作的?
  • 內(nèi)核是如何使用 device model 去構(gòu)建 i2c、spi、usb 等驅(qū)動框架?
  • device model 和 sysfs 是如何協(xié)同工作的?
  • sysfs 里如何創(chuàng)建屬性文件以訪問設(shè)備驅(qū)動?
  • sysfs 里的 class 有什么作用?

六、相關(guān)參考

《Linux 設(shè)備驅(qū)動》

  • 第 14 章 Linux 設(shè)備模型

《深入 Linux 設(shè)備驅(qū)動程序內(nèi)核機(jī)制》

  • 第 9 章 Linux 設(shè)備驅(qū)動模型

《Linux設(shè)備驅(qū)動開發(fā)詳解》

  • 第 5 章 Linux文件系統(tǒng)與設(shè)備文件
  • 第 12 章 Linux設(shè)備驅(qū)動的軟件架構(gòu)思想

Linux/Documentation/driver-model

  • bus.txt
  • class.txt
  • device.txt
  • driver.txt
  • overview.txt

 

責(zé)任編輯:武曉燕 來源: 嵌入式Hacker
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號