DEVICE_ATTR分析

来源:互联网 发布:胡歌车祸知乎 编辑:程序博客网 时间:2024/05/21 10:43

使用DEVICE_ATTR,可以在sys fs中添加“文件”,通过修改该文件内容,可以实现在运行过程中动态控制device的目的。
在documentation/driver-model/Device.txt中有对DEVICE_ATTR的详细介绍,这儿主要说明使用方法。
DEVICE_ATTR对应的文件在/sys/devices/目录中对应的device下面,DRIVER_ATTR,BUS_ATTR,CLASS_ATTR分别在driver,bus,class中对应的目录下。

DEVICE_ATTR(_name, _mode, _show, _store)_name:名称,也就是将在sys fs中生成的文件名称。_mode:上述文件的访问权限,与普通文件相同,UGO的格式。_show:显示函数,cat该文件时,此函数被调用。_store:写函数,echo内容到该文件时,此函数被调用。

模式可以为只读0444,只写0222,或者读写都行的0666。

显示函数的一般实现:

static ssize_t xxx_show(struct device *dev, struct device_attribute *attr, char *buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", dma_dump_flag);}

我自己写的驱动

/** * irfpa_show_nucdata() - This function show the nucdata register. * @dev:    Pointer to the device structure. * @attr:   Pointer to the device attribute structure. * @buf:    Pointer to the buffer location for the configuration *      data. * returns: size of the buffer. **/static ssize_t irfpa_show_nucdata(struct device *dev,        struct device_attribute *attr, char *buf){    u32 nucdata;    ssize_t status;    struct irfpa_drvdata *drvdata = (struct irfpa_drvdata *)dev_get_drvdata(dev);    nucdata = irfpa_readreg(drvdata->irfpa_base_address + IRFPA_NUCDATA);    //status = sprintf(buf, "0x%08x\n", ctrl);    status = sprintf(buf, "%d\n", nucdata);    return status;}//*******************************************************

写入函数的一般实现:

static ssize_t xxx_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ unsigned long num; if (strict_strtoul(buf, 0, &num))  return -EINVAL; if (num < 0)  return -EINVAL; mutex_lock(&xxx_lock);//加了个lock进行互斥。 dma_dump_flag = num; mutex_unlock(&xxx_lock); return count;}

我自己写的写入函数:

/** * irfpa_set_nucdata() - This function sets the nucdata register. * @dev:    Pointer to the device structure. * @attr:   Pointer to the device attribute structure. * @buf:    Pointer to the buffer location for the configuration data. * @size:   The number of bytes used from the buffer * returns: -EINVAL if invalid parameter is sent or size **/static ssize_t irfpa_set_nucdata(struct device *dev,                     struct device_attribute *attr,                     const char *buf, size_t size){    unsigned long nucdata;    ssize_t status;    struct irfpa_drvdata *drvdata = (struct irfpa_drvdata *)dev_get_drvdata(dev);    status = strict_strtoul(buf, 10, &nucdata);    if (status)        return status;    irfpa_writereg(drvdata->irfpa_base_address + IRFPA_NUCDATA, nucdata);    return size;}

预先设置好这些后,就对这些进行注册:
1:static DEVICE_ATTR(xxx, 0666, xxx_show, xxx_store);

static DEVICE_ATTR(type, 0444, show_type, NULL);static DEVICE_ATTR(power, 0644, show_power, store_power);

该代码可以防止文件的任何位置,只要别引起编译错误!

static DEVICE_ATTR(irfpa_nucdata,0644,irfpa_show_nucdata,irfpa_set_nucdata);

DEVICE_ATTR的功能就是定义一个device_attribute结构体对象,作为设备的一个属性,如果定义了这个属性就把这个属性加入到group中
2:第二步:加入到属性中:

static struct attribute *dev_attrs[] = {    &dev_attr_type.attr,    &dev_attr_power.attr,    NULL,};

3:然后再封装

static struct attribute_group dev_attr_group = {    .attrs = dev_attrs,};

4:在利用sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);创建接口。这个代码最好放在device的probe函数中。

通 过以上简单的几个步骤,就可以在终端查看到接口了。当我们将数据 echo 到接口中时,在上层实际上完成了一次 write 操 作,对应到 kernel ,调用了驱动中的 “wirte”。同理,当我们cat 一个 接口时则会调用 “show” 。到这里,只是简单的建立 了 应用 层到 kernel 的桥梁,真正实现对硬件操作的,还是在 “show” 和 “set” 中完成的。

0 0