内核模块将许多设备属性导出到用户空间

时间:2014-09-26 03:40:56

标签: linux-kernel kernel-module sysfs

我正在使用I2C设备的内核驱动程序,到目前为止,我一直在使用sysfs DEVICE_ATTR助手创建简单的属性。现在我需要制作一长串可用的属性,如/sys/bus/i2c/device/.../param0,../ param1等,但为每个属性编写一个函数似乎效率低下甚至是错误使用sysfs系统。例如:

static DEVICE_ATTR(param0, S_IRUGO, NULL, foo_set_param0);
static DEVICE_ATTR(param1, S_IRUGO, NULL, foo_set_param1);
...
static DEVICE_ATTR(param50, S_IRUGO, NULL, foo_set_param50);

设备上的值经常变化并且读取它们很昂贵,因此不断阅读它们或使用一个功能来读取它们并不是真正的选择。我有一点C新手,所以也许有一些非常明显我缺失的东西,但是你可以在sysfs show callback上使用包装器来获取参数吗?或者,我应该使用更好的系统吗?我查看了debugfs,似乎我需要为它维护内存中的值。

1 个答案:

答案 0 :(得分:2)

您可以尝试使用container_of()宏。只需在更大的结构中填充属性数据即可。

以下是在big_kattr大结构中创建100个属性的示例。参数是UNIT_NUM。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>

#define UNIT_NUM    100

typedef struct {
    struct kobj_attribute k_obj;
    int num;
} big_kattr;

static struct kobject *register_kobj;

// rw functions
static ssize_t __used store_value(struct kobject *kp, struct     kobj_attribute *attr, const char *buf, size_t count){ 
    big_kattr *a = container_of(attr, big_kattr, k_obj);
    sscanf(buf, "%du", &a->num);
    return count;
}

static ssize_t show_value(struct kobject *kp, struct kobj_attribute *attr, char *buf) {
    big_kattr *a = container_of(attr, big_kattr, k_obj);
    return sprintf(buf, "%d\n", a->num);
}

// put attribute to attribute group
static struct attribute * unit_attrs[UNIT_NUM + 1];
static big_kattr full_unit_attrs[UNIT_NUM];
static struct attribute_group  unit_attr_group;

static int hello_init(void){
    int i;
    memset(full_unit_attrs, 0, sizeof(full_unit_attrs));
    memset(unit_attrs, 0, sizeof(unit_attrs));
    memset(&unit_attr_group, 0, sizeof(unit_attr_group));

    for(i=0; i<UNIT_NUM; i++){
        char * str = kmalloc(32, GFP_KERNEL);
        sprintf(str, "unit-%03d",i);
        full_unit_attrs[i].k_obj.attr.name = str;
        full_unit_attrs[i].k_obj.attr.mode = S_IWUSR | S_IRUGO;
        full_unit_attrs[i].k_obj.show  = show_value;
        full_unit_attrs[i].k_obj.store = store_value;
        full_unit_attrs[i].num  = i;

        unit_attrs[i] = &(full_unit_attrs[i].k_obj.attr);
    }
    unit_attr_group.attrs = unit_attrs;
    // create sysfs object ( /sys/kernel/many directory )
    register_kobj = kobject_create_and_add("many", kernel_kobj);
    if (!register_kobj)
        return -ENOMEM;

    //create all attributes (files)
    if(sysfs_create_group(register_kobj, &unit_attr_group)){
        kobject_put(register_kobj);
        return -ENOMEM;
    }

    return 0;
}

static void hello_exit(void){
    int i;
    kobject_put(register_kobj);
    for(i=0; i<UNIT_NUM; i++)
        kfree(full_unit_attrs[i].k_obj.attr.name);
}

MODULE_LICENSE("Dual BSD/GPL");
module_init(hello_init);
module_exit(hello_exit);

示例:

cat /sys/kernel/many/unit-077
echo 12345 > /sys/kernel/many/unit-088
cat /sys/kernel/many/unit-088