kernel debug方法之DEVICE_ATTR 和 sysfs

本文详细介绍了Linux内核中的sysfs文件系统接口及DEVICE_ATTR宏的使用方法。通过具体示例,展示了如何创建sysfs接口并实现读写功能。

说道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  宏声明有四个参数,分别是名称、权限位、读函数、写函数。其中读函数和写函数是读写功能函数的函数名。

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

例如:

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

 eg:staticDEVICE_ATTR(proximity_poll_delay, S_IRUGO | S_IWUGO,  proximity_poll_delay_show, proximity_poll_delay_store);          


static struct device_attribute dev_attr_proximity_enable =
__ATTR(enable, S_IRUGO | S_IWUGO,    proximity_enable_show, proximity_enable_store);


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

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

  eg:  static struct attribute *proximity_sysfs_attrs[] = {
&dev_attr_proximity_enable.attr,
&dev_attr_proximity_poll_delay.attr,

2、然后再封装

    static structattribute_group dev_attr_grp = {
            .attrs = dev_attrs,
    };

  eg:static struct attribute_group proximity_attribute_group = {
.attrs = proximity_sysfs_attrs,


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


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


其实呢?!用个proc文件系统的就知道,这个就和proc中的write和read一样的,以我的理解:proc有点老了,以后肯定会大量使用attribute,proc好比是Windows XP,attribute就像是Windows Seven

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

以下来个例子:


/*
 * 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("kobject_example", 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");


From:http://www.cnblogs.com/superlcc/archive/2012/08/08/2628290.html

<think>我们正在讨论Linux内核中的属性机制,具体是`kobj_attribute``device_attribute`的区别用途。根据提供的引用内容,我们可以总结如下: 1. **kobj_attribute**: - 引用[1]提到,可以在kobj所在目录下创建一个属性文件,文件名为`attr->name`。这里使用的函数是`sysfs_create_file``sysfs_remove_file`,操作对象是`struct kobject``struct attribute`。 - `kobj_attribute`结构体通常定义如下(未直接给出,但可推断): ```c struct kobj_attribute { struct attribute attr; ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf); ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); }; ``` - 它用于与任意`kobject`关联的属性,提供`show``store`函数来读写属性值。 2. **device_attribute**: - 引用[2]给出了`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); }; ``` - 引用[3]详细说明了`DEVICE_ATTR`宏,它用于声明设备属性文件。该宏的参数包括属性名、权限、show函数store函数。 - `device_attribute`是专门为`struct device`设计的,它是对`kobj_attribute`的封装,因为`struct device`内嵌了一个`struct kobject`。 **区别与用途**: - **作用对象不同**: - `kobj_attribute`用于任何`kobject`(它是设备模型的基础,但不仅限于设备)。 - `device_attribute`专用于`struct device`(代表一个设备)。 - **函数参数不同**: - `kobj_attribute`的回调函数接收`struct kobject *`作为第一个参数。 - `device_attribute`的回调函数接收`struct device *`作为第一个参数,这更方便设备驱动开发者,因为可以直接操作设备结构。 - **创建宏不同**: - `kobj_attribute`通常使用`__ATTR`或`__ATTR_RW`等宏来静态初始化。 - `device_attribute`使用`DEVICE_ATTR`宏来声明,该宏会自动生成一个名为`dev_attr_<name>`的结构体变量,并初始化其中的`attr`、`show``store`成员。 - **使用场景**: - 当你在为一个设备(如字符设备、总线设备等)创建属性时,应使用`device_attribute`,因为它与设备模型紧密集成,且更方便(例如,在`sysfs`中会自动出现在设备目录下)。 - 当你为其他类型的`kobject`(如一个模块自己的kobject)创建属性时,使用`kobj_attribute`。 **示例**: - 使用`DEVICE_ATTR`声明一个设备属性: ```c static DEVICE_ATTR(foo, 0644, show_foo, store_foo); ``` 然后,在设备驱动中,可以通过`device_create_file``device_remove_file`来创建删除该属性文件。 - 使用`kobj_attribute`则需要自己定义并初始化: ```c static struct kobj_attribute bar_attr = __ATTR(bar, 0644, bar_show, bar_store); ``` 然后,在拥有kobject的地方,使用`sysfs_create_file`来创建。 总结:`device_attribute`是设备驱动中常用的属性类型,它是对`kobj_attribute`的封装,专门用于设备。而`kobj_attribute`则更通用,适用于所有kobject。 §§相关问题§§ 1. 在Linux内核中,如何为一个设备创建多个属性文件? 2. 除了`kobj_attribute``device_attribute`,还有哪些类型的属性结构体? 3. 在sysfs中创建属性文件时,权限模式(如0644)中的SUID/GUID位有什么特殊含义吗?</think>### kobj_attribute 与 device_attribute 的区别与用途 在 Linux 内核中,`kobj_attribute` `device_attribute` 都是用于在 sysfs 文件系统中创建属性文件的机制,但它们的应用场景对象层次不同: #### 1. **kobj_attribute (通用 kobject 属性)** - **作用对象**:面向任意 `kobject` 对象(内核对象的基础抽象) - **结构定义**: ```c struct kobj_attribute { struct attribute attr; ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, char *buf); ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count); }; ``` - **核心用途**: - 为**通用内核对象**(如模块、子系统等非设备对象)创建 sysfs 属性接口 - 通过 `sysfs_create_file()` 直接绑定到 `kobject` 目录[^1] - **操作函数**: - 创建:`sysfs_create_file(kobj, &attr->attr)` - 删除:`sysfs_remove_file(kobj, &attr->attr)` - **适用场景**:驱动核心框架、非设备类内核组件(如内存管理、调度器等) #### 2. **device_attribute (设备专用属性)** - **作用对象**:专用于 `struct device` 对象(代表具体硬件设备) - **结构定义**: ```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); }; ``` - **核心用途**: - 为**硬件设备**创建标准化的 sysfs 属性接口(如 `/sys/class/xxx/` 下的设备节点) - 通过宏 `DEVICE_ATTR` 声明属性,自动生成 `dev_attr_<name>` 变量[^3] - **操作函数**: - 创建:`device_create_file(dev, &dev_attr_<name>)` - 删除:`device_remove_file(dev, &dev_attr_<name>)` - **适用场景**:设备驱动程序(如 USB 设备、PCI 设备、传感器等) #### 关键区别总结 | 特性 | `kobj_attribute` | `device_attribute` | |---------------------|-----------------------------------|---------------------------------| | **作用对象** | 通用 `kobject` | 专用 `struct device` | | **层次关系** | 基础层(所有 kobject 均可使用) | 设备层(继承自 kobject) | | **声明宏** | 无标准宏,需手动初始化 | `DEVICE_ATTR(name, mode, show, store)`[^3] | | **参数传递** | `kobject *` | `device *` | | **典型应用位置** | `/sys/kernel/` 等非设备目录 | `/sys/class/` 或 `/sys/bus/` 下的设备目录 | #### 使用示例 **device_attribute 声明**(设备驱动中): ```c static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", read_sensor_temp()); } static DEVICE_ATTR(temperature, 0444, temp_show, NULL); // 声明只读属性 ``` **kobj_attribute 声明**(内核模块中): ```c static ssize_t debug_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "Debug mode: %d\n", debug_flag); } static struct kobj_attribute debug_attr = __ATTR(debug, 0644, debug_show, debug_store); ``` #### 选择建议 - 若操作对象是**硬件设备**(如传感器、网卡等),优先使用 `device_attribute` - 若操作对象是**内核通用组件**(如调度器参数、内存池等),使用 `kobj_attribute` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值