kobject 和 sysfs
活动地址:CSDN21天学习挑战赛
设备模型
kernel 2.6 增加了一个引人注目得新特性——统一设备模型(device model)。
设备模型是指设备、总线、驱动的系统结构抽象,它的意义在于能够系统地管理所有设备。
设备模型描述设备在系统中的拓扑结构,从而使得系统具有以下优点:
- 代码重复最小化
- 提供诸如引用计数这样的统一机制。
- 可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总线。
- 可以将系统中的全部设备结构以树的形式完整、有效地展现出来,包括所有的总线和内部连接
- 可以将设备和其对应的驱动联系起来,反之亦然。
- 可以将设备按照类型加以归类,如分类为输入设备,而无需理解物理设备的拓扑结构。
- 可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确的顺序关闭各设备的电源。
最后一点是实现设备模型的最初动机。若想在内核中实现智能的电源管理,就需要来建立表示系统中设备拓扑关系的树结构。当在树上端的设备关闭电源时,内核必须首先关闭该设备节点以下(处于叶子上的)设备电源。比如内核需要先关闭一个 USB 鼠标,然后才可以关闭 USB 控制器;同样内核也必须在关闭 PCI 总线前先关闭 USB 控制器。简而言之,若要准确又高效地完成上述电源管理目标,内核无疑需要一颗设备树。
kobject
设备模型地核心部分就是 kobject,它由 struct kobject 结构体表示,定义在头文件
struct kobject {const char *name;struct list_head entry;struct kobject *parent;struct kset *kset;struct kobj_type *ktype;struct kernfs_node *sd;struct kref kref;unsigned int state_initialized:1;unsigned int state_in_sysfs:1;unsigned int state_add_uevent_sent:1;unsigned int state_remove_uevent_sent:1;unsigned int uevent_suppress:1;
};
name:对应 sysfs 的目录名。
entry:用于将 kobj 挂在 kset->list 中。
parent:指向 kobj 的父结构,形成层次结构,在 sysfs 中表现为父子目录的关系。
kset:表征该 kobj 所属的 kset。kset 可以作为 parent 的“候补”:当注册时,传入的 parent 为空时,可以让 kset 来担当。
ktype:该 kobj 对应的 kobj_type。每个 kobj 或其嵌入的结构对象应该都对应一个 kobj_type。
sd:对应 sysfs 对象。在 3.14 以后的内核中,sysfs 基于 kernfs 来实现。
kref:引用计数对象,支撑 kobj 的引用计数功能。state_initialized:1---------------------记录初始化与否。调用 kobject_init() 后,会置位。
state_in_sysfs:1-----------------------记录 kobj 是否注册到 sysfs,在 kobject_add_internal() 中置位。
state_add_uevent_sent:1-----------当发送 KOBJ_ADD 消息时,置位。提示已经向用户空间发送 ADD 消息。
state_remove_uevent_sent:1------当发送 KOBJ_REMOVE 消息时,置位。提示已经向用户空间发送 REMOVE 消息。
uevent_suppress:1--------------------如果该字段为 1,则表示忽略所有上报的 uevent 事件。
sysfs
sysfs 是设备模型的意外收获。开发者为了方便调试,决定将设备结构树导出为一个文件系统——sysfs。
sysfs 代替了先前处于 /proc 下的设备相关文件。
sysfs 起初被称为 driverfs。
当前 sysfs 文件系统代替了以前需要由 ioctl() 和 procfs 文件系统完成的功能。
利用在 sysfs 目录中添加一个 sysfs 属性,代替在设备节点上实现一个新的 ioctl()。
sysfs 属性应该保证每个文件只导出一个值,这使得从命令行读写变得简单;该值应该是文本形式而且被映射为简单 C 类型,这使得 C 语言程序可以轻易地将内核数据从 sysfs 导入到自身的变量中。这就比 /proc 好多了,/proc 中的数据混乱而不具有可读性。
sysfs 提供内核到用户空间的服务,这多少有些用户空间的 ABI(应用程序二进制接口)的作用。
示例1
kobject、kset 结构关系还是挺复杂的,这里添加一些打印,直观地了解下其内容。
drivers/base/class.c
int __init classes_init(void)
{int i;struct kset *p;class_kset = kset_create_and_add("class", NULL, NULL);if (!class_kset)return -ENOMEM;
printk("clase's kobj name = %s\n", class_kset->kobj.name);
if (class_kset->kobj.parent)printk("clase's parent kobj name = %s\n", class_kset->kobj.parent->name);
elseprintk("parent = NULL\n");if (class_kset->kobj.kset)printk("clase's kset kobj name = %s\n", class_kset->kobj.kset->kobj.name);
elseprintk("clase's kset is NULL\n");return 0;
}
输出
clase's kobj name = class
parent = NULL
clase's kset is NULL
clase's kobj name = class,和 /sys/class 吻合。并且其 parent 和 kset 均为 NULL,说明 class 在设备模型中处于最顶层,所以 /sys 并不是最顶层,它只是一个目录,/sys 下的一级子目录是一个个顶级 kset。
示例2
static int __init leds_init(void)
{int i;struct kset *p;leds_class = class_create(THIS_MODULE, "leds");if (IS_ERR(leds_class))return PTR_ERR(leds_class);leds_class->pm = &leds_class_dev_pm_ops;leds_class->dev_groups = led_groups;printk("leds kobj name = %s\n", leds_class->dev_kobj->name);
printk("leds's parent kobj name = %s\n", leds_class->dev_kobj->parent->name);printk("name = %s\n", leds_class->p->subsys.kobj.name);
printk("parent name = %s\n", leds_class->p->subsys.kobj.parent->name);return 0;
}
leds kobj name = char
leds's parent kobj name = dev
name = leds
parent name = class
得到两种目录结构 dev/char/ 和 class/leds/,这两种形式在 /sys 下都有呈现:/sys/dev/char/ 和 /sys/class/leds/
总结
设备模型还是很复杂、很抽象的,后面还需要深入学习,这里就当做个引子。继续努力!
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
