【问题标题】:How can I create lots of similar functions for sysfs attributes?如何为 sysfs 属性创建许多类似的函数?
【发布时间】:2018-01-31 10:46:42
【问题描述】:

我的 FPGA 中有一个带有多个 I/O 寄存器的通用 AXI 从设备。我想使用 sysfs 接口访问我的寄存器。对于我想访问的每个寄存器,我创建了一个_show 和一个_store 函数,但这会是很多代码。

static ssize_t writereg0_store(struct device *dev, struct device_attribute                *attr, const char *buf, size_t count) {
    struct axi_register_driver *drv = dev_get_drvdata(dev);
    u32 val;

    if (kstrtou32(buf, 10, &val) != 0)
        return -EINVAL;

    iowrite32(val, drv->reg_base + WRITE_OFFSET + 0);

    return count;

}

static ssize_t writereg0_show(struct device *dev, struct device_attribute *attr, char *buf) {
    struct axi_register_driver *drv = dev_get_drvdata(dev);

    u32 reg;
    reg = ioread32(drv->reg_base + WRITE_OFFSET + 0);

    return sprintf(buf, "0x%x\n", reg);
}
static DEVICE_ATTR_RW(writereg0);

static ssize_t readreg0_show(struct device *dev, struct device_attribute *attr, char *buf) {
    struct axi_register_driver *drv = dev_get_drvdata(dev);

    u32 reg;
    reg = ioread32(drv->reg_base + 0);

    return sprintf(buf, "0x%x\n", reg);
}
static DEVICE_ATTR_RO(readreg0);

第二个只读寄存器基本相同,只是函数名和地址偏移:

static ssize_t readreg1_show(struct device *dev, struct device_attribute *attr, char *buf) {
    struct axi_register_driver *drv = dev_get_drvdata(dev);

    u32 reg;
    reg = ioread32(drv->reg_base + OFF_REG1);

    return sprintf(buf, "0x%x\n", reg);
}
static DEVICE_ATTR_RO(readreg1);

当创建例如32 个寄存器,我必须这样做 32 次;代码不会很漂亮。

那么创建一堆类似函数的最佳方法是什么,尤其是对于给定的 sysfs-attribute 用例?

【问题讨论】:

  • 这里没有问题。您可以编辑您的帖子以清楚地说明您想要回答的内容吗?例如“我怎样才能生成许多相似的结构和功能”之类的。
  • 顺便说一句,我对内核源代码的阅读表明它的sprintf() 支持# 修饰符,就像用户空间sprintf() 一样,所以你可以简单地写%#x 而不是0x%x .
  • @TobySpeight 谢谢,我不知道。

标签: c linux linux-kernel linux-device-driver sysfs


【解决方案1】:

您的 _show_store 函数不使用 struct device_attribute *attr 参数,但该参数旨在包含有关给定文件表示的特定事物的信息:

// Derive 'device_attribute' structure for a read register's attribute
struct dev_axi_read_reg_attribute {
    struct device_attribute attr;
    int reg_offset; // Offset of the register here
};

// Generic 'show' method, suitable for every read register
static ssize_t read_axi_reg_show(struct device *dev, struct device_attribute *attr, char *buf) {
    struct axi_register_driver *drv = dev_get_drvdata(dev);
    // 'attr' is actually of type `struct dev_axi_read_reg_attribute`.
    // See definition of the macro 'AXI_READ_REG_ATTR' below.
    struct dev_axi_read_reg_attribute* axi_read_attr = container_of(attr,
        struct dev_axi_read_reg_attribute, attr);

    u32 reg;
    // Take offset to the register from the attribute
    reg = ioread32(drv->reg_base + axi_read_attr->reg_offset);

    return sprintf(buf, "0x%x\n", reg);
}

// Macro for declare attribute for read register
#define AXI_READ_REG_ATTR(_name, _reg_offset) \
struct dev_axi_read_reg_attribute dev_attr_##_name = \
    { __ATTR(_name,  S_IRUGO, read_axi_reg_show, NULL), _reg_offset }

// Declare as many attributes as you want
static AXI_READ_REG_ATTR(readreg0, OFF_REG0);
static AXI_READ_REG_ATTR(readreg1, OFF_REG1);
// ...

static struct attribute *axi_register_attrs[] = {
    &dev_attr_readreg0.attr.attr,
    &dev_attr_readreg1.attr.attr,
    // ...
    NULL,
};
ATTRIBUTE_GROUPS(axi_register);

DEVICE_ULONG_ATTR 宏中使用了类似的方法,在include/linux/device.h 中定义。该宏为“long”类型的变量创建一个属性。

【讨论】:

    【解决方案2】:

    我可能遗漏了一些东西,但你不想制作 32 个包装器吗:

    static ssize_t readreg_show(struct device *dev, struct device_attribute *attr, char *buf,unsigned long offset) {
        struct axi_register_driver *drv = dev_get_drvdata(dev);
    
        u32 reg;
        reg = ioread32(drv->reg_base + offset);
    
        return sprintf(buf, "0x%x\n", reg);
    }
    

    也许可以定义 32:

    static ssize_t readreg1_show(struct device *dev, struct device_attribute *attr, char *buf) {readreg_show(dev,attr,buf,OFF_REG1)}
    

    (每个 reg 一个)如果您需要不同的函数名称?这可能是 MACROd,如果复制 32 次真的很麻烦,如果偏移量都是 OFF_REGi。

    【讨论】:

      猜你喜欢
      • 2016-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-17
      相关资源
      最近更新 更多