bus, device, driver作为整个系列文章的第四篇,将会介绍Linux设备驱动模型的中层抽象,也就是bus、device、driver.
bus
总线(bus)是处理器和一个或者多个设备之间的通道。在设备模型中,所有的设备都通过总线连接。总线既可以是实际物理总线(I2C等)的抽象,也可以是处于Linux设备驱动模型架构需要而虚拟出的”平台总线“。
符合Linux设备驱动模型的device和driver必须挂载在同一根总线上。
bus的抽象结构
总线的抽象数据结构为bus_type1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28struct bus_type {
const char *name;
const char *dev_name;
struct device *dev_root;
struct device_attribute *dev_attrs; /* use dev_groups instead */
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);
int (*online)(struct device *dev);
int (*offline)(struct device *dev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
const struct dev_pm_ops *pm;
const struct iommu_ops *iommu_ops;
struct subsys_private *p;
struct lock_class_key lock_key;
};
主要的成员介绍如下
- dev_root
- dev_attrs
- bus_groups, dev_groups, drv_groups
- match
- subsys_private
dev_root
默认parent device?
dev_attrs
默认挂载在bus下设备的属性?
bus_groups, dev_groups, drv_groups
match
对试图挂载到该总线上的device和driver执行的匹配操作。
什么时候回调用?
subsys_private
适用于bus和class.
该结构用来管理bus, driver, device之间的关系。
1 | struct subsys_private { |
- kset subsys: 意义是什么?作为一个bus的抽象,其kset是bus_kset。如subsys->name = bus1, 那么将会创建/sys/bus/bus1
- devices_kset: 总线上所有devices的集合
- drivers_kset: 总线上所有drivers的集合
- klist_devices和klist_drivers是devices和drivers的链表
什么地方会用到?
- drivers_autoprobe:当注册设备或驱动的时候,是否进行绑定操作
什么地方会用到?
bus的函数
- buses_init
- bus_register
bus的起源buses_init
在系列第一篇中,提到了driver_init函数,其中调用了buses_init. 这个函数是系统中所有bus的起源。1
2bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj);
bus_kset是所有bus的源头,将会建立/sys/bus,热插拔操作函数为bus_uevent_ops,当bus有状态变化时,将会通知用户空间uevent消息。
devices_kset是在devices_init中建立的,system_kset的parent是devices_kset,所以将会创建/sys/devices/system。
这个文件夹的作用是什么?
bus_uevent_ops中只有一个filter函数,将会对需要提交的消息进行过滤,过滤条件参考代码:1
2
3
4
5
6
7
8static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
{
struct kobj_type *ktype = get_ktype(kobj);
if (ktype == &bus_ktype)
return 1;
return 0;
}
表示如果要求发送uevent消息的Kobj的kobj_type类型不是bus_type,那么将不会发送到用户空间。
那么为什么要这么规定呢?bus_type中是什么?
1 | static struct kobj_type bus_ktype = { |
bus_register
- 初始化priv结构体,建立关系网
- 设置subsys.kobj.kset = bus_kset
- 设置subsys.kobj.ktype = &bus_ktype
- 设置drivers_autoprobe = 1
- kset_register(priv->subsys)
- 创建uevent属性文件,作用是输入对应的kobject_action type,可以用来模拟事件
- 创建devices kset, 同时/sys/bus/bus_name/devices and /sys/bus/bus_name/drivers
- 初始化drivers and devices链表
- add_probe_files,创建probe和autoprobe属性文件,probe文件用来输入device名字进行手动配对,autoprobe用来设置autoprobe变量
- bus_add_groups
以上,sysfs下的总线基本框架结构就全都有了。
attribute和show, store的关系
比如bus_attribute结构体
1
2
3
4
5
6
7
8
9
10 struct bus_attribute {
struct attribute attr;
ssize_t (*show)(struct bus_type *bus, char *buf);
ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);
}
struct attribute {
const char *name;
umode_t mode;
}
属性是通过sysfs_create_file创建,但是其参数只有attribute,而没有show和store。那么文件是如何和操作函数联系起来的呢?
在3.0以前的版本中,sysfs_open_file函数会根据file找到对应sysfs_dirent, 再根据sysfs_dirent找到kobj, 将kobj->ktype->sysfs_ops赋值给打开的属性文件。
这时候,对文件的write和open实质上是sysfs_ops中的store和show。sysfs_ops决定于kobj_type。
在3.0之后的版本中,由于kernfs从sysfs中分离出来,暂时还不知道具体的过程。
device和driver的绑定
每个device应该有对应的driver,将device和driver联系起来的过程叫做绑定。在Linux设备驱动模型中,通过总线实现绑定(所有的device和driver都挂载在bus下)。那么绑定的过程是如何发生的呢?
既然绑定是双方共同的行为,那么双方都有触发绑定的权利。在device端,device_reigster向bus注册设备时会触发绑定。在driver端,driver_register向bus注册驱动时会触发绑定。具体的绑定代码分析,留到后面的deivce和driver章节。
device
在Linux系统中,所有的对象都被抽象为kobject.
在Linux系统中,所有的硬件设备被抽象为device。其结构如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53struct device {
struct device *parent;
struct device_private *p;
struct kobject kobj;
const char *init_name; /* initial name of the device */
struct device_type *type;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
struct bus_type *bus; /* type of bus device is on */
struct device_driver *driver; /* which driver has allocated this
device */
void *platform_data; /* Platform specific data, device
core doesn't touch it */
struct dev_pm_info power;
struct dev_power_domain *pwr_domain;
int numa_node; /* NUMA node this device is close to */
u64 *dma_mask; /* dma mask (if dma'able device) */
u64 coherent_dma_mask;/* Like dma_mask, but for
alloc_coherent mappings as
not all hardware supports
64 bit addresses for consistent
allocations such descriptors. */
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; /* dma pools (if dma'ble) */
struct dma_coherent_mem *dma_mem; /* internal for coherent mem
override */
/* arch specific additions */
struct dev_archdata archdata;
struct device_node *of_node; /* associated device tree node */
dev_t devt; /* dev_t, creates the sysfs "dev" */
spinlock_t devres_lock;
struct list_head devres_head;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; /* optional groups */
void (*release)(struct device *dev);
};
其中以下成员需要关注
- struct device *parent
当前device的父设备,作用是什么?层次关系在kobject中不是已经表明了么?
- struct device_private *p
- struct kobject kobj
- struct device_type *type
- struct bus_type *bus
- struct device_driver *driver
device对应的driver,没绑定时为NULL
- device_node *of_node
- struct class *class
- struct attribute_grout **groups
device的相关函数
- devices_init: device系统的初始化
- device_initialize
- device_register
- device_add
device_init
在driver_init中被调用。1
2
3
4
5
6
7int __init devices_init(void)
{
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
dev_kobj = kobject_create_and_add("dev", NULL);
sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);
sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);
}
在/sys下创建devices, dev, 在/sys/dev下面创建block和char文件夹。
问题:为什么dev, block, char没有用kset?
device_initialize
1 | void device_initialize(struct device *dev) |
需要注意的是device->kobj的kset是devices_kset,那么该kobj对应的目录将会建立在/sys/devices下面
device_register
1 | int device_register(struct device *dev) |
重点是device_add.
device_add
位于drivers/base/core.c中,API为
int device_add(struct device *dev)
device_add做了什么?
坑,devtmpfs,动态生成设备节点
建立系统硬件拓扑关系图
为dev建立属性文件
bus_probe_device
1 | void bus_probe_device(struct device *dev) |
在autoprobe为1的情况下,执行device_attach.1
2
3
4
5
6
7__device_attach
__device_match_device //根据drv->bus->match判断是否匹配
driver_probe_device
really_probe //如果有dev->bus->probe
dev->bus->probe
//如果有drv->probe
drv->probe
driver
driver数据结构
driver在内核中的数据结构如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23struct 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 */
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 module *owner
驱动所在的内核模块,该部分在哪里会用到?作用是什么 - const struct of_device_id *of_match_table
- probe
驱动程序的探测函数,当bus中将驱动和对应的设备绑定时(bus_probe_device),内核会首先调用bus中的probe函数,如果bus没有实现自己的probe函数,内核会调用驱动程序的probe函数。 - struct driver_private *p
driver的函数
通过driver_reigster向系统注册驱动,其核心代码如下:1
2
3
4
5
6
7
8
9<driver/base/driver.c>
int driver_register(struct device_driver *drv)
{
other = driver_find(drv->name, drv->bus);
ret = bus_add_driver(drv);
ret = driver_add_groups(drv, drv->groups);
object_uevent(&drv->p->kobj, KOBJ_ADD);
}
driver_find用来确认driver是否在系统中注册过,通过Bus指名查找的总线,如果成功返回指针,否则返回0.
如果驱动没有被注册,那么通过bus_add_driver(drv)向系统注册。
1 | int bus_add_driver(struct device_driver *drv) |
driver_attach函数用来匹配device和driver1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40int driver_attach(struct device_driver *drv)
{
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
if (!driver_match_device(drv, dev))
return 0;
if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
device_lock(dev);
//实际的绑定函数
if (!dev->driver)
driver_probe_device(drv, dev);
device_unlock(dev);
if (dev->parent)
device_unlock(dev->parent);
return 0;
}
在device_add函数中,会通过bus_probe_device调用device_attach函数,而在driver_register中,经过层层调用最后会调用到driver_attach函数。这两个函数最后都会调用really_probe函数。
而在really_probe函数中,如果bus有probe函数,会调用dev->bus->probe。如果bus没有probe,会调用driver的probe函数。
class
class不同于bus/device/driver,是完全抽象出来的概念。常见的有block, tty, input等。
class example
class_simple example from ldd3
以input子系统为例。
class的起源
通过classes_init创建了/sys/class目录(kset_create_and_add),对应的内核对象为class_kset,所谓系统中所有class内核对象的顶层kset.
class
1 | struct class { |
- owner
- class_attrs
- dev_groups
- subsys_private *p
class和系统的关系
和class以及系统相关的函数主要是以下几个
- class注册
- class_create
- class_register
- device_create
class_create && class_register
1 | class_register(class) |
这两个函数都调用了__class_register1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23int __class_register(struct class *cls, struct lock_class_key *key)
{
struct subsys_private *cp;
cp = kzalloc(sizeof(*cp), GFP_KERNEL);
klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put);
INIT_LIST_HEAD(&cp->interfaces);
kset_init(&cp->glue_dirs);
__mutex_init(&cp->mutex, "subsys mutex", key);
error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name);
/* set the default /sys/dev directory for devices of this class */
if (!cls->dev_kobj)
cls->dev_kobj = sysfs_dev_char_kobj;
cp->subsys.kobj.kset = class_kset;
cp->subsys.kobj.ktype = &class_ktype;
cp->class = cls;
cls->p = cp;
error = kset_register(&cp->subsys);
error = add_class_attrs(class_get(cls));
}
目录对应的kobj_type就是class_ktype,也就决定了对该目录的操作最后会调用到class_ktype中的sysfs_ops.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct class_attribute *class_attr = to_class_attr(attr);
struct subsys_private *cp = to_subsys_private(kobj);
ssize_t ret = -EIO;
if (class_attr->show)
ret = class_attr->show(cp->class, class_attr, buf);
return ret;
}
static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct class_attribute *class_attr = to_class_attr(attr);
struct subsys_private *cp = to_subsys_private(kobj);
ssize_t ret = -EIO;
if (class_attr->store)
ret = class_attr->store(cp->class, class_attr, buf, count);
return ret;
}
static const struct sysfs_ops class_sysfs_ops = {
.show = class_attr_show,
.store = class_attr_store,
};
static struct kobj_type class_ktype = {
.sysfs_ops = &class_sysfs_ops,
.release = class_release,
.child_ns_type = class_child_ns_type,
};
在class对应的sysfs_ops中,show最后会调用class_attribute->show, store会调用class_attribute->store.
cp->subsys通过kset_register加入到系统中,因为subsys.kobj.kset = class_kset,所以对应的目录是/sys/class/cls->name.
最后通过add_class_attrs添加目录下的属性文件,其属性文件通过class->class_attrs指定。
以上是创建class的过程。
如何创建一个class?
属性文件
属性文件框架的核心是attribute以及sysfs_create_file.
attribute作为嵌入式的结构被嵌入各式各样的xxx_attribute结构体中,xxx_attribute中包含了对应的xxx_show和xxx_store函数。
sysfs_create_file(kobj, attr)会根据kobj确认path,根据attr建立文件。
那么属性文件对应的操作如何确定?
这就需要kobj_type的帮助,在kobj_type->sysfs_ops中的show和store函数中,会通过attr找到被嵌入的xxx_attribute结构体,然后调用相应的show和store函数。
bus_attribute
1 | struct attribute { |
该结构体通过BUS_ATTR(_name, _mode, _show, _store)构建,会初始化结构为bus_attribute的bus_attr_name的变量。
并通过bus_create_file建立属性文件。对于bus来说,属性文件的目录层级通过bus_type决定。1
2
3
4
5
6
7
8
9
10int bus_create_file(struct bus_type *bus, struct bus_attribute *attr)
{
int error;
if (bus_get(bus)) {
error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
bus_put(bus);
} else
error = -EINVAL;
return error;
}
其文件对应的操作方式由bus_ktype中的bus_sysfs_ops决定:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr,
char *buf)
{
struct bus_attribute *bus_attr = to_bus_attr(attr);
struct subsys_private *subsys_priv = to_subsys_private(kobj);
ssize_t ret = 0;
if (bus_attr->show)
ret = bus_attr->show(subsys_priv->bus, buf);
return ret;
}
static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr,
const char *buf, size_t count)
{
struct bus_attribute *bus_attr = to_bus_attr(attr);
struct subsys_private *subsys_priv = to_subsys_private(kobj);
ssize_t ret = 0;
if (bus_attr->store)
ret = bus_attr->store(subsys_priv->bus, buf, count);
return ret;
}
static const struct sysfs_ops bus_sysfs_ops = {
.show = bus_attr_show,
.store = bus_attr_store,
};
static struct kobj_type bus_ktype = {
.sysfs_ops = &bus_sysfs_ops,
.release = bus_release,
};
device_attribute
driver_attribute
以上两部分和bus_attribute相似,就略过了。
attribute_group
attribute_group的作用就是将多个attr放在一个group中,方便管理。
以i2c为例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<driver/i2c/i2c-core.c>
static struct attribute *i2c_dev_attrs[] = {
&dev_attr_name.attr,
/* modalias helps coldplug: modprobe $(cat .../modalias) */
&dev_attr_modalias.attr,
NULL
};
//生成i2c_dev_groups
ATTRIBUTE_GROUPS(i2c_dev);
static struct device_type i2c_client_type = {
.groups = i2c_dev_groups,
.uevent = i2c_device_uevent,
.release = i2c_client_dev_release,
};
其中ATTRIBUTE_GROUPS在include/linux/sysfs.h中定义1
2
3
4
5
static const struct attribute_group _name##_group = { \
.attrs = _name##_attrs, \
}; \
__ATTRIBUTE_GROUPS(_name)
整个device_type会赋值给device.type,然后device_register会生成属性文件。
如果group赋值给class->dev_groups或者device_type->groups或者dev->groups, 那么将在bus_add_device中通过device_register->device_add->device_add_attrs中
1 | <drivers/base/core.c> |
默认属性文件
- uevent
- probe
- autoprobe
uevent属性文件
该部分的实现在driver/base/core.c中。
uevent的读取:会输出uevent env
uevent的写入:会根据写入的action,引起kobject_uevent的操作
probe 和 autoprobe
该部分你的实现在driver/base/bus.c中。1
2
3static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
show_drivers_autoprobe, store_drivers_autoprobe);
autoprobe文件用来改变autoprobe变量的值。
probe文件是只写,用来手动启动一次probe.