内核设备模型之为kobject添加属性文件
//为内核对象添加属性文件
//如何通过文件系统配置内核空间的kobject的属性
//对属性文件操作
struct kobj_type *ktype;
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);
};
struct sysfs_ops {
ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);
};
struct sysfs_ops 定义一组对内核struct attribute 操作的函数
struct attribute {
const char *name; //名字
struct module *owner;
mode_t mode; //属性
};
sysfs_create_file //create an attribute file for an object.
int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
//添加属性文件
//例子:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kobject.h>
static struct kobject * parent = NULL;
static struct kobject * child = NULL;
static struct attribute child_attr = {
.name = "child_attr",
.mode = S_IRUSR,
};
static int __init kobject_test_init(void)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
parent = kobject_create_and_add("pa_obj",NULL);
child = kobject_create_and_add("pb_obj",parent);
sysfs_create_file(child, &child_attr); //添加一个文件
return 0;
}
static void __exit kobject_test_exit(void)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
sysfs_remove_file(child, &child_attr); //删除文件
kobject_del(child);
kobject_del(parent);
}
module_init(kobject_test_init);
module_exit(kobject_test_exit);
//测试后 在/pa_obj/pb_obj/路径下会有一个 child_attr
那么怎么对 child_attr文件的操作 ?
app: open("/pa_obj/pb_obj/child_attr",O_RDONLY)
sys_open
...
sysfs_open_file(struct inode *inode, struct file *file) // fs/sysfs/file.c
struct sysfs_buffer *buffer;
const struct sysfs_ops *ops;
ops = kobj->ktype->sysfs_ops; // 获取到驱动中的sysfs_ops
buffer->needs_read_fill = 1;
buffer->ops = ops;
file->private_data = buffer; //放进私有数据
对属性文件的读:
ssize_t read(int fd, void *buf, size_t count);
sys_read
.....
static ssize_t sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
struct sysfs_buffer * buffer = file->private_data;
fill_read_buffer(file->f_path.dentry,buffer);
const struct sysfs_ops * ops = buffer->ops;
count = ops->show(kobj, attr_sd->s_attr.attr, buffer->page); //调用ktyte中注册的show函数
对属性文件的写操作
ssize_t write(int fd, void *buf, size_t count);
sys_write
......
sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
struct sysfs_buffer * buffer = file->private_data;
len = fill_write_buffer(buffer, buf, count);
buffer->page = (char *)get_zeroed_page(GFP_KERNEL);
error = copy_from_user(buffer->page,buf,count);
en = flush_write_buffer(file->f_path.dentry, buffer, len);
const struct sysfs_ops * ops = buffer->ops;
rc = ops->store(kobj, attr_sd->s_attr.attr, buffer->page, count); //调用ktype中注册的store函数
例子:
//对内核对象的属性操作
int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,struct kobject *parent, const char *fmt, ...)
//例子
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include <linux/slab.h>
static struct kobject * parent = NULL;
static struct kobject * child = NULL;
static struct attribute child_attr = {
.name = "child_attr",
.mode = S_IRUSR|S_IWUSR,
};
static ssize_t attr_show(struct kobject *kobj, struct attribute *attr,char *buf)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
return 0;
}
//为什么 一直 store 需要返回count
static ssize_t attr_store (struct kobject *kobj,struct attribute *attr,const char *buf, size_t count)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
printk(KERN_INFO"buf[0] = 0x%x",*buf);
printk(KERN_INFO"buf[1] = 0x%x",*buf);
//return count
return count;
}
static struct sysfs_ops attr_ops ={
.show = attr_show,
.store = attr_store,
};
static struct kobj_type attr_ktype={
.sysfs_ops = &attr_ops,
};
static int __init kobject_test_init(void)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
parent = kobject_create_and_add("pa_obj",NULL);
//child = kobject_create();
child = kzalloc(sizeof(*child), GFP_KERNEL);
if (!child)
return NULL;
kobject_init_and_add(child ,&attr_ktype, parent, "pb_obj");
sysfs_create_file(child, &child_attr);
return 0;
}
static void __exit kobject_test_exit(void)
{
printk(KERN_INFO "%s\n",__FUNCTION__);
sysfs_remove_file(child, &child_attr);
kobject_del(child);
kobject_del(parent);
}
module_init(kobject_test_init);
module_exit(kobject_test_exit);
MODULE_AUTHOR("derrick email: kjfure@163.com");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Kobject test Module");
MODULE_ALIAS("Kobject test Module");
//测试
写 : echo '1' > /sys/pa_obj/pa_obj/child_attr
读 : cat /sys/pa_obj/pa_obj/child_attr