DEVICE_ATTR是一个宏,其定义在include/linux/device.h:
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
__ATTR宏定义在include/linux/sysfs.h:
#define __ATTR(_name,_mode,_show,_store) { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
struct device_attribute结构定义在include/linux/device.h:
/* interface for exporting device attributes */
struct device_attribute {
struct attribute attr;
ssize_t (*show)(struct device *dev, struct device_attribute *attr,
char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
};
DEVICE_ATTR宏展开:
#define DEVICE_ATTR(_name, _mode, _show, _store) \
struct device_attribute dev_attr_##_name = { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
}
举例说明DEVICE_ATTR使用方法:
static DEVICE_ATTR(msm_gpio, 0664, msmgpio_show, msmgpio_store);
static ssize_t msmgpio_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
int temp[5];
struct gpio_data *gpio_data_ptr = dev_get_drvdata(dev);
temp[0] = gpio_get_value(gpio_data_ptr->gpio0);
temp[1] = gpio_get_value(gpio_data_ptr->gpio2);
temp[2] = gpio_get_value(gpio_data_ptr->gpio3);
temp[3] = gpio_get_value(gpio_data_ptr->gpio10);
temp[4] = gpio_get_value(gpio_data_ptr->gpio11);
return snprintf(buf, 6, "%d%d%d%d%d", temp[0], temp[1],
temp[2], temp[3], temp[4]);
}
static ssize_t msmgpio_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct gpio_data *gpio_data_ptr = dev_get_drvdata(dev);
gpio_set_value(gpio_data_ptr->gpio0, (buf[0] == '1') ? 1 : 0);
gpio_set_value(gpio_data_ptr->gpio2, (buf[1] == '1') ? 1 : 0);
gpio_set_value(gpio_data_ptr->gpio3, (buf[2] == '1') ? 1 : 0);
gpio_set_value(gpio_data_ptr->gpio10, (buf[3] == '1') ? 1 : 0);
gpio_set_value(gpio_data_ptr->gpio11, (buf[4] == '1') ? 1 : 0);
return size;
}
static DEVICE_ATTR(msm_gpio, 0664, msmgpio_show, msmgpio_store);
之后在驱动的probe函数中即可调用device_create_file:
err = device_create_file(&dev->dev, &dev_attr_msm_gpio);
if (err) {
dev_err(&dev->dev, "sys file creation failed\n");
return -ENODEV;
}
device_create_file和device_remove_file定义在drivers/base/core.c中,声明在include/linux/device.h中,device_create_file返回0代表创建成功。
int device_create_file(struct device *dev, const struct device_attribute *attr)
{
int error = 0;
if (dev) {
WARN(((attr->attr.mode & S_IWUGO) && !attr->store),
"Attribute %s: write permission without 'store'\n",
attr->attr.name);
WARN(((attr->attr.mode & S_IRUGO) && !attr->show),
"Attribute %s: read permission without 'show'\n",
attr->attr.name);
error = sysfs_create_file(&dev->kobj, &attr->attr);
}
return error;
}
void device_remove_file(struct device *dev,
const struct device_attribute *attr)
{
if (dev)
sysfs_remove_file(&dev->kobj, &attr->attr);
}
在文件系统/sys/devices/soc.0/gpio_ctrl.72下面生成msm_gpio节点,用cat,echo操作硬件:
root@msm8909:/sys/devices/soc.0/gpio_ctrl.72 # ls -l msm_gpio
-rw-rw-r– root root 4096 1970-01-01 00:02 msm_gpio
root@msm8909:/sys/devices/soc.0/gpio_ctrl.72 # cat msm_gpio
00000
root@msm8909:/sys/devices/soc.0/gpio_ctrl.72 # echo 11111 > msm_gpio