You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为FPGA的AXI-slave设备寄存器批量创建sysfs属性函数?

Great question! When dealing with large numbers of identical sysfs attributes for memory-mapped registers (like your AXI slave registers), preprocessor macros are the standard Linux kernel way to eliminate redundant code. They let you generate all the repetitive _show/_store functions and device attribute definitions in a single line per register.

Step 1: Define Reusable Macros

First, create macros that encapsulate the common logic for read-only and read-write registers. These macros will generate the full function definitions and DEVICE_ATTR declarations automatically.

For Read-Only Registers

#define DEFINE_READ_REG_ATTR(name, reg_offset) \
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) { \
    struct axi_register_driver *drv = dev_get_drvdata(dev); \
    u32 reg_val = ioread32(drv->reg_base + (reg_offset)); \
    return sprintf(buf, "0x%x\n", reg_val); \
} \
static DEVICE_ATTR_RO(name)

For Read-Write Registers

#define DEFINE_RW_REG_ATTR(name, reg_offset) \
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) { \
    struct axi_register_driver *drv = dev_get_drvdata(dev); \
    u32 reg_val = ioread32(drv->reg_base + (reg_offset)); \
    return sprintf(buf, "0x%x\n", reg_val); \
} \
static ssize_t name##_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; \
    /* Use base 0 to support both decimal and hex input (e.g., "123" or "0x7b") */ \
    if (kstrtou32(buf, 0, &val) != 0) \
        return -EINVAL; \
    iowrite32(val, drv->reg_base + (reg_offset)); \
    return count; \
} \
static DEVICE_ATTR_RW(name)

Step 2: Generate Attributes for Your Registers

Now you can create all 32 registers with just one line each. For example:

// Read-only registers
DEFINE_READ_REG_ATTR(readreg0, 0);
DEFINE_READ_REG_ATTR(readreg1, OFF_REG1);
// ... add 30 more read-only registers here ...

// Read-write registers
DEFINE_RW_REG_ATTR(writereg0, WRITE_OFFSET + 0);
// ... add other RW registers here ...

Step 3: Group Attributes for Easy Registration

To add these attributes to your device, create an attribute array and group:

static struct attribute *axi_reg_attrs[] = {
    &dev_attr_readreg0.attr,
    &dev_attr_readreg1.attr,
    &dev_attr_writereg0.attr,
    // ... add pointers to all your generated attributes ...
    NULL, /* Terminate the array */
};

static const struct attribute_group axi_reg_attr_group = {
    .attrs = axi_reg_attrs,
};

Then in your driver's probe function, register the group with:

int ret = device_add_groups(dev, &axi_reg_attr_group);
if (ret) {
    dev_err(dev, "Failed to add sysfs attributes\n");
    return ret;
}

Key Notes

  • The ## in the macros is the token pasting operator—it combines the name parameter with _show/_store to create the function names (e.g., readreg0 becomes readreg0_show).
  • Using kstrtou32(buf, 0, &val) instead of base 10 lets users input values in decimal or hexadecimal (more flexible for register access).
  • All generated code is resolved at compile time, so there's no runtime overhead compared to writing each function manually.

This approach keeps your code clean, maintainable, and avoids the error-prone process of copying/pasting 32 identical function definitions.

内容的提问来源于stack exchange,提问作者Franz Forstmayr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:42:36