linux ------ 设备驱动模型之一(sysfs, koject, kset)

        随着linux系统越来越成熟,设备驱动加入了一些新的特性,之前独立的设备驱动已经无法胜任这种工作,于是linux系统找出一种方式,让各种设备及其驱动程序有效的联系起来,形成一个“群体”,这就是设备驱动模型。

        设备驱动模型最基本的元素包括:sysfs, kobject, kset。

         一. sysfs是2.6版本之后加入的一个文件系统接口,它把内核里面的各种kobject, kset 联系起来,通过文件接口的方式跟外界的沟通与互动,实现用户空间与内核空间之间数据对象的交互。sysfs取代proc文件系统的部分功能,实现ioctl的功能。如果用老的设备文件的方式来控制设备,需要先open设备文件,再调用ioctl来发控制命令,需要一个完整的应用程序来实现,现在有了sysfs,一个简单的shell命令,比如cat 或 echo 命令就能完成ioctl的功能。

         sysfs的初始化发生在linux系统启动阶段,调用的代码如下:

         int __init sysfs_init()

         {

                   err = register_filesystem(&sysfs_fs_type);

                   if(!err)

                             sysfs_mount = kern_mount(&sysfs_fs_type);

                   els

                             goto out_err;

         }

         sysfs 文件系统是居于RAM实现的文件系统,内核编译时需要指定 CONFIG_SYSFS 选项。sysfs的标准挂载点是"/sys"目录,挂载命令为:mount -t sysfs sysfs /sys

所有内核层面对sysfs文件树的操作,都显示在用户空间的"/sys”目录下。

         二. koject是一个内核对象,kset是同类型的kobject对象的一个集合,kobject与kset是设备驱动模型最基本的数据单位,它们在内部的联系构成了一个设备的驱动模型。   

         1. kobject的数据结构定义:

         struct kobject {

                const char  *name;           //内核对象名称,在sysfs文件系统中作为一个目录,即在目录"/sys"下的一个子目录。

                struct list_head  entry;      //将一系列的内核对象构成链表。

                struct kobject  *parent;      //该内核对象的上层内核对象节点,构成内核对象的层次关系。

                struct kset   *kset;              //该内核对象所属的kset对象指针,它容纳同类型的kobject 对象。

                struct kobj_type  *ktype;    //该内核对象一组sysfs文件系统相关的操作函数和属性,不同类型的内核对象有不同的ktype。

                struct sysfs_dirent  *sd;    //该内核对象在sysfs文件系统中对应的目录项的实例。

                struct kref   kref;                  //表示该内核对象的引用计数,核心数据是一个原子型变量,通过该成员追踪内核对象的生命周期。

        };

        kobject 数据结构最通用的用法是嵌入在某一个设备的对象数据结构中,比如字符设备cdev中就嵌入了一个kobject成员。

        struct cdev {

                struct kobject kobj;

                struct module *owner;

                const struct file_operations *ops;

                struct list_head list;

                dev_t  dev;

                unsigned int count;

       };

       2. kobject 常用操作函数

             (1).  int kobject_set_name(struct kobject *kobj, const char *fmt, ...);   //设定kobject中name成员。

             (2). void kobject_init(struct kobject *kobj, struct kobj_type *ktype);       //初始化一个内核对象的数据结构。

             (3). int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...); //建立kobject的层次关系,并在sysfs文件系统中创建一个目录。

             (4). int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...);//实际是把kobject_init与kobject_add合在一起。

             (5). struct kobject *kobject_create(void); //分配并初始化一个kobject内核对象。

             (6). struct kobject *kobject_create_and_add(const char *name, struct kobject *parent); //先分配并初始化一个内核对象,然后调用kobject_add在sysfs中创建新目录

             (7). void kobject_del(struct kobject *kobj);  //在sysfs文件系统文件树中把内核对象对应的目录删掉,如果该对象属于某kset的话,将其从kset链表中删除。

        3. kobject 的类型属性

             数据结构:

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

             release是一个函数指针,重点的是sysfs_ops, 它的结构定义为:

             struct sysfs_ops {
                     ssize_t (*show)(struct kobject *, struct attribute *,char *);
                     ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
                     const void *(*namespace)(struct kobject *, const struct attribute *);
              };

             sysfs_ops实际就是对struct attribute对象的操作。

      三.  kset

             1. kset 就是一组kobject的集合,是kobject的容器。kset本身也是一个内核对象,所以需要内嵌一个kobject对象,数据结构为:

             struct kset {
                      struct list_head list;    //将其中的kobject对象构建成链表。
                      spinlock_t list_lock;    //对链表进行访问时用来作为互斥保护用的自旋锁。
                      struct kobject kobj;      //当前内核对象的kobject变量。
                      const struct kset_uevent_ops *uevent_ops;  //一组函数指针,kobject发生变化时调用这些函数通知用户空间。
             };

             2. 主要操作函数

                 (1). void kset_init(struct kset *k);     //初始化一个kset对象。

                 (2). int kset_register(struct kset *k);  //初始化并向系统注册一个kset对象。

                 (3). struct kset *kset_create_and_add(const char *name, const struct kset_uevent_ops *uevent_ops, struct kobject *parent_kobj);//动态产生一个kset对象并加入到sysfs文件系统。

                 (4). void kset_unregister(struct kset *k);  //将k指向的kset从系统中注销。

      四.  例子实现代码

             1. 包含头文件

                  #include <linux/kobject.h>

                  #include <linux/sysfs.h>

             2. 定义相关变量

                  static struct kobject *parent;

                  static sturct kobject *child;

                  static struct kset *c_kset;

                  static unsigned long flag=1;

             3. 属性操作函数

                  static ssize_t att_show(struct kobject *kobj, struct attribute *attr, char *buf)

                  {

                            size_t count=0;

                            count += sprintf(&buf[count], "%lu\n", flag);

                            return count;

                  }

                  static ssize_t att_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count)

                  {

                           flag = buf[0] - '0';

                           switch(flag)

                           {

                                     case 0:

                                                kobject_uevent(kobj, KOBJ_ADD);

                                                break;

                                     case 1:

                                                kobject_uevent(kobj, KOBJ_REMOVE);

                                                break;

                           }

                           return count;

                  }

             4. 属性对象、sysfs_ops及kobj_type对象

                 static struct attribute cld_att= {

                                     .name = "cldatt",

                                     .mode = S_IRUGO | S_IWUSR,

                            };

                  static const struct sysfs_ops att_ops= {

                                     .show = att_show,

                                     .store = att_store,

                           };

                  static sturct kobj_type cld_ktype= {

                                     .sysfs_ops = &att_ops,

                           };

             5. 初始化函数,创建并向系统加入kobject, kset

                 static int kobj_demo_init()

                 {

                           int err;

                           parent = kobject_create_and_add("pa_obj", NULL);

                           child = kzalloc(sizeof(*child), GFP_KERNEL);

                           if(!child)

                                  return PTR_ERR(child);

 

                            c_kset = kset_create_and_add("c_kset", NULL, parent);

                            if(!c_kset)

                                   return -1;

                            child->kset = c_kset;

                            err = sysfs_create_file(child, &cld_att);

                            return err;

                 }

             6. 注销函数

                 static void kobj_demo_exit(void)

                 {

                         sysfs_remove_file(child, &cld_att);

                         kset_unregister(c_kset);

                         kobject_del(child);

                         kobject_del(parent);

                 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值