sysfs接口函数的建立_DEVICE_ATTR

本文详细介绍了sysfs接口函数的使用,包括DEVICE_ATTR宏的定义与应用,以及如何通过sysfs接口实现Sensor驱动的操作。通过简单的步骤,可以建立Android层与Kernel层之间的桥梁,实现对硬件的直接操作。

sysfs接口函数的建立_DEVICE_ATTR

2012-08-08 15:02 by superlcc, 9304 阅读, 0 评论, 收藏编辑

sysfs接口函数到建立_DEVICE_ATTR


最近在弄Sensor驱动,看过一个某厂家的成品驱动,里面实现的全都是sysfs接口,hal层利用sysfs生成的接口,对Sensor进行操作。

说道sysfs接口,就不得不提到函数宏 DEVICE_ATTR

原型是#define DEVICE_ATTR(_name, _mode, _show, _store) \

struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)

函数宏DEVICE_ATTR内封装的是__ATTR(_name,_mode,_show,_stroe)方法,_show表示的是读方法,_stroe表示的是写方法。

当然_ATTR不是独生子女,他还有一系列的姊妹__ATTR_RO宏只有读方法,__ATTR_NULL等等

如 对设备的使用  DEVICE_ATTR  ,对总线使用  BUS_ATTR  ,对驱动使用 DRIVER_ATTR  ,对类 别 (class) 使用  CLASS_ATTR,  这四个高级的宏来自于<include/linux/device.h> 

DEVICE_ATTR  宏声明有四个参数,分别是名称、权限位、读函数、写函数。其中读函数和写函数是读写功能函数的函数名。

如果你完成了DEVICE_ATTR函数宏的填充,下面就需要创建接口了

例如:

    static DEVICE_ATTR(polling, S_IRUGO | S_IWUSR, show_polling, set_polling);
    static struct attribute *dev_attrs[] = {
            &dev_attr_polling.attr,
            NULL,
    };

当你想要实现的接口名字是polling的时候,需要实现结构体struct attribute *dev_attrs[]

其中成员变量的名字必须是&dev_attr_polling.attr

然后再封装

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

 

在利用sysfs_create_group(&pdev->dev.kobj, &dev_attr_grp);创建接口

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


######################################################################

以下来个例子:


/*
 * Sample kobject implementation
 *
 * Copyright (C) 2004-2007 Greg Kroah-Hartman <greg@kroah.com>
 * Copyright (C) 2007 Novell Inc.
 *
 * Released under the GPL version 2 only.
 *
 */
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/gpio.h>
#include <linux/delay.h>

/*
 * This module shows how to create a simple subdirectory in sysfs called
 * /sys/kernel/kobject-example  In that directory, 3 files are created:
 * "foo", "baz", and "bar".  If an integer is written to these files, it can be
 * later read out of it.
 */

static int foo;

/*
 * The "foo" file where a static variable is read from and written to.
 */

static struct msm_gpio qup_i2c_gpios_io[] = {
     { GPIO_CFG(60, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
           "qup_scl" },
     { GPIO_CFG(61, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
           "qup_sda" },
     { GPIO_CFG(131, 0, GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
           "qup_scl" },
     { GPIO_CFG(132, 0, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
           "qup_sda" },
};

static struct msm_gpio qup_i2c_gpios_hw[] = {
     { GPIO_CFG(60, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
           "qup_scl" },
     { GPIO_CFG(61, 1, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
           "qup_sda" },
     { GPIO_CFG(131, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
           "qup_scl" },
     { GPIO_CFG(132, 2, GPIO_CFG_INPUT, GPIO_CFG_NO_PULL, GPIO_CFG_8MA),
           "qup_sda" },
};

static void gsbi_qup_i2c_gpio_config(int adap_id, int config_type)
{
     int rc;

     if (adap_id < 0 || adap_id > 1)
           return;

     /* Each adapter gets 2 lines from the table */
     if (config_type)
           rc = msm_gpios_enable(&qup_i2c_gpios_hw[adap_id*2], 2);
     else
           rc = msm_gpios_enable(&qup_i2c_gpios_io[adap_id*2], 2);
     if (rc < 0)
           pr_err("QUP GPIO request/enable failed: %d\n", rc);
}

static ssize_t foo_show(struct kobject *kobj, struct kobj_attribute *attr,
    char *buf)
{
      return sprintf(buf, "%d\n", foo);
}

static ssize_t foo_store(struct kobject *kobj, struct kobj_attribute *attr,
      const char *buf, size_t count)
{
     int sda,scl;
     int i;
     sscanf(buf, "%du", &foo);
     printk("foo = %d.\n",foo);

     foo = foo -1;

     if  (foo < 0 || foo > 1)
     {
           printk("input foo error. foo=%d.\n",foo);
           return 0;
     }
           
      sda = GPIO_PIN((&qup_i2c_gpios_hw[foo*2+1])->gpio_cfg);
      scl = GPIO_PIN((&qup_i2c_gpios_hw[foo*2])->gpio_cfg);
      
     printk("sda = %d.\n",sda);
     printk("scl = %d.\n",scl);
     
     gsbi_qup_i2c_gpio_config(foo,0);

     for(i=0;i<9;i++)
     {
           if(gpio_get_value(sda))
           {
                printk("sda of i2c%d is high when %d pulse is output on scl.\n",foo,i);
                break;
           }
           gpio_set_value(scl,0);
           udelay(5);
           gpio_set_value(scl,1);
           udelay(5);
     }
     
     gsbi_qup_i2c_gpio_config(foo,1);

     printk("finish.\n");
     return count;
}

static struct kobj_attribute foo_attribute =
      __ATTR(i2c_unlock, 0666, foo_show, foo_store);

/*
 * Create a group of attributes so that we can create and destroy them all
 * at once.
 */
static struct attribute *attrs[] = {
      &foo_attribute.attr,
      NULL,»  /* need to NULL terminate the list of attributes */
};

/*
 * An unnamed attribute group will put all of the attributes directly in
 * the kobject directory.  If we specify a name, a subdirectory will be
 * created for the attributes with the directory being the name of the
 * attribute group.
 */
static struct attribute_group attr_group = {
      .attrs = attrs,
};

static struct kobject *example_kobj;

static int __init example_init(void)
{
     int retval;

     /*
      * Create a simple kobject with the name of "kobject_example",
      * located under /sys/kernel/
      *
      * As this is a simple directory, no uevent will be sent to
      * userspace.  That is why this function should not be used for
      * any type of dynamic kobjects, where the name and number are
      * not known ahead of time.
      */
     example_kobj = kobject_create_and_add("i2c_recovery", kernel_kobj);
     if (!example_kobj)
          return -ENOMEM;

     /* Create the files associated with this kobject */
     retval = sysfs_create_group(example_kobj, &attr_group);
     if (retval)
          kobject_put(example_kobj);

     return retval;
}

static void __exit example_exit(void)
{
     kobject_put(example_kobj);
}

module_init(example_init);
module_exit(example_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Wupeng");

<think> 我们被要求回答关于DEVICE_ATTR函数的问题。根据提供的引用,我们可以总结如下: 1. DEVICE_ATTR是一个宏,用于定义一个设备属性(device_attribute结构体)。 2. 它用于在sysfs中创建文件,这些文件位于设备目录下(通常在/sys/devices/.../)。 3. 宏的定义在<linux/device.h>中。 4. 它接受四个参数:属性名(_name)、文件权限(_mode)、显示函数(_show)和存储函数(_store)。 5. 显示函数用于读取属性值(当用户读取sysfs文件时调用),存储函数用于写入属性值(当用户写入sysfs文件时调用)。 6. 使用DEVICE_ATTR宏会创建一个名为`dev_attr_<name>`的结构体变量。 根据引用[1],DEVICE_ATTR的作用是定义一个device_attribute对象,然后可以将其加入到设备的属性组中。例如,在dev_attrs数组中添加。 引用[2]和[3]展示了宏定义: ```c #define DEVICE_ATTR(_name, _mode, _show, _store) \ struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) ``` 引用[4]说明DEVICE_ATTR对应的文件位于/sys/devices/下相应设备的目录中,并且还有类似的宏(如DRIVER_ATTR、BUS_ATTR、CLASS_ATTR)分别对应不同的目录。 引用[5]给出了结构体device_attribute的定义,以及展示和存储函数的原型。 因此,我们可以这样介绍DEVICE_ATTRDEVICE_ATTR是Linux内核中用于创建设备属性的宏。通过这个宏,开发者可以在sysfs文件系统中为设备添加属性文件,从而允许用户空间程序读取或设置设备的内核内部状态。每个属性对应sysfs中的一个文件,位于设备的目录下。 使用步骤通常包括: 1. 使用DEVICE_ATTR宏定义一个设备属性,指定名称、权限以及读写函数。 2. 将该属性添加到设备的属性数组中(例如,通过.dev_attrs指针或使用属性组)。 读写函数的原型: - 读函数(show):`ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);` - 写函数(store):`ssize_t (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);` 例如,定义一个名为“test”的属性,权限为0644(用户可读写,组和其他可读): ```c static ssize_t test_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "Test\n"); } static ssize_t test_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { // 根据buf的内容进行相应处理 return count; } static DEVICE_ATTR(test, 0644, test_show, test_store); ``` 然后,在设备的结构体中,需要包含这个属性。通常,我们会定义一个属性数组,将属性包含进去,然后将该数组赋给设备结构体的属性组。 注意:在Linux内核中,使用sysfs的机制可以方便地进行设备驱动和用户空间的交互。 根据上述分析,我们给出回答。 </think>### DEVICE_ATTR函数详解 `DEVICE_ATTR`是Linux内核驱动开发中用于创建设备属性的核心宏,主要用于在sysfs文件系统中动态生成设备属性文件。其功能原理和使用方法如下: #### 1. **功能本质** - 定义`device_attribute`结构体对象,作为设备的可配置属性 - 在sysfs中生成对应文件(路径:`/sys/devices/.../设备目录/`) - 提供用户空间与内核驱动的交互接口(读/写操作) #### 2. **宏定义原型** ```c #define DEVICE_ATTR(_name, _mode, _show, _store) \ struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) ``` 参数说明: - `_name`:属性文件名(生成文件名为`_name`) - `_mode`:文件权限(如0644) - `_show`:读回调函数指针 - `_store`:写回调函数指针 #### 3. **数据结构** 生成的`device_attribute`结构: ```c 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); // 写操作函数 }; ``` #### 4. **使用流程** **(1) 定义回调函数** ```c // 读回调(cat命令触发) static ssize_t attr_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "Current value: %d\n", value); } // 写回调(echo命令触发) static ssize_t attr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { sscanf(buf, "%d", &value); return count; } ``` **(2) 声明设备属性** ```c static DEVICE_ATTR(custom_value, 0644, attr_show, attr_store); ``` 生成结构体变量:`dev_attr_custom_value` **(3) 添加到sysfs** ```c device_create_file(dev, &dev_attr_custom_value); ``` #### 5. **sysfs交互示例** ```bash # 用户空间读取属性 cat /sys/devices/platform/mydevice/custom_value # 用户空间设置属性 echo 100 > /sys/devices/platform/mydevice/custom_value ``` #### 6. **同类宏对比** | 宏名称 | sysfs路径 | 作用域 | |---------------|------------------------|----------------| | `DEVICE_ATTR` | `/sys/devices/...` | 设备级属性 | | `DRIVER_ATTR` | `/sys/bus/.../drivers` | 驱动级属性 | | `BUS_ATTR` | `/sys/bus/...` | 总线级属性 | | `CLASS_ATTR` | `/sys/class/...` | 设备类别属性 | #### 典型应用场景 1. 动态配置设备参数(如寄存器值) 2. 实时获取设备状态(如传感器数据) 3. 调试驱动行为(运行时修改调试级别) 4. 固件升级接口(通过文件写入固件数据) [^1][^2][^3][^4][^5]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值