我是靠谱客的博主 稳重月饼,这篇文章主要介绍Linux驱动开发之DEVICE_ATTR调试技术一、功能介绍二、使用流程三、使用实例1、源码2、节点使用,现在分享给大家,希望可以做个参考。

一、功能介绍

1、简介

在sysfs中添加device属性文件,可以动态控制device或者获取device信息。

2、相关函数、宏原型及功能

2.1、DEVICE_ATTR

DEVICE_ATTR宏定义在kernel/include/linux/device.h文件中。原型如下:

复制代码
1
2
3
#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中。原型如下:

复制代码
1
2
3
4
5
6
7
8
9
10
11
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中。原型如下:

复制代码
1
2
3
4
5
6
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结构变量

复制代码
1
DEVICE_ATTR(xxx,0755,xxx_show,xxx_store);

2、实现show、store函数

show。

复制代码
1
2
3
4
static size_t xxx_show(struct device *dev,struct device_attribute *attr,char *buf) {     return sprintf(buf,"xxxn"); }

store。

复制代码
1
2
3
4
static size_t xxx_store(struct device *dev,struct device_attribute *attr,char *buf,size_t count) {     return count; }

3、init函数中创建device属性文件

复制代码
1
device_create_file(device, &dev_attr_xxx); 

4、exit函数中移除device属性文件

复制代码
1
device_remove_file(device, &dev_attr_xxx); 

三、使用实例

1、源码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#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, &regValue); 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、节点使用内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(77)

评论列表共有 0 条评论

立即
投稿
返回
顶部