1.中断注册
1
2
3
4
5
6
7
8#include <linux/interrupt.h> int request_irq(unsigned int irq, void (*handler)(int, void*, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) 返回0表示成功,或者返回一个错误码
参数说明
irq: 中断号 ;
handler:中断处理函数;
flags: 中断管理有关的各种选项;
–>IRQF_DISABLED(SA_INTERRUPT)
如果设置该位,表示是一个“快速”中断处理程序;
如果没有设置这位,那么是一个“慢速”中断处理程
序。
–>IRQF_SHARED(SA_SHIRQ)
该位表明该中断号是多个设备共享的。
–>IRQF_TRIGGER_RISING 上升沿触发
–>IRQF_TRIGGER_FALLING 下降沿触发
–>IRQF_TRIGGER_HIGH 高电平触发
–>IRQF_TRIGGER_LOW 低电平触发
devname:设备名;
dev_id:共享中断时使用;
或者使用函数
1
2
3
4
5
6
7int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id);
参数说明
irq: 中断号 ;
handler:中断处理函数,可以理解为中断上半部,不能做耗时操作;
thread_fn:可以理解为中断下半部,能做耗时操作,因为这里会建一个线程;
irqflags: 中断管理有关的各种选项,同上;
devname:设备名;
dev_id:共享中断时使用;
注意
如果遇到“Threaded irq requested with handler=NULLand !ONE_SHOT for irq xxx”这种错,irqflags参数就需要或上IRQF_ONESHOT。IRQF_ONESHOT是为了保证thread_fn函数执行完之后才继续接受中断,也就是说该中断在整个thread_fn函数处理过程中都是不会再次触发,直到处理完成。
如:
1
2
3
4
5
6request_threaded_irq(irq, NULL, gpio_keys_gpio_isr, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "sunxi-keyboard-gpio",NULL);
2.中断处理程序
1
2
3
4
5
6
7
8
9
10
11irqreturn_t key_int(int irq, void *dev_id) { //1. 检测是否发生了按键中断 //2. 清除已经发生的按键中断 //3. 打印按键值 return 0; }
注意:中断处理程序不能引起阻塞、不能调度。
3.注销中断
1
2
3#include <linux/interrupt.h> void free_irq(unsigned int irq, void *dev_id)
4.一个简单的GPIO按键案例
–>dts配置
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&soc { keygpio { compatible = "allwinner,sunxi-keygpio"; status = "okay"; button@0 { label = "Key VOLUME UP"; linux,code = <115>; gpios = <&r_pio PL 8 6 1 0xffffffff 0xffffffff>; wakeup-source; }; button@1 { label = "KEY VOLUME DOWN"; linux,code = <114>; gpios = <&r_pio PL 9 6 1 0xffffffff 0xffffffff>; wakeup-source; }; button@2 { label = "Key Menu"; linux,code = <139>; gpios = <&r_pio PL 10 6 1 0xffffffff 0xffffffff>; wakeup-source; }; }; };
简单说明
button@X就是对应的GPIO按键,如果有两个GPIO按键那就是button@0,button@1;
label 就是为了说明这个按键是什么功能键;
gpios就是对应的GPIO口,示例的是全志平台的表示方法;
linux,code就是上报的按键码;
wakeup-source表示该按键对应的GPIO是不是唤醒源,有没有休眠唤醒功能;全志PL口是唤醒源,用用作深度休眠唤醒;
–>驱动代码
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
247
248
249
250
251
252
253
254
255
256
257#include <linux/module.h> #include <linux/init.h> #include <linux/input.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/keyboard.h> #include <linux/irq.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/of_gpio.h> #include <linux/of_irq.h> #include <linux/of_address.h> #if defined(CONFIG_PM) #include <linux/pm.h> #endif struct key_gpio { int gpio; int code; u8 can_wakeup; u8 active_low; u8 is_last_down; }; static struct key_gpio buttons[5]; static u8 nbuttons = 0; static struct input_dev *sunxikbd_dev; #ifdef CONFIG_OF /* * Translate OpenFirmware node properties into platform_data */ static struct of_device_id const sunxi_keygpio_of_match[] = { { .compatible = "allwinner,sunxi-keygpio"}, { }, }; MODULE_DEVICE_TABLE(of, sunxi_keygpio_of_match); #else /* !CONFIG_OF */ #endif static int gpio_keys_get_devtree_pdata(struct device *dev) { struct device_node *node, *pp; struct key_gpio *button; int error; int i; node = dev->of_node; if (!node) return -ENODEV; nbuttons = of_get_available_child_count(node); if (nbuttons == 0) return -ENODEV; i = 0; for_each_available_child_of_node(node, pp) { button = &buttons[i++]; button->gpio = of_get_named_gpio_flags(pp, "gpios", 0, NULL); if (button->gpio < 0) { error = button->gpio; if (error != -ENOENT) { if (error != -EPROBE_DEFER) dev_err(dev, "Failed to get gpio flags, error: %dn", error); return error; } } if (!gpio_is_valid(button->gpio)) { dev_err(dev, "Found button without gpiosn"); return -EINVAL; } if (of_property_read_u32(pp, "linux,code", &button->code)) { dev_err(dev, "Button without keycode: 0x%xn", button->gpio); return -EINVAL; } //button->desc = of_get_property(pp, "label", NULL); button->can_wakeup = of_property_read_bool(pp, "wakeup-source"); //nbuttons++; printk("buttons[%d]: gpio=%d, code=%d, can_wakeup=%dn", i-1,button->gpio,button->code,button->can_wakeup); } printk(KERN_ERR"----%s finish, have %d buttonn",__func__,nbuttons); if (nbuttons == 0) return -EINVAL; return 0; } static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) { int i,value; for (i = 0; i < nbuttons; i++) { value = gpio_get_value(buttons[i].gpio); printk("buttons[%d]:value=%dn",i,value); if(value == 0 && buttons[i].is_last_down == 0){ //report down input_report_key(sunxikbd_dev, buttons[i].code, 1); input_sync(sunxikbd_dev); } if(value == 1 && buttons[i].is_last_down == 1) { //report up input_report_key(sunxikbd_dev, buttons[i].code, 0); input_sync(sunxikbd_dev); } if(value == 0) buttons[i].is_last_down = 1; else buttons[i].is_last_down = 0; } return IRQ_HANDLED; } static int sunxi_keygpio_probe(struct platform_device *pdev) { int ret = -1; u8 i; printk(KERN_ERR"-----%s----n",__func__); ret = gpio_keys_get_devtree_pdata(&pdev->dev); if (ret < 0) return -1; /* init input */ sunxikbd_dev = input_allocate_device(); if (!sunxikbd_dev) { pr_err("sunxikbd: not enough memory for input devicen"); return -ENOMEM; } sunxikbd_dev->name = "sunxi-keyboard-gpio"; sunxikbd_dev->phys = "sunxikbd/input1"; sunxikbd_dev->id.bustype = BUS_HOST; sunxikbd_dev->id.vendor = 0x0001; sunxikbd_dev->id.product = 0x0001; sunxikbd_dev->id.version = 0x0100; sunxikbd_dev->evbit[0] = BIT_MASK(EV_KEY); for (i = 0; i < nbuttons; i++) { if (buttons[i].code < KEY_MAX) set_bit(buttons[i].code, sunxikbd_dev->keybit); buttons[i].is_last_down = 0; } ret = input_register_device(sunxikbd_dev); if (ret < 0){ goto input_error; } for (i = 0; i < nbuttons; i++) { ret = request_threaded_irq(gpio_to_irq(buttons[i].gpio),NULL, gpio_keys_gpio_isr, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "sunxi-keyboard-gpio",NULL); if(ret < 0) { printk(KERN_ERR"buttons[%d] request irq error!!!n",i); } } return 0; input_error: input_free_device(sunxikbd_dev); return -1; } static int sunxi_keygpio_remove(struct platform_device *pdev) { u8 i; for (i = 0; i < nbuttons; i++) { free_irq(gpio_to_irq(buttons[i].gpio),NULL); } input_unregister_device(sunxikbd_dev); input_free_device(sunxikbd_dev); return 0; } #ifdef CONFIG_PM static int sunxi_keygpio_suspend(struct device *dev) { u8 i; for (i = 0; i < nbuttons; i++) { if (buttons[i].can_wakeup) { enable_irq_wake(gpio_to_irq(buttons[i].gpio)); } else { disable_irq(gpio_to_irq(buttons[i].gpio)); } } return 0; } static int sunxi_keygpio_resume(struct device *dev) { u8 i; for (i = 0; i < nbuttons; i++) { if (buttons[i].can_wakeup) { disable_irq_wake(gpio_to_irq(buttons[i].gpio)); } else { enable_irq(gpio_to_irq(buttons[i].gpio)); } } return 0; } #endif #ifdef CONFIG_PM static const struct dev_pm_ops sunxi_keygpio_pm_ops = { .suspend = sunxi_keygpio_suspend, .resume = sunxi_keygpio_resume, }; #define SUNXI_KEYGPIO_PM_OPS (&sunxi_keygpio_pm_ops) #endif static struct platform_driver sunxi_keygpio_driver = { .probe = sunxi_keygpio_probe, .remove = sunxi_keygpio_remove, .driver = { .name = "sunxi-keygpio", .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = SUNXI_KEYGPIO_PM_OPS, #endif .of_match_table = of_match_ptr(sunxi_keygpio_of_match), }, }; module_platform_driver(sunxi_keygpio_driver); MODULE_DESCRIPTION("sunxi-keygpio driver"); MODULE_LICENSE("GPL");
insmod驱动成功驱动之后,使用getevent看按键的上报情况。
最后
以上就是愉快微笑最近收集整理的关于2. 例-中断(GPIO按键事件)的全部内容,更多相关2.内容请搜索靠谱客的其他文章。
发表评论 取消回复