我是靠谱客的博主 光亮导师,这篇文章主要介绍一、字符设备驱动4-异步通知按键驱动按键驱动:异步通知源码,现在分享给大家,希望可以做个参考。

按键驱动:异步通知

4种读按键方式对比:

查询:非常耗费CPU资源

中断:会休眠,若一直没有按键动作,将一直休眠

Poll:可以指定超时时间,有按键动作立即唤醒,或超时后唤醒

异步通知:驱动程序主动通知应用程序可以读数据了

3种都是应用程序读的时候资源并不一定就绪,异步通知是驱动程序通知应用程序去读,此时资源已经就绪

思路指导:

1. 应用程序:注册信号处理函数,接收到信号时会调用此函数

2. 谁发?驱动程序

3. 发给谁?应用程序,因此app需要告诉驱动自己的pid

4. 怎么发?调用kill_fasync()

编程要点:

驱动程序:

1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID。不过此项工作已由内核完成,驱动程序无需处理。

2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序中的file_operations->fasync()得以执行。

3. 在设备资源可获得时,调用kill_fasync()函数激发相应的信号。

应用程序:

复制代码
1
2
3
4
5
6
7
signal(SIGIO, my_signal_fun);   // 设置接收到SIGIO信号后的回调函数                                   // SIGIO表示有数据读或有空间写了                                   // 在回调函数中去执行read, write      fcntl(fd, F_SETOWN, getpid());  // 告诉内核发给谁   oflags = fcntl(fd, F_GETFL);    // 若要修改标志,先读出原始的   fcntl(fd, F_SETFL, oflags | FASYNC); // 改变fasync标记,最终会调用到驱动的fops->fasync()  

源码

驱动:

复制代码
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* * 引脚:PI0,1,2 */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/gpio.h> #include <linux/leds.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/module.h> #include <linux/pinctrl/consumer.h> #include <linux/err.h> #include <linux/fs.h> #include <linux/kdev_t.h> #include <linux/uaccess.h> #include <linux/interrupt.h> #include <asm/io.h> #include <linux/wait.h> #include <linux/sched.h> #include <linux/poll.h> #include <asm/signal.h> struct pin_desc{ int pin; int val; }; /* * 按下时,返回:0x81, 0x82, 0x83 * */ static struct pin_desc pins_desc[3] = { {NUC970_PI0, 0x1}, {NUC970_PI1, 0x2}, {NUC970_PI2, 0x3}, }; static unsigned char val; static DECLARE_WAIT_QUEUE_HEAD(buttons_waitq); int evpress = 0; struct fasync_struct *buttons_async; static irqreturn_t buttons_handler(int irq, void *dev_id) { struct pin_desc *pin = (struct pin_desc *)dev_id; //int res; //res = gpio_get_value(pin->pin); val = 0x80 | pin->val; evpress = 1; wake_up_interruptible(&buttons_waitq); kill_fasync(&buttons_async, SIGIO, POLL_IN); // 发送信号 return IRQ_HANDLED; } static int buttons_open(struct inode *inode, struct file *filp) { // request_irq会自动设置引脚,此处不再配置 request_irq(gpio_to_irq(pins_desc[0].pin), buttons_handler, IRQF_TRIGGER_FALLING, "S1", &pins_desc[0]); request_irq(gpio_to_irq(pins_desc[1].pin), buttons_handler, IRQF_TRIGGER_FALLING, "S2", &pins_desc[1]); request_irq(gpio_to_irq(pins_desc[2].pin), buttons_handler, IRQF_TRIGGER_FALLING, "S3", &pins_desc[2]); return 0; } static ssize_t buttons_read (struct file *filp, char __user *buf, size_t count, loff_t *ppos) { if (count != 1) { return -EINVAL; } wait_event_interruptible(buttons_waitq, evpress); evpress = 0; copy_to_user(buf, &val, 1); return 1; } int buttons_release (struct inode *inode, struct file *filp) { free_irq(gpio_to_irq(pins_desc[0].pin), &pins_desc[0]); free_irq(gpio_to_irq(pins_desc[1].pin), &pins_desc[1]); free_irq(gpio_to_irq(pins_desc[2].pin), &pins_desc[2]); return 0; } static unsigned int buttons_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; poll_wait(file, &buttons_waitq, wait); // 不会立即休眠,只是把进程挂到buttons_waitq队列 if (evpress) { mask = POLLIN | POLLRDNORM; } return mask; } // 每当应用程序修改FAYNC标记时,此程序就会被调用 static int buttons_fasync(int fd, struct file *filp, int on) { return fasync_helper(fd, filp, on, &buttons_async); // 此函数会初始化buttons_async } static struct file_operations buttons_fops = { .owner = THIS_MODULE, .open = buttons_open, .read = buttons_read, .release = buttons_release, .poll = buttons_poll, .fasync = buttons_fasync, }; static int major; static struct class *buttons_class; static struct device *button_device; static int buttons_init(void) { major = register_chrdev(0, "buttons", &buttons_fops); buttons_class = class_create(THIS_MODULE, "buttons"); button_device = device_create(buttons_class, NULL, MKDEV(major, 0), NULL, "buttons"); return 0; } static void buttons_exit(void) { device_destroy(buttons_class, MKDEV(major, 0)); class_destroy(buttons_class); unregister_chrdev(major, "buttons"); } module_init(buttons_init); module_exit(buttons_exit); MODULE_LICENSE("GPL");

测试程序:

复制代码
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
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <poll.h> #include <signal.h> #include <fcntl.h> int fd; static void my_signal_fun(int sig) { unsigned char keyval; read(fd, &keyval, 1); printf("keyval = 0x%xn", keyval); } int main(void) { int oflags; fd = open("/dev/buttons", O_RDONLY); if (fd < 0) { printf("Can't open /dev/buttonsn"); return -1; } signal(SIGIO, my_signal_fun); fcntl(fd, F_SETOWN, getpid()); // 告诉驱动发给谁 oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, oflags | FASYNC); while (1) { sleep(1000); } close(fd); return 0; }

最后

以上就是光亮导师最近收集整理的关于一、字符设备驱动4-异步通知按键驱动按键驱动:异步通知源码的全部内容,更多相关一、字符设备驱动4-异步通知按键驱动按键驱动内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部