如何为 sysfs 属性创建许多类似的函数?
How can I create lots of similar functions for sysfs attributes?
我的 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 用例?
我可能遗漏了一些东西,但你不想制作 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.
你的 _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);
在 include/linux/device.h 中定义的 DEVICE_ULONG_ATTR
宏中使用了类似的方法。该宏为 'long'.
类型的变量创建一个属性
我的 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 用例?
我可能遗漏了一些东西,但你不想制作 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.
你的 _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);
在 include/linux/device.h 中定义的 DEVICE_ULONG_ATTR
宏中使用了类似的方法。该宏为 'long'.