您的位置:首页 > 运维架构 > Linux

Linux驱动之设备模型(2)

2013-04-23 09:03 344 查看

原文地址: /article/7669642.html

3.ktype& Kset
3.1 ktype
l 用来描述一组kobject所具有的共同特性,用struct kobj_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)(structkobject *kobj);
const void *(*namespace)(structkobject*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;
mode_t mode;
};

3.2 kset
l Kset是kobject对象的集合体。把它看成是一个容器,可将所有相关的kobject对象放到同一位置,比如块设备在/sys/block下。
struct kset {
struct list_head list;
spinlock_t list_lock;
struct kobject kobj;
const struct kset_uevent_ops *uevent_ops;
};
因为内嵌一个kobject,所以在sysfs中也表现为一个目录
l Kset的操作函数
n 初始化
void kset_init(struct kset*kset);
n 注册/注销
int __must_check kset_register(structkset *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 struct attribute * attr)
n 删除属性
void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
n 创建二进制属性

int sysfs_create_bin_file(struct kobject *kobj,const structbin_attribute *attr)
n 删除二进制属性
void sysfs_remove_bin_file(struct kobject *kobj, conststructbin_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
int kobject_uevent(structkobject *kobj, enum kobject_actionaction)
n kobj:指定发送该信号的koject对象
n action:描述该信号的动作
KOBJ_ADD, 添加
KOBJ_REMOVE, 移除
Andso on…

3.5 实例解析

#include
#include
#include
#include
#include
#include

struct foo_obj {
struct kobject kobj;
int foo;
int soo;
int coo;
};
#define to_foo_obj(x) container_of(x, struct foo_obj, kobj)

struct foo_attribute {
struct attribute attr;
ssize_t(*show)(struct foo_obj *foo, structfoo_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, structattribute *attr,
char*buf)
{
struct foo_attribute *attribute;
struct foo_obj *foo;

attribute= to_foo_attr(attr);
foo= to_foo_obj(kobj);

if(!attribute->show) //公共属性的 show调用了attribute->show,所以sysfs_ops只是一个接口,为要调用attribute->show
return-EIO;
return attribute->show(foo, attribute,buf);
}

static ssize_t foo_attr_store(struct kobject*kobj, struct attribute *attr,
const
char *buf, size_t len)
{
struct foo_attribute *attribute;
struct foo_obj *foo;

attribute = to_foo_attr(attr);
foo= to_foo_obj(kobj);

if(!attribute->store)
return-EIO;
return attribute->store(foo, attribute,buf, len);
}

static conststruct sysfs_ops foo_sysfs_ops={ //公共属性操作方法
.show = foo_attr_show,
.store = foo_attr_store,
};

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, structfoo_attribute *attr,
char*buf)
{
return sprintf(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(structfoo_obj*foo_obj, struct foo_attribute *attr,
char*buf)
{
return sprintf(buf, "%d\n",foo_obj->soo);
}

static ssize_t soo_store(struct foo_obj*foo_obj, structfoo_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 structfoo_attribute soo_attribute =
__ATTR(soo,0666, soo_show, soo_store);

static structfoo_attribute coo_attribute =
__ATTR(coo,0666, soo_show, soo_store);

static struct attribute * foo_default_attrs[]=
{
&foo_attribute.attr,
&soo_attribute.attr,
NULL,
};

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)
{
struct foo_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 __initexample_init(void)
{
kset_example = kset_create_and_add("kset_example", NULL, NULL); //创建kset
if(!kset_example)
return-ENOMEM;

foo_obj= create_foo_obj("foo");
//创建kobject,用foo_ktype,有foo_attribute.attr和soo_attribute.attr
if(!foo_obj)
gotofoo_error;

soo_obj= create_foo_obj("soo"); //创建kobject,用foo_ktype,有foo_attribute.attr和soo_attribute.attr
if(!soo_obj)
gotosoo_error;

sysfs_create_file(&foo_obj->kobj,&coo_attribute.attr);
//为kobject (foo_obj)添加新的属性coo_attribute

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");

试验结果:


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: