我是靠谱客的博主 暴躁舞蹈,这篇文章主要介绍linux驱动之休眠与唤醒,现在分享给大家,希望可以做个参考。

休眠唤醒

想要达到的效果:
应用程序对设备文件进行read操作时, 如果没有数据则程序休眠, 直到有数据时程序被唤醒.

休眠函数
头文件 includelinuxwait.h

**wait_event_interruptible(wq, condition) **
休眠,直到condition为真;
休眠期间是可被打断的,可以被信号打断

复制代码
1
2
3
4
5
6
7
8
9
10
11
wq参数是 wait_queue_head_t condition 作为一个判断条件语句 #define wait_event_interruptible(wq, condition) ({ int __ret = 0; might_sleep(); if (!(condition)) __ret = __wait_event_interruptible(wq, condition); __ret; })

wait_event(wq, condition)
休眠,直到condition为真;信号不能打断;

复制代码
1
2
3
4
5
6
7
8
#define wait_event(wq, condition) do { might_sleep(); if (condition) break; __wait_event(wq, condition); } while (0)

wait_event_interruptible_timeout(wq, condition, timeout)
休眠,直到condition为真或超时;
休眠期间是可被打断的,可以被信号打断;

复制代码
1
2
3
4
5
6
7
8
9
10
#define wait_event_interruptible_timeout(wq, condition, timeout) ({ long __ret = timeout; might_sleep(); if (!___wait_cond_timeout(condition)) __ret = __wait_event_interruptible_timeout(wq, condition, timeout); __ret; })

wait_event_timeout(wq, condition, timeout)
休眠,直到condition为真或超时;
休眠期间是可被打断的,不可以被信号打断;

复制代码
1
2
3
4
5
6
7
8
9
10
#define wait_event_interruptible_timeout(wq, condition, timeout) ({ long __ret = timeout; might_sleep(); if (!___wait_cond_timeout(condition)) __ret = __wait_event_interruptible_timeout(wq, condition, timeout); __ret; })

唤醒函数

wake_up_interruptible
唤醒x队列中状态为“TASK_INTERRUPTIBLE”的线程,只唤醒其中的一个线程

复制代码
1
2
#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)

wake_up_interruptible_nr(x, nr)
唤醒x队列中状态为“TASK_INTERRUPTIBLE”的线程,只唤醒其中的nr个线程

复制代码
1
2
#define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)

wake_up_interruptible_all(x)
唤醒x队列中状态为“TASK_INTERRUPTIBLE”的线程,唤醒其中的所有线程

复制代码
1
2
#define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)

wake_up(x)
唤醒x队列中状态为“TASK_INTERRUPTIBLE”或“TASK_UNINTERRUPTIBLE”的线程,只唤醒其中的一个线程

复制代码
1
2
3
#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)

wake_up_nr(x, nr)
唤醒x队列中状态为“TASK_INTERRUPTIBLE”或“TASK_UNINTERRUPTIBLE”的线程,只唤醒其中nr个线程

复制代码
1
2
#define wake_up_nr(x, nr) __wake_up(x, TASK_NORMAL, nr, NULL)

wake_up_all(x)
唤醒x队列中状态为“TASK_INTERRUPTIBLE”或“TASK_UNINTERRUPTIBLE”的线程,唤醒其中的所有线程

复制代码
1
2
3
#define wake_up_all(x) __wake_up(x, TASK_NORMAL, 0, NULL)

初始化 wait_queue_head_t 类型
使用DECLARE_WAIT_QUEUE_HEAD(wq)

编码:
在带有中断的设备驱动程序的框架上进行
驱动程序:

复制代码
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#include <linux/module.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/mutex.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/stat.h> #include <linux/init.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/kmod.h> #include <linux/gfp.h> #include <linux/gpio/consumer.h> #include <linux/platform_device.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/slab.h> struct gpio_key{ int gpio; struct gpio_desc *gpiod; int flag; int irq; } ; static struct gpio_key *gpio_keys_array; /* 主设备号 */ static int major = 0; static struct class *gpio_key_class; /* 环形缓冲区 */ #define BUF_LEN 128 static int g_keys[BUF_LEN]; static int r, w; #define NEXT_POS(x) ((x+1) % BUF_LEN) static int is_key_buf_empty(void) { return (r == w); } static int is_key_buf_full(void) { return (r == NEXT_POS(w)); } static void put_key(int key) { if (!is_key_buf_full()) { g_keys[w] = key; w = NEXT_POS(w); } } static int get_key(void) { int key = 0; if (!is_key_buf_empty()) { key = g_keys[r]; r = NEXT_POS(r); } return key; } //休眠唤醒关键函数 wait_event_interruptible wake_up_interruptible static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait); /* 实现对应的open/read/write等函数,填入file_operations结构体 */ static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset) { //printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); int err; int key; wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());//数据缓存为空 则休眠 key = get_key(); err = copy_to_user(buf, &key, 4); return 4; } /* 定义自己的file_operations结构体 */ static struct file_operations gpio_key_drv = { .owner = THIS_MODULE, .read = gpio_key_drv_read, }; static irqreturn_t gpio_key_isr(int irq, void *dev_id) { struct gpio_key *gpio_key = dev_id; int val; int key; val = gpiod_get_value(gpio_key->gpiod); printk("key %d %dn", gpio_key->gpio, val); key = (gpio_key->gpio << 8) | val; put_key(key); wake_up_interruptible(&gpio_key_wait); //唤醒队列 return IRQ_HANDLED; } /* 1. 从platform_device获得GPIO * 2. gpio=>irq * 3. request_irq */ static int gpio_key_probe(struct platform_device *pdev) { int err; struct device_node *node = pdev->dev.of_node; int count; int i; enum of_gpio_flags flag; printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); count = of_gpio_count(node); if (!count) { printk("%s %s line %d, there isn't any gpio availablen", __FILE__, __FUNCTION__, __LINE__); return -1; } gpio_keys_array = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL); for (i = 0; i < count; i++) { gpio_keys_array[i].gpio = of_get_gpio_flags(node, i, &flag); if (gpio_keys_array[i].gpio < 0) { printk("%s %s line %d, of_get_gpio_flags failn", __FILE__, __FUNCTION__, __LINE__); return -1; } gpio_keys_array[i].gpiod = gpio_to_desc(gpio_keys_array[i].gpio); gpio_keys_array[i].flag = flag & OF_GPIO_ACTIVE_LOW; gpio_keys_array[i].irq = gpio_to_irq(gpio_keys_array[i].gpio); } for (i = 0; i < count; i++) { err = request_irq(gpio_keys_array[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "gpio_key", &gpio_keys_array[i]); //注册中断服务程序 } /* 注册file_operations */ major = register_chrdev(0, "gpio_key", &gpio_key_drv); /* /dev/gpio_key */ gpio_key_class = class_create(THIS_MODULE, "gpio_key_class"); if (IS_ERR(gpio_key_class)) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); unregister_chrdev(major, "gpio_key"); return PTR_ERR(gpio_key_class); } device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, "gpio_key"); /* /dev/gpio_key */ return 0; } static int gpio_key_remove(struct platform_device *pdev) { //int err; struct device_node *node = pdev->dev.of_node; int count; int i; device_destroy(gpio_key_class, MKDEV(major, 0)); class_destroy(gpio_key_class); unregister_chrdev(major, "gpio_key"); count = of_gpio_count(node); for (i = 0; i < count; i++) { free_irq(gpio_keys_array[i].irq, &gpio_keys_array[i]); } kfree(gpio_keys_array); return 0; } static const struct of_device_id keys[] = { { .compatible = "jzy,gpio_key" }, { }, }; /* 1. 定义platform_driver */ static struct platform_driver gpio_keys_driver = { .probe = gpio_key_probe, .remove = gpio_key_remove, .driver = { .name = "gpio_key", .of_match_table = keys, }, }; /* 2. 在入口函数注册platform_driver */ static int __init gpio_key_init(void) { int err; printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); err = platform_driver_register(&gpio_keys_driver); return err; } /* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数 * 卸载platform_driver */ static void __exit gpio_key_exit(void) { printk("%s %s line %dn", __FILE__, __FUNCTION__, __LINE__); platform_driver_unregister(&gpio_keys_driver); } /* 7. 其他完善:提供设备信息,自动创建设备节点 */ module_init(gpio_key_init); module_exit(gpio_key_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
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { int fd; int val; /* 1. 判断参数 */ if (argc != 2) { printf("Usage: %s <dev>n", argv[0]); return -1; } /* 2. 打开文件 */ fd = open(argv[1], O_RDWR); if (fd == -1) { printf("can not open file %sn", argv[1]); return -1; } while (1) { /* 3. 读文件 */ read(fd, &val, 4); //这里没有数据的话会被驱动休眠 printf("get button : 0x%xn", val); } close(fd); return 0; }

最后

以上就是暴躁舞蹈最近收集整理的关于linux驱动之休眠与唤醒的全部内容,更多相关linux驱动之休眠与唤醒内容请搜索靠谱客的其他文章。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部