2

我正在使用 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 显示回调上使用包装器来获取参数吗?或者我应该为此使用更好的系统吗?我查看了 debugfs ,似乎我需要为它维护内存中的值。

4

1 回答 1

3

您可以尝试 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
于 2015-03-25T15:05:21.767 回答