<script>function StorePage(){d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();}</script>
原创,转载请注明作者及出处。作者:刘洪涛,华清远见嵌入式学院金牌讲师
在上篇《利用udev、sys动态创建设备结点》的记录中,设备驱动中主要依靠下面两个功能完成的:
1、在/sys/class下创建farsight_class类
my_class =class_create(THIS_MODULE, "farsight_class");
2、在farsight_class中创建新的class设备
class_device_create(my_class,NULL, devno, NULL,"farsight_dev");
然后会在/sys中出现如图的文件结构:
其中”dev”和uevent都是“属性”,可以读取dev获取设备的主次设备号;也可以对uevent操作;让内核发出“add”事件用于热插拔。如:
注:这里写入任何值都会导致“add”事件的产生,udevmonitor检测时现象如下:
UEVENT[1220019773.507374] add????? /class/farsight_class/farsight_dev (farsight_class)
那么上述功能实现的原理是什么呢?现在就要过度到本文的主题ktype的使用了。先认识下这个结构
kype的结构定义为:
struct kobj_type {
void (*release)(struct kobject *);
struct sysfs_ops *sysfs_ops;/*提供实现以下属性的方法*/
struct attribute **default_attrs; /*用于保存类型属性列表(指针的指针) */
};
其中 attribute定义为:
struct attribute {
char *name;/*属性的名字(在kobject的sysfs 目录中显示,如上文的dev、uvent)*/
struct module *owner;/*指向模块的指针(如果有), 此模块负责实现这个属性*/
mode_t mode; /*属性的保护位,modes 的宏定义在 <linux/stat.h>:例如S_IRUGO 为只读属性等等*/
}; /*default_attrs 列表中的最后一个元素必须用 0 填充*/
sysfs 系统中的属性读写是由 kobj_type->sysfs_ops 成员中的函数完成的:
struct sysfs_ops {
ssize_t (*show)(struct kobject *kobj, struct attribute *attr, char *buffer);
ssize_t (*store)(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size);
};
当用户空间读取一个属性时(如:#cat dev),内核会使用指向 kobject 的指针(kobj)和正确的属性结构(*attr)来调用show 方法,该方法将给定属性值编码进缓冲(buffer)(注意不要越界( PAGE_SIZE 字节)), 并返回实际数据长度。
也可对所有 kobject (通常指在一个kset关联的范围内)关联的属性使用同一个 show 方法,用传递到函数的 attr 指针来判断所请求的属性。有的 show 方法包含对属性名字的检查。有的show 方法会将属性结构嵌入另一个结构(本文举的例子就是用的这种方法), 这个结构包含需要返回属性值的信息,这时可用container_of 获得上层结构的指针以返回属性值的信息。
当用户空间写入一个属性时(如echo “hello” > event)内核会使用指向 kobject 的指针(kobj)和正确的属性结构(*attr)来调用store 方法。
store 方法将存在缓冲(buffer)的数据( size为数据的长度,不能超过 PAGE_SIZE )解码并保存新值到属性(*attr), 返回实际解码的字节数。store 方法只在拥有属性的写权限时才能被调用。此时注意:接收来自用户空间的数据一定要验证其合法性。如果到数据不匹配, 返回一个负的错误值。
每一个 kobject 需要有一个关联的 kobj_type 结构,指向这个结构的指针能在 2 个不同的地方找到:
(1)kobject 结构自身包含一个成员(ktype)指向kobj_type ;
struct kobject {
……
struct kobj_type* ktype;/*负责对该kobject类型进行跟踪的struct kobj_type的指针*/
……
}
(2)如果这个 kobject 是一个 kset 的成员, kset 会提供kobj_type 指针。
struct kset {
struct kobj_type* ktype; /*指向该kset对象类型的指针*/
……
}
访问属性的时候到底是用的哪个kobj_type呢?
下面这个函数用以查找指定kobject的kobj_type 指针:
static inline struct kobj_type * get_ktype(struct kobject * k)
{
if (k->kset && k->kset->ktype)
return k->kset->ktype;
else
return k->ktype;
}
上面可以看出,kset中的ktype这个类型优先于 kobject 自身中的 ktype 。因此在典型的应用中, 在 struct kobject 中的 ktype 成员被设为 NULL, 而 kset 中的ktype是实际被使用的。
下面通过跟踪class_device_create(my_class,NULL, devno, NULL,"farsight_dev");来确定ktype的使用。
1、
struct class_device *class_device_create(……)
{
……
retval = class_device_register(class_dev);
}
2、
int class_device_register(struct class_device *class_dev)
{
class_device_initialize(class_dev);
return class_device_add(class_dev);
}
3、
void class_device_initialize(struct class_device *class_dev)
{
kobj_set_kset_s(class_dev, class_obj_subsys);
kobject_init(&class_dev->kobj);
INIT_LIST_HEAD(&class_dev->node);
}
4、
#define kobj_set_kset_s(obj,subsys) \
(obj)->kobj.kset = &(subsys).kset
从中可以看出名为“farsight_dev”的kobject对应的kset是class_obj_subsys.kset
5、
看看class_obj_subsys的定义
static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
#define decl_subsys(_name,_type,_uevent_ops) \
struct subsystem _name##_subsys = { \
.kset = { \
.kobj = { .name = __stringify(_name) }, \
.ktype = _type, \
.uevent_ops =_uevent_ops, \
} \
}
所以kset对应的ktype为ktype_class_device
6、
static struct kobj_type ktype_class_device = {
.sysfs_ops????? = &class_dev_sysfs_ops,
.release??? = class_dev_release,
};
7、
static struct sysfs_ops class_dev_sysfs_ops = {
.show???? = class_device_attr_show,
.store????? = class_device_attr_store,
};
在操作上文中的“dev”或“uevent”时都是操作这个class_dev_sysfs_ops
8、
class_device_attr_show(struct kobject * kobj, struct attribute * attr,
char * buf)
{
struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
struct class_device * cd = to_class_dev(kobj);
ssize_t ret = 0;
if (class_dev_attr->show)
ret = class_dev_attr->show(cd, buf);
return ret;
}
class_device_attr_store(struct kobject * kobj, struct attribute * attr,
const char * buf, size_t count)
{
struct class_device_attribute * class_dev_attr = to_class_dev_attr(attr);
struct class_device * cd = to_class_dev(kobj);
ssize_t ret = 0;
if (class_dev_attr->store)
ret = class_dev_attr->store(cd, buf, count);
return ret;
}
可以看出操作函数会根据to_class_dev_attr(attr);找出对应attr的class_dev_attr并调用其对应的show或store
9、
再跟踪一下上文中的dev及uvent属性的定义及其对应的操作函数
attr->attr.name = "dev";
attr->attr.mode = S_IRUGO;
attr->attr.owner = parent_class->owner;
attr->show = show_dev;
error = class_device_create_file(class_dev, attr);
static ssize_t show_dev(struct class_device *class_dev, char *buf)
{
return print_dev_t(buf, class_dev->devt);//上文中将打印出“252:0”
}
class_dev->uevent_attr.attr.name = "uevent";
class_dev->uevent_attr.attr.mode = S_IWUSR;
class_dev->uevent_attr.attr.owner = parent_class->owner;
class_dev->uevent_attr.store = store_uevent;
error = class_device_create_file(class_dev, &class_dev->uevent_attr);
static ssize_t store_uevent(struct class_device *class_dev,
const char *buf, size_t count)
{
kobject_uevent(&class_dev->kobj, KOBJ_ADD);
return count;
}
可以看出无论写入什么值都会触发KOBJ_ADD事件,内核调用kobject_uevent函数发送netlink message给用户空间用户层,用户空间可以用udev通过取到此事件,从而处理热插拔事件。
好了,写完了,希望对大家有点参考价值。
分享到:
相关推荐
在Linux设备模型中,ktype(也称为kobject类型)是一种关键的数据结构,用于定义一类对象(如设备、模块等)在sysfs文件系统中的表示方式。sysfs是一个虚拟文件系统,它允许用户空间程序与内核进行交互,读取或写入...
在 Linux 2.6.29 中,驱动使用设备模型来描述设备的结构和行为,从而使得驱动可以更方便地访问和控制设备。设备模型提供了一种统一的方法来描述设备的结构和行为,从而使得驱动可以更方便地访问和控制设备。 Linux ...
在上篇《利用udev、sys动态创建设备结点》的记录中,设备驱动中主要依靠下面两个功能完成的: 1、在/sys/class下创建farsight_class类 my_class =class_create(THIS_MODULE, "farsight_class"); 2、在...
Linux设备驱动模型是Linux内核中的一个重要组成部分,它负责管理和协调硬件设备的驱动程序,使得操作系统能够有效地控制和通信硬件。设备驱动模型提供了一个抽象层,简化了对各种硬件设备的处理,使得驱动程序的编写...
Linux设备模型是Linux内核中的一个重要组成部分,主要用于管理和组织硬件设备。随着Linux系统的发展,其设备模型也在不断地完善与优化。Linux 2.6版本的设备模型相比之前的版本有了很大的改进,不仅更加模块化,而且...
Linux设备驱动模型是Linux内核中的一个重要组成部分,它为设备驱动程序提供了一套统一的接口和框架,使得驱动程序能够更加高效地管理和控制硬件资源。对于Linux设备驱动工程师来说,深入理解这套模型对于编写高质量...
- **Class**:定义了系统中设备的类型,例如网卡、声卡等。 #### 内核对象机制的关键数据结构 ##### kobject内核对象 kobject是Linux 2.6内核设备模型的核心组成部分,它通过`struct kobject`这一数据结构来实现...
在Linux内核中,设备模型是用来管理硬件资源和软件接口的一种机制。kobject是这个模型中的核心抽象,它提供了一种通用的方法来管理和操作内核中的对象。kobject的使用贯穿于内核的各个部分,从简单的设备到复杂的子...
此外,`/sys/bus` 目录下有各种总线子目录,如PCI、IDE、USB等,用户可以通过这些子目录了解系统中所使用的总线和连接在这些总线上的设备。 sysfs与kobject层次结构紧密相关。kobject是Linux 2.6引入的设备管理机制...