概述
一、功能介绍
1、简介
在sysfs中添加device属性文件,可以动态控制device或者获取device信息。
2、相关函数、宏原型及功能
2.1、DEVICE_ATTR
DEVICE_ATTR宏定义在kernel/include/linux/device.h文件中。原型如下:
#define DEVICE_ATTR(_name, _mode, _show, _store)
struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
具体怎么展开,这里就不讨论了,有兴趣的小伙伴可以自己查一下。
功能:
定义一个device_attribute结构的dev_attr_name变量。
参数:
_name:名称,在sysfs中device属性文件名称
_mode:访问权限,与普通文件相同,UGO格式
_show:显示函数,cat文件时调用此函数
_store:写函数,echo内容到文件时调用此函数
2.2、device_create_file
函数定义在kernel/drivers/base/core.c中。原型如下:
int device_create_file(struct device *dev, const struct device_attribute *attr)
{
int error = 0;
if (dev)
error = sysfs_create_file(&dev->kobj, &attr->attr);
return error;
}
功能:
创建device属性文件。
参数:
dev:设备指针,需要描述属性的设备指针;
attr:device_attribute指针,即DEVICE_ATTR宏生成的dev_attr_name指针。
2.3、device_remove_file
函数定义在kernel/drivers/base/core.c中。原型如下:
void device_remove_file(struct device *dev, const struct device_attribute *attr)
{
if (dev)
sysfs_remove_file(&dev->kobj, &attr->attr);
}
功能:
移除device属性文件。
二、使用流程
1、创建device_attribute结构变量
DEVICE_ATTR(xxx,0755,xxx_show,xxx_store);
2、实现show、store函数
show。
static size_t xxx_show(struct device *dev,struct device_attribute *attr,char *buf)
{
return sprintf(buf,"xxxn");
}
store。
static size_t xxx_store(struct device *dev,struct device_attribute *attr,char *buf,size_t count)
{
return count;
}
3、init函数中创建device属性文件
device_create_file(device, &dev_attr_xxx);
4、exit函数中移除device属性文件
device_remove_file(device, &dev_attr_xxx);
三、使用实例
1、源码
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <mach/gpio_drv.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define chrtest_CNT 1 /* 设备号个数 */
#define chrtest_NAME "gpio_test" /* 名字 */
/* chrtest设备结构体 */
struct chrtest_dev{
dev_t devid; /* 设备号 */
struct cdev cdev; /* cdev */
struct class *class; /* 类 */
struct device *dev; /* 设备 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
};
static struct chrtest_dev chrtest;
static struct file_operations chrtest_fops = {
.owner = THIS_MODULE,
};
static ssize_t gpio_power_show(struct device *dev, struct device_attribute *attr, char *buf)
{
printk("---gpio_power:%d---n", gpio_get_value(GPIO_POWER_EN));
return 0;
}
static ssize_t gpio_power_store(struct device *dev, struct device_attribute *attr, char *buf, size_t len)
{
int ret, regValue;
ret = kstrtoint(buf, 0, ®Value);
printk("value:%dn", regValue);
GPIO_OUTPUT(GPIO_POWER_EN, regValue);
return len;
}
static DEVICE_ATTR(gpio_power, 0755, gpio_power_show, gpio_power_store);
static int __init led_init(void)
{
u32 val = 0;
int ret;
/* 注册字符设备驱动 */
/* 1、创建设备号 */
if (chrtest.major) { /* 定义了设备号 */
chrtest.devid = MKDEV(chrtest.major, 0);
register_chrdev_region(chrtest.devid, chrtest_CNT, chrtest_NAME);
} else { /* 没有定义设备号 */
alloc_chrdev_region(&chrtest.devid, 0, chrtest_CNT, chrtest_NAME); /* 申请设备号 */
chrtest.major = MAJOR(chrtest.devid); /* 获取分配号的主设备号 */
chrtest.minor = MINOR(chrtest.devid); /* 获取分配号的次设备号 */
}
printk("new char device major=%d,minor=%dn",chrtest.major, chrtest.minor);
/* 2、初始化cdev */
chrtest.cdev.owner = THIS_MODULE;
cdev_init(&chrtest.cdev, &chrtest_fops);
/* 3、添加一个cdev */
cdev_add(&chrtest.cdev, chrtest.devid, chrtest_CNT);
/* 4、创建类 */
chrtest.class = class_create(THIS_MODULE, chrtest_NAME);
if (IS_ERR(chrtest.class)) {
return PTR_ERR(chrtest.class);
}
/* 5、创建设备 */
chrtest.dev = device_create(chrtest.class, NULL, chrtest.devid, NULL, chrtest_NAME);
if (IS_ERR(chrtest.dev)) {
return PTR_ERR(chrtest.dev);
}
/*6、创建调试节点*/
ret = device_create_file(chrtest.dev, &dev_attr_gpio_power);
if (ret){
printk("%s gpio_power device_create_file err!n", __func__);
} else {
printk("%s gpio_power device_create_file success!n", __func__);
}
return 0;
}
static void __exit led_exit(void)
{
/* 注销字符设备驱动 */
cdev_del(&chrtest.cdev);/* 删除cdev */
unregister_chrdev_region(chrtest.devid, chrtest_CNT); /* 注销设备号 */
device_destroy(chrtest.class, chrtest.devid);
class_destroy(chrtest.class);
/* 移除device属性节点 */
device_remove_file(chrtest.dev, &dev_attr_gpio_power);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
实例代码中,主要是针对了一个GPIO进行了读写,也就是获取它的电平高低和设置它的输出电平高低。
然后就是这个device属性节点是基于字符设备创建的,它生成的device节点路径我没记错的话,应该是在/sys/devices/virtual/gpio_test/gpio_test/。
2、节点使用
读:cat /sys/devices/virtual/chartest/gpio_test/gpio_test。
写:echo 1 > /sys/devices/virtual/chartest/gpio_test/gpio_test或者echo 0 > /sys/devices/virtual/chartest/gpio_test/gpio_test。
最后
以上就是稳重月饼为你收集整理的Linux驱动开发之DEVICE_ATTR调试技术一、功能介绍二、使用流程三、使用实例1、源码2、节点使用的全部内容,希望文章能够帮你解决Linux驱动开发之DEVICE_ATTR调试技术一、功能介绍二、使用流程三、使用实例1、源码2、节点使用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复