中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Linux驅動開發中device model的介紹以及用法

發布時間:2021-09-27 17:47:29 來源:億速云 閱讀:307 作者:柒染 欄目:系統運維

Linux驅動開發中device model的介紹以及用法 ,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。

一、什么是 device model?

Linux 的 device model 是一個旨在統一管理所有設備驅動的模型。

它猶如一棟規模宏大的建筑:

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

構造出支撐驅動世界的 bus、device、driver 三大組件,

最后通過 sysfs 在各種基礎的建筑材料之間建立彼此的互聯層次關系,并向外界提供了與建筑內設施進行互動的文件接口。

device model 有什么作用?

可以將 device 的硬件描述 和 driver 進行分離,提升 driver 的代碼復用率;

可以對 device 進行分類;

可以遍歷 device 和 driver;

可以更好地呈現設備的拓撲關系;

可以通過 sysfs 訪問設備;

可以讓設備支持熱插拔;

...

為了控制篇幅,本文將重點放在與驅動工程師關系最緊密的 bus、device、driver 3 個 組件。

二、device model 的 3 個核心概念

device model 里有 3 個核心的概念:

  • bus

  • device

  • driver

什么是 bus?

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

bus 是 Linux 設備驅動模型這種建筑的核心框架,系統中的設備和驅動都依附在其周圍。

啟動系統后,可以通過 /sys/bus 可以查看系統里當前有哪些總線。

bus 由 struct bus_type 來描述:

struct bus_type {  const char *name;  const char *dev_name;  struct device *dev_root;  const struct attribute_group **bus_groups;  const struct attribute_group **dev_groups;  const struct attribute_group **drv_groups;   int (*match)(struct device *dev, struct device_driver *drv);  int (*uevent)(struct device *dev, struct kobj_uevent_env *env);  int (*probe)(struct device *dev);  int (*remove)(struct device *dev);  void (*shutdown)(struct device *dev);   ...  struct subsys_private *p;  struct lock_class_key lock_key; };

不需要一下子了解各個成員的作用,用到的時候再說明。

重點關注成員:

  • int (*match)(struct device *dev, struct device_driver *drv),用于判斷掛在該 bus  上的設備和驅動是否匹配的回調函數;

  • int (*probe)(struct device *dev),如果 bus 具有探測設備的能力,則會提供該回調函數;

  • struct subsys_private *p,用于管理 bus 上的設備和驅動的數據結構;

注冊 bus 的 api:

int bus_register(struct bus_type *bus);

什么是 device ?

device 代表了某個設備。

由 struct device 來描述:

struct device {  struct device *parent;  struct device_private *p;  struct kobject kobj;  const char *init_name;  const struct device_type *type;  struct mutex mutex;  struct bus_type *bus;  struct device_driver *driver;  void *platform_data;  void *driver_data;     ... }

重點關注成員:

  • struct kobject kobj,內核對象;

  • struct bus_type *bus,設備所在的總線;

  • struct device_driver *driver,和設備綁定在一起的驅動,如果還沒綁定,則為 NULL;

注冊 device 的 api:

int device_register(struct device *dev)

什么是 driver?

driver 代表了設備驅動。

由 struct device_driver 來描述:

struct device_driver {  const char *name;  struct bus_type *bus;   struct module *owner;  const char *mod_name; /* used for built-in modules */   bool suppress_bind_attrs; /* disables bind/unbind via sysfs */  enum probe_type probe_type;   const struct of_device_id *of_match_table;  const struct acpi_device_id *acpi_match_table;   int (*probe) (struct device *dev);  int (*remove) (struct device *dev);  void (*shutdown) (struct device *dev);  int (*suspend) (struct device *dev, pm_message_t state);  int (*resume) (struct device *dev);  const struct attribute_group **groups;   const struct dev_pm_ops *pm;   struct driver_private *p; };

重點關注成員:

  • struct bus_type *bus;

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

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

例如 I2C 總線控制器這個設備,對應的驅動為 I2C controller driver。

而掛在 I2C 總線上的設備,對應的驅動為 I2C device driver。

注冊 driver 的 api:

int driver_register(struct device_driver *drv);

三、bus、device、driver 是如何關聯的?

device model 最核心的工作就是維護這三類抽象的實例,以及建立它們之間的關聯關系。

bus 如何管理 device 和 driver ?

在 struct bus_type 中有一個 struct subsys_private *p 指針,它負責管理掛在 bus  上的所有設備和驅動,其定義如下:

struct subsys_private {  struct kset subsys;  struct kset *devices_kset;  struct list_head interfaces;  struct mutex mutex;   struct kset *drivers_kset;  struct klist klist_devices;  struct klist klist_drivers;  struct blocking_notifier_head bus_notifier;  unsigned int drivers_autoprobe:1;  struct bus_type *bus;   struct kset glue_dirs;  struct class *class; };

Linux驅動開發中device model的介紹以及用法

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

struct kset *drivers_kset 和 struct kset *devices_kset  是在向系統注冊當前新總線時動態生成的容納該總線上所有驅動與設備的 kset。

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

內核用 kobject 和 kset 等數據結構作為原材料,以實現面向對象的方式構建了 device model 的框架。

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

Linux驅動開發中device model的介紹以及用法

device 和 driver 的綁定

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

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

都會導致 bus 嘗試執行 device 和 driver 的綁定行為。

1. device_register() 觸發的綁定

注冊 device 時:

int device_register(struct device *dev);  device_add(dev);   bus_probe_device(dev);    __device_attach(dev, true);

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

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

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

是否 match 的判斷標準一般是通過 of_match_table 或者是 id_table 作為衡量的標準,

以 i2c bus 的 match 函數為例:

static int i2c_device_match(struct device *dev, struct device_driver *drv) {  struct i2c_client *client = i2c_verify_client(dev);  struct i2c_driver *driver;    /* Attempt an OF style match */  if (i2c_of_match_device(drv->of_match_table, client))   return 1;   /* Then ACPI style match */  if (acpi_driver_match_device(dev, drv))   return 1;   driver = to_i2c_driver(drv);   /* Finally an I2C match */  if (i2c_match_id(driver->id_table, client))   return 1;   return 0; }

一旦 match 成功,就會調用 driver_probe_device() 以觸發探測設備的行為:

int driver_probe_device(struct device_driver *drv, struct device *dev);  really_probe(dev, drv);   if (dev->bus->probe) {    ret = dev->bus->probe(dev);   } else if (drv->probe) {    ret = drv->probe(dev);   }

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

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

2. 由 driver_register() 觸發的綁定

int driver_register(struct device_driver *drv);  bus_add_driver(drv);   driver_attach(drv);

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

int driver_attach(struct device_driver *drv);  bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);   __driver_attach();    driver_match_device(drv, dev);    driver_probe_device(drv, dev);

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

進而通過 bus 里的 match 函數來判斷是否 device 和 driver 是否匹配。

同樣地,一旦 match 成功,就會調用 driver_probe_device() 以觸發探測設備的行為,后續的操作和注冊設備時是一模一樣的。

3. device 和 drvier 的綁定關系

前面說了綁定是如何被觸發的,現在來明確一下綁定的具體操作。

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

Linux驅動開發中device model的介紹以及用法

對于 device:

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

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

對于 driver:

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

int driver_probe_device(struct device_driver *drv, struct device *dev)  really_probe(dev, drv);   driver_bound(dev);    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 最簡單示例

下面的例子,

構造了一個名為 "simple_bus" 的 bus 實例。

static int sb_match(struct device *dev, struct device_driver *driver) {  return !strncmp(dev_name(dev), driver->name, strlen(driver->name)); }  struct bus_type sb_bus_type = {  .name = "sb",  .match = sb_match, };  static ssize_t version_show(struct bus_type *bus, char *buf) {  return snprintf(buf, PAGE_SIZE, "%s\n", Version); }  static BUS_ATTR_RO(version);  static void sb_dev_release(struct device *dev) { }  int register_sb_device(struct sb_device *sbdev) {     sbdev->dev.bus = &sb_bus_type;  sbdev->dev.release = sb_dev_release;     dev_set_name(&sbdev->dev, sbdev->name);     return device_register(&sbdev->dev); } EXPORT_SYMBOL(register_sb_device);  void unregister_sb_device(struct sb_device *sbdev) {  device_unregister(&sbdev->dev); } EXPORT_SYMBOL(unregister_sb_device);  static int sb_drv_probe(struct device *dev) {  printk(KERN_INFO"sb_drv probe %s\n", dev_name(dev));  return 0; }  int register_sb_driver(struct sb_driver *sdrv) {  sdrv->driver.bus = &sb_bus_type;  sdrv->driver.probe = &sb_drv_probe;  return driver_register(&sdrv->driver); } EXPORT_SYMBOL(register_sb_driver);  void unregister_sb_driver(struct sb_driver *driver) {  driver_unregister(&driver->driver); } EXPORT_SYMBOL(unregister_sb_driver);  static int __init sb_bus_init(void) {  int ret;   ret = bus_register(&sb_bus_type);  if (ret) {   printk(KERN_ERR "Unable to register sb bus, failure was %d\n",ret);   return ret;  }  if (bus_create_file(&sb_bus_type, &bus_attr_version))   printk(KERN_ERR "Unable to create version attribute\n");  return 0; }  static void sb_bus_exit(void) {  bus_unregister(&sb_bus_type); }  module_init(sb_bus_init); module_exit(sb_bus_exit);

xxx_chip.c:注冊4個名為 "chipX" 的 device

struct xxx_chip {  char devname[20];  struct sb_device sdev; };  int chipdev_num = 4; struct xxx_chip *chipdev;  static void chip_register_dev(struct xxx_chip *dev, int index) {  snprintf(dev->devname, sizeof(dev->devname), "chip%d", index);  dev->sdev.name = dev->devname;  dev_set_drvdata(&dev->sdev.dev, dev);  register_sb_device(&dev->sdev); }  int chip_init(void) {     int i;      chipdev = kmalloc(chipdev_num*sizeof (struct xxx_chip), GFP_KERNEL);      memset(chipdev, 0, chipdev_num*sizeof (struct xxx_chip));     for (i = 0; i < chipdev_num; i++) {   chip_register_dev(chipdev + i, i);  }      return 0; }  void chip_cleanup(void) {     int i;     for (i = 0; i < chipdev_num; i++) {   unregister_sb_device(&chipdev[i].sdev);  }     kfree(chipdev); }  module_init(chip_init); module_exit(chip_cleanup);

xxx_chip_drv.c:注冊1個名為 "chip" 的 driver

static struct sb_driver sculld_driver = {  .driver = {   .name = "chip",  }, };  int xxx_chipdrv_init(void) {     return register_sb_driver(&sculld_driver); }  void xxx_chipdrv_cleanup(void) {     unregister_sb_driver(&sculld_driver); }  module_init(xxx_chipdrv_init); module_exit(xxx_chipdrv_cleanup);

運行效果:

root@buildroot:~# insmod simple_bus.ko  root@buildroot:~# tree /sys/bus/sb /sys/bus/sb ├── devices ├── drivers ├── drivers_autoprobe ├── drivers_probe ├── uevent └── version  root@buildroot:~# insmod xxx_chip.ko  root@buildroot:~# tree /sys/bus/sb /sys/bus/sb ├── devices │   ├── chip0 -> ../../../devices/chip0 │   ├── chip1 -> ../../../devices/chip1 │   ├── chip2 -> ../../../devices/chip2 │   └── chip3 -> ../../../devices/chip3 ├── drivers ├── drivers_autoprobe ├── drivers_probe ├── uevent └── version  root@buildroot:~# insmod xxx_chip_drv.ko sb_drv probe chip0 sb_drv probe chip1 sb_drv probe chip2 sb_drv probe chip3  root@buildroot:~# tree /sys/bus/sb /sys/bus/sb ├── devices │   ├── chip0 -> ../../../devices/chip0 │   ├── chip1 -> ../../../devices/chip1 │   ├── chip2 -> ../../../devices/chip2 │   └── chip3 -> ../../../devices/chip3 ├── drivers │   └── chip │       ├── bind │       ├── chip0 -> ../../../../devices/chip0 │       ├── chip1 -> ../../../../devices/chip1 │       ├── chip2 -> ../../../../devices/chip2 │       ├── chip3 -> ../../../../devices/chip3 │       ├── uevent │       └── unbind ├── drivers_autoprobe ├── drivers_probe ├── uevent └── version

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

五、小結

Linux 的 device model 是個非常復雜的系統。

從一個比較高的層次來看,主要由總線、設備和驅動構成。

內核為了實現這些組件間的相關關系,定義了 kobject 和 kset 這樣的基礎底層數據結構,然后通過 sysfs  文件系統向用戶空間展示發生在內核空間中的各組件間的互聯層次關系,并以文件系統接口的方式為用戶空間程序提供了訪問內核對象屬性信息的簡易方法。

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

泸定县| 富锦市| 合肥市| 永新县| 武清区| 恭城| 福贡县| 台南市| 平阴县| 寻甸| 扬州市| 黔东| 湘阴县| 繁昌县| 比如县| 灌云县| 大厂| 垦利县| 阿巴嘎旗| 鄄城县| 胶州市| 临沧市| 贵南县| 普洱| 前郭尔| 朔州市| 肥城市| 屏山县| 彭州市| 合水县| 咸阳市| 仁寿县| 故城县| 湾仔区| 高台县| 延长县| 武冈市| 柳河县| 白河县| 乐清市| 资阳市|