乐趣区

关于嵌入式:Linux-驱动开发-驱动世界里的宏伟建筑

哈喽,我是老吴。

是否每一个上进的人都会感觉本人还能够再致力一点?

事件到了最初,只有没达成目标,总能把失败的起因归为 “ 没有再致力一点 ”。

然而,对致力的最大谬误认知就是:工夫越长,过程越苦楚,代表我越致力。

想一想,是否有更正当的致力形式?

以下是注释:

 一、什么是 device model?二、device model 的 3 个外围概念
三、bus、device、driver 是如何关联的?四、bus、device、driver 最简略示例
五、小结
六、相干参考

一、什么是 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;
};

点击查看大图

两个 klist 成员以链表的模式将该总线上所有的驱动与设施链接到一起。

struct kset *drivers\_kset 和 struct kset *devices\_kset 是在向零碎注册以后新总线时动静生成的包容该总线上所有驱动与设施的 kset。

在内核里,用 kobject 来示意一个对象,kset 则是 kobject set 的缩写,即内核对象汇合。

内核用 kobject 和 kset 等数据结构作为原材料,以实现面向对象的形式构建了 device model 的框架。

最初,device 和 device\_driver 的 bus 成员也会指向总线:

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 绑定在一起。

点击查看大图

对于 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 实例。

simple\_bus.c:注册了一条名为 “sb” 的 bus,并且提供了注册 device 和 driver 的 api。

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 文件系统向用户空间展现产生在内核空间中的各组件间的互联档次关系,并以文件系统接口的形式为用户空间程序提供了拜访内核对象属性信息的繁难办法。

为了管制篇幅,本文并没有波及到 kojbect 和 sysfs。

如果你感兴趣的话,去开掘一下以下内容:

  • device model 的底层数据结构 kojbect、kset 是如何工作的?
  • 内核是如何应用 device model 去构建 i2c、spi、usb 等驱动框架?
  • device model 和 sysfs 是如何协同工作的?
  • sysfs 里如何创立属性文件以拜访设施驱动?
  • sysfs 里的 class 有什么作用?

六、相干参考

《Linux 设施驱动》

  • 第 14 章 Linux 设施模型

《深刻 Linux 设施驱动程序内核机制》

  • 第 9 章 Linux 设施驱动模型

《Linux 设施驱动开发详解》

  • 第 5 章 Linux 文件系统与设施文件
  • 第 12 章 Linux 设施驱动的软件架构思维

Linux/Documentation/driver-model

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

思考技术,也思考人生

要学习技术,更要学习如何生存

最近在看的书:

《指数基金投资指南》

作者银行螺丝钉,专一于低估值指数基金投资,系统性地解说各类指数基金,以及投资指数基金的无效策略。

点击查看大图

播种了什么?

  • 复习了一些对于基金定投的基础知识;

你和我各有一个苹果,如果咱们替换苹果的话,咱们还是只有一个苹果。但当你和我各有一个想法,咱们替换想法的话,咱们就都有两个想法了。

感觉文章对你有价值,无妨 在看 + 分享

举荐浏览:

专辑 | Linux 驱动开发

专辑 | 每天一点 C

专辑 | Linux 零碎编程

退出移动版