kobject 和 sysfs
Posted Li-Yongjun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kobject 和 sysfs相关的知识,希望对你有一定的参考价值。
活动地址:CSDN21天学习挑战赛
设备模型
kernel 2.6 增加了一个引人注目得新特性——统一设备模型(device model)。
设备模型是指设备、总线、驱动的系统结构抽象,它的意义在于能够系统地管理所有设备。
设备模型描述设备在系统中的拓扑结构,从而使得系统具有以下优点:
- 代码重复最小化
- 提供诸如引用计数这样的统一机制。
- 可以列举系统中所有的设备,观察它们的状态,并且查看它们连接的总线。
- 可以将系统中的全部设备结构以树的形式完整、有效地展现出来,包括所有的总线和内部连接
- 可以将设备和其对应的驱动联系起来,反之亦然。
- 可以将设备按照类型加以归类,如分类为输入设备,而无需理解物理设备的拓扑结构。
- 可以沿设备树的叶子向其根的方向依次遍历,以保证能以正确的顺序关闭各设备的电源。
最后一点是实现设备模型的最初动机。若想在内核中实现智能的电源管理,就需要来建立表示系统中设备拓扑关系的树结构。当在树上端的设备关闭电源时,内核必须首先关闭该设备节点以下(处于叶子上的)设备电源。比如内核需要先关闭一个 USB 鼠标,然后才可以关闭 USB 控制器;同样内核也必须在关闭 PCI 总线前先关闭 USB 控制器。简而言之,若要准确又高效地完成上述电源管理目标,内核无疑需要一颗设备树。
kobject
设备模型地核心部分就是 kobject,它由 struct kobject 结构体表示,定义在头文件 <linux/kobject.h> 中。
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);
else
printk("parent = NULL\\n");
if (class_kset->kobj.kset)
printk("clase's kset kobj name = %s\\n", class_kset->kobj.kset->kobj.name);
else
printk("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/
总结
设备模型还是很复杂、很抽象的,后面还需要深入学习,这里就当做个引子。继续努力!
以上是关于kobject 和 sysfs的主要内容,如果未能解决你的问题,请参考以下文章