Linux驱动之设备模型(2)

来源:互联网 发布:软件相机 编辑:程序博客网 时间:2024/06/08 12:41

原文地址:  http://blog.csdn.net/hsly_support/article/details/7362949


3.ktype& Kset

3.1  ktype

用来描述一组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);

};

Release 函数当引用计数(kref)减到0时调用,完成销毁工作

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方法用户空间写入属性时调用

Default_attrs 默认属性

struct attribute {

constchar                 *name; 

mode_t                      mode;  

};

 

3.2  kset

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的操作函数

初始化

void kset_init(struct kset*kset);

注册/注销

int  __must_check kset_register(structkset *kset);

void kset_unregister(struct kset *kset);

引用计数加一

struct  kset *kset_get(struct kset*k)

引用计数减一

void kset_put(struct kset*k)

 

3.3  sysfs

Sysfs是一个处于内存中的虚拟文件系统,它为我们供了kobject对象层次结构视图。

 

Sysfs操作

创建属性,在sys下创建一个属性文件

int   sysfs_create_file(struct kobject * kobj,const struct  attribute * attr)

删除属性

void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)

创建二进制属性

 

int  sysfs_create_bin_file(struct kobject *kobj,const structbin_attribute *attr)

删除二进制属性

void sysfs_remove_bin_file(struct kobject *kobj, conststructbin_attribute *attr)

at24.c(eeprom)驱动就是使用这两个函数在sys目录下产生bin文件,此bin文件其实就是对eeprom的映射,可以通过读写这个bin文件来操作eeprom

 

 

3.4  内核事件层

内核事件层实现了内核到用户的消息通知系统,是建立在kobject上的。通过kobject_uevent函数向用户空间发送uevent,来实现热插拔机制。

 

内核事件向用户空间的传递方式

在PC上,经由netlink传递,netlink是一个用于传送网络信息的多点传送套接字。用户空间使用udev来监听内核发送来的uevent并执行相应的热插拔操作

在嵌入式里,使用mdev来实现。

 

 Kobject_uevent,向用户空间发送消息uevent

int kobject_uevent(structkobject *kobj,  enum kobject_actionaction)

kobj:指定发送该信号的koject对象

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

 

试验结果:

Linux驱动之设备模型(2)

Linux驱动之设备模型(2)

原创粉丝点击