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

Linux kernel 内核模块将许多设备属性导出到用户空间,linux-kernel,kernel-module,sysfs,Linux Kernel,Kernel Module,Sysfs,我正在使用I2C设备的内核驱动程序,到目前为止,我一直在使用sysfs device\u ATTR helper提供简单属性。现在我需要列出一长串可用的属性,比如/sys/bus/i2c/device/../param0、/param1等。但是为每个属性编写函数似乎效率低下,甚至可能是错误地使用了sysfs系统。例如: static DEVICE_ATTR(param0, S_IRUGO, NULL, foo_set_param0); static DEVICE_ATTR(param1, S_I

我正在使用I2C设备的内核驱动程序,到目前为止,我一直在使用sysfs device\u ATTR helper提供简单属性。现在我需要列出一长串可用的属性,比如/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回调上使用包装器来获取参数吗?还是有更好的系统可以用?我查看了debugfs,似乎需要在内存中为它维护值。

您可以尝试container\u 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