20150223 IMX257 设备驱动模型之Kobject(一)
2015-02-23 李海沿
接下来我们开始涉及设备驱动模型,从简入深,我们先写一个驱动,实现的功能就是在sys目录下建立一个目录和一个属性文件,可读可写。
所以今天的任务就是把这个程序搞定,只要把这几个结构体了解,知道有这个结构体就够了,很晚了,剩下的我们交给明天吧。
一、结构体参数解释
1. kobject
kobject是设备驱动模型的基础。sysfs是基于kobject建立起来的。
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; //是否支持热拔 } |
2. kobj_type
每个kobject都会有一个属性kobj_type
struct kobj_type { void (*release)(struct kobject *kobj); //释放kobject和其他占用资源的函数 struct sysfs_ops *sysfs_ops; //操作属性的方法 struct attribute **default_attrs; //属性数组 }; |
3. sysfs_ops
struct sysfs_ops{ ssize_t (*show)(struct kobject *,struct attribute *,char *); //读属性操作函数 ssize_t (*store)(struct kobject *,struct attribute *,const char *,size_t); //写属性操作函数 }; |
4. 描述属性文件的结构
sysfs文件系统中,最重要的就是struct attribute结构,它被用来管理内核sysfs文件的接口(名字,属性,读写函数等)。内核sysfs提供了基本的attribute接口,不同的设备如bus、device在基本attribute的基础上定义了自己的读写函数,sysfs提供了对应的宏来简化属性的操作。请参考<linux/sysfs.h>头文件中。
struct attribute { const char *name; struct module *owner; mode_t mode; }; #define __ATTR(_name,_mode,_show,_store) { \ int __must_check sysfs_create_file(struct kobject *kobj, const struct attribute *attr); |
5. 定义操作函数
我们看到,sysfs的struct attribute结构本身并不包含读写访问函数,驱动模型的各个部分都会扩展这个结构并定义自己的属性结构来引入各自的操作函数,如 class:(这个结构定义在<linux/device.h>头文件中)。
struct class_attribute { struct attribute attr; ssize_t (*show)(struct class *, char * buf); ssize_t (*store)(struct class *, const char * buf, size_t count); }; #define CLASS_ATTR(_name, _mode, _show, _store) struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store) |
二、驱动程序详解
1. 定义相关结构体
首先从大的开始,我们先实现一个框架,我们也就先定义一个kobject结构体,接下来就是定义sysfs_ops和 kobj_type 这两个结构体。
在kobj_type中将 属性结构体 连接起来。
2. 定义属性结构体
框架搭建好了,我们接下来的任务就是前面我们所说的建立 属性文件夹和属性文件。
3.在init函数中,将kobject注册入内核
4.在exit函数中 删除我们注册的kobject
5.编译测试
附上驱动代码:
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 struct attribute test_attr = { 11 .name = "kobject_test", //属性名 12 .mode = S_IRWXUGO, //属性为可读可写 13 }; 14 //该kobject只有一个属性 15 static struct attribute *def_attrs[] = { 16 &test_attr, 17 NULL, 18 }; 19 20 void kobject_test_release(struct kobject *kobject){ 21 printk("kobject_test: kobject_test_release() . \n"); 22 } 23 //读属性的名字 24 ssize_t kobject_test_show(struct kobject *kobject, struct attribute *attr, char *buf){ 25 printk("call kobject_test_show(). \n"); /*调试信息*/ 26 printk("attrname: %s.\n",attr->name); //打印属性名字 27 sprintf(buf,"%s\n",attr->name); //将名字方法buf中返回用户空间 28 return strlen(attr->name) + 2; 29 } 30 //写一属性的值 31 ssize_t kobject_test_store(struct kobject *kobject,struct attribute *attr, const char *buf, size_t count){ 32 printk("call kobject_test_store(). \n"); /*调试信息*/ 33 printk("write: %s.\n",buf); //打印属性名字 34 strcpy(attr->name, buf); //写一个属性 35 return count; 36 } 37 38 struct sysfs_ops obj_test_sysops = { 39 .show = kobject_test_show, //属性读函数 40 .store = kobject_test_store, //属性写函数 41 }; 42 43 struct kobj_type ktype={ 44 .release = kobject_test_release, //释放函数 45 .sysfs_ops = &obj_test_sysops, //属性的操作函数 46 .default_attrs = def_attrs, //默认属性 47 }; 48 49 struct kobject kobj; //要添加的kobject结构 50 static int kobject_test_init(void){ 51 printk("kobject test_init(). \n"); 52 kobject_init_and_add(&kobj, &ktype, NULL, "kobject_test"); 53 54 return 0; 55 } 56 57 static int kobject_test_exit(void){ 58 printk("kobject test_exit. \n"); 59 kobject_del(&kobj); //删除kobject 60 return 0; 61 } 62 63 module_init(kobject_test_init); 64 module_exit(kobject_test_exit); 65 66 MODULE_AUTHOR("Lover雪儿"); 67 MODULE_LICENSE("Dual BSD/GPL");