• 20150225 IMX257 设备驱动模型之Kobject(三)


    20150225 IMX257 设备驱动模型之Kobject(三)

    2012-02-25 李海沿

        刚才我们整理了一大批乏味的知识点,但是相信大家已经大概的了解了sysfs 的原理了。

    这里我们趁热打铁,将前面我们那个似懂非懂的kobject程序一步拿下。

    我们这个程序的目的是,在sys目录下面创建一个kboject_test目录和一个名为kobject_test的属性文件,我们可以使用cat去读取其文件名。

    前面虽然解释了kobject程序的大概工作流程,这次我们再次详细的说明一下其工作流程,然后再附上今天注有详细解释的kobject驱动程序代码:

    一、工作流程:

    1. 定义kobject结构体

    kboject结构体定义如下:

    struct kobject{

        const char *name; //显示在sysfs中的名称

        struct list_head entry;   //下一个kobject结构

        struct kobject *parent;  //指向父kobject结构体,如果存在

        struct kset    *kset;   //指向kset集合

        struct kobj_type   *ktype; //指向kobject类型描述符

        struct sysfs_dirent *sd; //对应sysfs的文件目录

        struct kref kref;   //kobject引用计数

        unsigned int state_initialized:1; //是否初始化

        unsigned int state_in_sysfs:1; //是否加入sysfs

        unsigned int state_add_uevent_sent:1; //是否支持热插

        unsigned int state_remove_uevent_sent:1; //是否支持热拔

    }

    既然定义了kobject结构体,但是这是一个空的结构体,并没有什么属性,所以自然我们就是定义它的属性结构体属性 kobj_type 类描述符

    2. 定义kobj_type结构体

    kobje结构体定义如下:

    struct kobj_type

    {

      void (*release)(struct kobject *kobj); //释放kobject和其他占用资源的函数

      struct sysfs_ops *sysfs_ops;      //操作属性的方法

      struct attribute **default_attrs;     //属性数组

    };

    所以自然我们就要实现结构体中的 释放函数,操作属性方法,和属性数组

    2.1 release函数实现 属性释放方法

    这里我们release函数只是简单的打印一句话,实际项目中的release可能包含各种代码,视具体功能而定

    2.2 sysfs_ops结构体 属性操作方法

    如图所示,sys_ops中就是定义了对属性文件的读写操作调用的函数

    其原型结构体如下:

    struct sysfs_ops{

      ssize_t (*show)(struct kobject *,struct attribute *,char *);  //读属性操作函数

      ssize_t (*store)(struct kobject *,struct attribute *,const char *,size_t); //写属性操作函数

    };

    2.3 default_attrs属性数组

    在注释中已经讲得很详细了,它也可以理解为在sys的文件夹中的属性文件,结构体就对应属性文件

    2.3.1 test_attr属性结构体

    同样在代码中已经解释的很详细了,可以这样理解,这个结构体中所有的属性就是在属性文件中的文件内容

    其原型如下:

    struct attribute {

    const char *name;

    struct module *owner;

    mode_t mode;

    };

    #define __ATTR(_name,_mode,_show,_store) {

    .attr = {.name = __stringify(_name), .mode = _mode },

    .show = _show,

    .store = _store,

    }

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

    int __must_check sysfs_create_dir(struct kobject *kobj);

    3. 添加kobject进入内核

    到此为止,我们呢已经将kobject基本的属性、方法等都实现了,下面自然就是将它加入结构体,告诉操作系统啊,

    我们此处init函数唯一的操作就是将它加入注册进入操作系统,让操作系统认识这个结构体。

    4. 从内核中删除操作系统

    有添加自然就会有删除

    如图所示,简简单单的几个字却要这么多话来为它解释。

    具体工作流程这里就不赘述了

    二、带详细注释的源代码

      1 #include <linux/device.h>
      2 #include <linux/module.h>
      3 #include <linux/kernel.h>
      4 #include <linux/init.h>
      5 #include <linux/string.h>
      6 #include <linux/sysfs.h>
      7 #include <linux/stat.h>
      8 
      9 //定义一个名为kobject_test,可以读写的属性
     10 //这个结构体就是定义我们 /sys/kobject_test/kobject_test属性文件的属性
     11 //当我们使用cat去读时,
     12 //系统会调用kobject_test_show从而打印出属性文件的name属性
     13 //并且我们可以通过echo "Lover雪儿" > kobject_test命令去写入时
     14 //系统会调用kobject_test_store将.name这个属性修改为我们自定义的"Lover雪儿"
     15 //总结一下,它的功能就是 /sys/kobject_test/下面的属性文件
     16 struct attribute test_attr = {
     17     .name = "kobject_test",        //属性名
     18     .mode = S_IRWXUGO,            //属性为可读可写
     19 };
     20 
     21 //我们要使用kobject自然就要定义一个kobject属性
     22 //其实这个结构体就是 会在 /sys/目录下建立一个文件夹 
     23 //文件夹的名字在init函数kobject_init_and_add中定义的那个名字
     24 //总结一下,这个结构体的功能就是在sys目录下建立这个文件夹
     25 //然后我们文件夹中有的属性文件,只要在它下面添加就行了
     26 //该kobject只有一个属性就是前面定义的test_attr
     27 static struct attribute *def_attrs[] = {
     28     &test_attr,
     29     NULL,    
     30 };
     31 
     32 //当kobject的引用计数为0时,会自动调用此函数,
     33 //当我们在exit函数中调用kobject_del(&kobj);时
     34 //在del中主要的操作就是在sysfs中删除kobj
     35 //然后将kboj从kset集合中删除
     36 //然后将kobj的父目录设置为空
     37 //最重要的是将父目录的引用计数设为0 ,
     38 //系统检测到引用计数为0,就会调用此函数
     39 void kobject_test_release(struct kobject *kobject){
     40     printk("kobject_test: kobject_test_release() . 
    ");
     41 }
     42 
     43 //读属性的名字
     44 //在系统空间当我们使用cat命令对属性文件进行读取时,
     45 //系统就会自动调用此函数,将前面我们test_attr的.name属性打印出来
     46 ssize_t kobject_test_show(struct kobject *kobject, struct attribute *attr, char *buf){
     47     printk("call kobject_test_show(). 
    ");        /*调试信息*/
     48     printk("attrname: %s.
    ",attr->name);    //打印属性名字
     49     sprintf(buf,"%s
    ",attr->name);        //将名字方法buf中返回用户空间
     50     return strlen(attr->name) + 2;
     51 }
     52 
     53 //写一属性的值
     54 //和前面读属性函数差不多,这里就是把我们的test_attr的.name属性重新赋一个值
     55 ssize_t kobject_test_store(struct kobject *kobject,struct attribute *attr, const char *buf, size_t count){
     56     printk("call kobject_test_store(). 
    ");    /*调试信息*/
     57     printk("write: %s.
    ",buf);                    //打印属性名字
     58     strcpy(attr->name, buf);                    //写一个属性
     59     return count;
     60 }
     61 
     62 //前面我们实现了对属性文件读和写的方法,
     63 //但是操作系统如何才知道那两个函数时读写函数
     64 //重点就在这里,和以前我们的字符函数file_operation差不多
     65 //这里就是告诉系统,当发生读写操作时,分别调用什么函数
     66 struct sysfs_ops obj_test_sysops = {
     67     .show = kobject_test_show,    //属性读函数
     68     .store = kobject_test_store,    //属性写函数
     69 };
     70 
     71 //后面代码中我们使用struct kobject kobj;
     72 //但是kobj的属性只是一个空的结构体而已
     73 //它又有哪些属性呢,答案就在这里,这里定义了kobject的默认属性
     74 //.realease 当删除kobject时会调用的函数
     75 //.sysfs_ops 当系统对属性文件进行读写是,会调用的函数,也就是前面我们的sysfs_ops这个结构体
     76 //.default_atrs 默认的属性,就是定义我们/sys/kobject/目录下有哪些属性文件
     77 struct kobj_type ktype={
     78     .release = kobject_test_release,    //释放函数
     79     .sysfs_ops = &obj_test_sysops,        //属性的操作函数
     80     .default_attrs = def_attrs,            //默认属性
     81 };
     82 
     83 //此处定义我们的kobject结构体
     84 struct kobject kobj;        //要添加的kobject结构
     85 
     86 //初始化函数
     87 static int kobject_test_init(void){
     88     printk("kobject test_init(). 
    ");
     89 
     90     //此处,就是将我们的kobject函数注册进入系统。
     91     //arg1:既然要注册kobject,此处自然是我们前面定义的kboj这个机构提
     92     //arg2:ktype前面我定义的属性,这里就是将我们的kobject和ktype联系起来
     93     //arg3:此处就是定义kobj的父kobject结构体
     94     //arg4:此处就是定义我们kobject的属性的目录名字
     95     kobject_init_and_add(&kobj, &ktype, NULL, "kobject_test");
     96 
     97     return 0;
     98 }
     99 
    100 static int kobject_test_exit(void){
    101     printk("kobject test_exit. 
    ");
    102     
    103     //前面说过了
    104     //当我们在exit函数中调用kobject_del(&kobj);时
    105     //在del中主要的操作就是在sysfs中删除kobj
    106     //然后将kboj从kset集合中删除
    107     //然后将kobj的父目录设置为空
    108     //最重要的是将父目录的引用计数设为0 ,
    109     //系统检测到引用计数为0,就会调用前面的release函数
    110     kobject_del(&kobj);        //删除kobject
    111     return 0;
    112 }
    113 
    114 module_init(kobject_test_init);
    115 module_exit(kobject_test_exit);
    116 
    117 MODULE_AUTHOR("Lover雪儿");
    118 MODULE_LICENSE("Dual BSD/GPL");
  • 相关阅读:
    CentOS7 安装Redis Cluster集群
    CentOS7 安装Redis 单机版
    CentOS7 配置免密登陆
    深入java虚拟机学习 -- 内存管理机制
    深入java虚拟机学习 -- 类的卸载
    深入java虚拟机学习 -- 类的加载机制(四)
    深入java虚拟机学习 -- 类的加载机制(三)
    深入java虚拟机学习 -- 类的加载机制(续)
    (原创)cocos lua 热更新从零开始(一)最简单demo
    lua 调用参数报错(a userdata value)
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4299390.html
Copyright © 2020-2023  润新知