Linux驱动之设备模型(2)
3.ktype& Kset3.1 ktypel 用来描述一组kobject所具有的共同特性,用structkobj_type结构体来表示struct kobj_type{ void (*release)(struct kobject *kobj); const struct sysfs_ops *sysfs_ops; st
3.ktype& Kset
3.1 ktype
l 用来描述一组kobject所具有的共同特性,用structkobj_type结构体来表示
struct kobj_type{
void (*release)(struct kobject *kobj);
const struct sysfs_ops *sysfs_ops;
struct attribute **default_attrs;
const struct kobj_ns_type_operations*(*child_ns_type)(struct kobject *kobj);
const void *(*namespace)(struct kobject*kobj);
};
n Release 函数当引用计数(kref)减到0时调用,完成销毁工作
n Sysfs_ops定义属性的操作方法
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *,size_t);
constvoid *(*namespace)(struct kobject *, const struct attribute *);
};
Show方法用户空间读取属性时调用
Store方法用户空间写入属性时调用
n Default_attrs 默认属性
struct attribute {
constchar *name; /* 属性名,对应在sysfs中为文件名 */
mode_t mode; /* 权限 */
};
3.2 kset
l Kset是kobject对象的集合体。把它看成是一个容器,可将所有相关的kobject对象放到同一位置,比如块设备在/sys/block下。
struct kset {
struct list_head list; /* 链表头,把包含所有的kobject组成一个链表 */
spinlock_t list_lock; /* */
struct kobject kobj; /* 内嵌的kobject */
const struct kset_uevent_ops*uevent_ops; /* uevent操作 */
};
因为内嵌一个kobject,所以在sysfs中也表现为一个目录
l Kset的操作函数
n 初始化
void kset_init(struct kset *kset);
n 注册/注销
int __must_check kset_register(struct kset *kset);
void kset_unregister(struct kset *kset);
n 引用计数加一
struct kset *kset_get(struct kset *k)
n 引用计数减一
void kset_put(struct kset *k)
3.3 sysfs
l Sysfs是一个处于内存中的虚拟文件系统,它为我们提供了kobject对象层次结构视图。
l Sysfs操作
n 创建属性,在sys下创建一个属性文件
int sysfs_create_file(struct kobject * kobj, const structattribute * attr)
n 删除属性
void sysfs_remove_file(struct kobject * kobj, const structattribute * attr)
n 创建二进制属性
int sysfs_create_bin_file(struct kobject *kobj, const structbin_attribute *attr)
n 删除二进制属性
void sysfs_remove_bin_file(struct kobject *kobj, const structbin_attribute *attr)
at24.c(eeprom)驱动就是使用这两个函数在sys目录下产生bin文件,此bin文件其实就是对eeprom的映射,可以通过读写这个bin文件来操作eeprom。
3.4 内核事件层
l 内核事件层实现了内核到用户的消息通知系统,是建立在kobject上的。通过kobject_uevent函数向用户空间发送uevent,来实现热插拔机制。
l 内核事件向用户空间的传递方式
n 在PC上,经由netlink传递,netlink是一个用于传送网络信息的多点传送套接字。用户空间使用udev来监听内核发送来的uevent并执行相应的热插拔操作
n 在嵌入式里,使用mdev来实现。
l Kobject_uevent,向用户空间发送消息uevent
intkobject_uevent(struct kobject *kobj, enum kobject_action action)
n kobj:指定发送该信号的koject对象
n action:描述该信号的动作
KOBJ_ADD, 添加
KOBJ_REMOVE, 移除
Andso on…
3.5 实例解析
/*
* for learn kobject, kset, ktype
*/
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
struct foo_obj {
structkobject kobj;
intfoo;
intsoo;
intcoo;
};
#define to_foo_obj(x) container_of(x, struct foo_obj, kobj)
struct foo_attribute {
structattribute attr;
ssize_t(*show)(struct foo_obj *foo, struct foo_attribute *attr, char *buf);
ssize_t(*store)(struct foo_obj *foo, struct foo_attribute *attr,
constchar *buf, size_t count);
};
#define to_foo_attr(x) container_of(x, struct foo_attribute, attr)
/* 公共的属性操作方法 */
static ssize_t foo_attr_show(struct kobject*kobj, struct attribute *attr,
char*buf)
{
structfoo_attribute *attribute;
structfoo_obj *foo;
attribute= to_foo_attr(attr);
foo= to_foo_obj(kobj);
if(!attribute->show)
return-EIO;
returnattribute->show(foo, attribute, buf);
}
static ssize_t foo_attr_store(structkobject *kobj, struct attribute *attr,
constchar *buf, size_t len)
{
structfoo_attribute *attribute;
structfoo_obj *foo;
attribute= to_foo_attr(attr);
foo= to_foo_obj(kobj);
if(!attribute->store)
return-EIO;
returnattribute->store(foo, attribute, buf, len);
}
static const struct sysfs_ops foo_sysfs_ops= {
.show = foo_attr_show,
.store = foo_attr_store,
};
/* 销毁函数,当引用计数(kref)减为0时调用 */
static void foo_release(struct kobject*kobj)
{
structfoo_obj *foo;
foo= to_foo_obj(kobj);
kfree(foo);
}
/* 属性操作方法 */
static ssize_t foo_show(struct foo_obj*foo_obj, struct foo_attribute *attr,
char*buf)
{
returnsprintf(buf, "%d\n", foo_obj->foo);
}
static ssize_t foo_store(struct foo_obj*foo_obj, struct foo_attribute *attr,
constchar *buf, size_t count)
{
sscanf(buf,"%du", &foo_obj->foo);
returncount;
}
static ssize_t soo_show(struct foo_obj*foo_obj, struct foo_attribute *attr,
char*buf)
{
returnsprintf(buf, "%d\n", foo_obj->soo);
}
static ssize_t soo_store(struct foo_obj*foo_obj, struct foo_attribute *attr,
constchar *buf, size_t count)
{
sscanf(buf,"%du", &foo_obj->soo);
returncount;
}
/*
*构造文件属性
*/
static struct foo_attribute foo_attribute =
__ATTR(foo,0666, foo_show, foo_store);
static struct foo_attribute soo_attribute =
__ATTR(soo,0666, soo_show, soo_store);
static struct foo_attribute coo_attribute =
__ATTR(coo,0666, soo_show, soo_store);
/*
*添加foo_attribute.attr和soo_attribute.attr为foo_obj的默认属性
*/
static struct attribute*foo_default_attrs[] = {
&foo_attribute.attr,
&soo_attribute.attr,
NULL,
};
/*
*定义foo_obj公共属性和操作
*/
static struct kobj_type foo_ktype = {
.sysfs_ops = &foo_sysfs_ops,
.release = foo_release,
.default_attrs= foo_default_attrs,
};
static struct kset *kset_example;
static struct foo_obj *foo_obj;
static struct foo_obj *soo_obj;
static struct foo_obj *create_foo_obj(constchar *name)
{
structfoo_obj *foo;
intret;
foo= kzalloc(sizeof(*foo), GFP_KERNEL);
if(!foo)
returnNULL;
foo->kobj.kset= kset_example;
foo->foo= 6;
foo->soo= 7;
ret= kobject_init_and_add(&foo->kobj, &foo_ktype, NULL, "%s",name);
if(ret) {
kobject_put(&foo->kobj);
returnNULL;
}
/*通知用户空间 */
kobject_uevent(&foo->kobj,KOBJ_ADD);
returnfoo;
}
static void destroy_foo_obj(struct foo_obj*foo)
{
kobject_put(&foo->kobj);
}
static int __init example_init(void)
{
kset_example= kset_create_and_add("kset_example", NULL, NULL);
if(!kset_example)
return-ENOMEM;
foo_obj= create_foo_obj("foo");
if(!foo_obj)
gotofoo_error;
soo_obj= create_foo_obj("soo");
if(!soo_obj)
gotosoo_error;
/*添加新的属性 */
sysfs_create_file(&foo_obj->kobj,&coo_attribute.attr);
return0;
soo_error:
destroy_foo_obj(foo_obj);
foo_error:
kset_unregister(kset_example);
return-EINVAL;
}
static void __exit example_exit(void)
{
sysfs_remove_file(&foo_obj->kobj,&coo_attribute.attr);
destroy_foo_obj(soo_obj);
destroy_foo_obj(foo_obj);
kset_unregister(kset_example);
}
module_init(example_init);
module_exit(example_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("CJOK<cjok.liao@gmail.com>");
试验结果:
更多推荐
所有评论(0)