没有选择双面打印,还出来双面打印提示,每次复印还都出来一张白纸,怎么回事? 求迅速解答2天内要,谢谢
986
2022-05-29
文章目录
前言
框架
如何实现`input device` 设备驱动?
头文件
注册input_dev设备
上报按键值
dev->open()和dev->close()
其他事件类型,处理输出事件
查看input device信息
附录
前言
这次主要会学习linux中对于输入设备统一封装的框架,在计算机组成原理中,我们可以知道计算机的组成主要分为五个部分:控制器,运算器,存储器,输入,输出。可见,输入作为其中的一个子系统,但是对于众多的设备来说,需要一套统一的规范。所以,在嵌入式系统中的外设,鼠标、键盘、按键、G-Sensor等等都可以注册为Input设备。Linux在用户层提供了相应的接口读取数据,这里我暂时只介绍在上一篇文章的基础上,如何编写一个Input驱动。
框架
首先还是先看一下Input子系统的整体框架,具体如下图所示;
如何实现input device 设备驱动?
如何编写input驱动的sample?在内核文档中已经有详细的介绍,虽然是英文的,但是相当规范,简单,详细,本文就是在此基础上展开,具体可以参考内核input文档。
在这里,我们需要在代码中做哪些工作呢?下面将会重点罗列成每一个步骤进行讲解。
头文件
首先需要包含头文件#include
注册input_dev设备
首先定义一个用来注册input device的变量,这里会用到input_dev这个结构体。目前的情况是,我把需要的各种变量都封装到gpio_demo_device这个结构体中,但是,实际上这里暂时这关心input_demo就可以了。
struct gpio_demo_device { struct platform_device *pdev; struct device *dev; struct gpio_platform_data *pdata; struct workqueue_struct *gpio_monitor_wq; struct delayed_work gpio_delay_work ; struct input_dev *input_demo; };
1
2
3
4
5
6
7
8
9
10
在这里需要为我们创建的gpio_demo_device结构体定义一个变量priv,并且使用devm_kzalloc为其分配相应的内存。
struct gpio_demo_device *priv; priv = devm_kzalloc(dev, sizeof(*priv) , GFP_KERNEL);
1
2
然后,我们再为input_demo分配内存;
priv->input_demo = devm_input_allocate_device(priv->dev);
1
初始化input_demo;
// kernel/include/uapi/linux/input-event-codes.h priv->input_demo->name = "input-demo"; priv->input_demo->dev.parent = priv->dev; priv->input_demo->evbit[0] = BIT_MASK(EV_KEY); //事件类型注册为EV_KEY priv->input_demo->keybit[BIT_WORD(KEY_VOLUMEDOWN)] = BIT_MASK(KEY_VOLUMEDOWN); //按键值
1
2
3
4
5
name:当前初始化的input device的名字;
evbit[0]:配置为BIT_MASK(EV_KEY),将事件类型注册为EV_KEY类型,具体有哪些类型如下所示;
所有定义都在kernel/include/uapi/linux/input-event-codes.h文件中。
除了EV_KEY之外,还有两种基本事件类型:EV_REL和EV_ABS。它们用于设备提供的相对值和绝对值。相对值可以是例如X轴上的鼠标移动。鼠标将其报告为与上一个位置的相对差异,因为它没有任何绝对坐标系可供使用。绝对事件即操纵杆和数字化仪 - 在绝对坐标系中工作的设备。
/*
Event types
*/
#define EV_SYN 0x00
#define EV_KEY 0x01
#define EV_REL 0x02
#define EV_ABS 0x03
#define EV_MSC 0x04
#define EV_SW 0x05
#define EV_LED 0x11
#define EV_SND 0x12
#define EV_REP 0x14
#define EV_FF 0x15
#define EV_PWR 0x16
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)
keybit[BIT_WORD(KEY_VOLUMEDOWN)]:按键值设置为BIT_MASK(KEY_VOLUMEDOWN),就是音量减的按键;
BITS_TO_LONGS(), BIT_WORD(), BIT_MASK()
These three macros from bitops.h help some bitfield computations:
BITS_TO_LONGS(x) - returns the length of a bitfield array in longs for x bits
BIT_WORD(x) - returns the index in the array in longs for bit x
BIT_MASK(x) - returns the index in a long for bit x
完成初始化之后,然后注册input_demo;
ret = input_register_device(priv->input_demo);
1
上报按键值
当用户发生了向系统输入一定信息的操作之后,input device需要将一些列信息上传,本文需要上传按键值。在这里要可以通过中断触发,或者轮询去检测用户的动作,前面已经有提及,这里不再赘述,
本文代码已经在附录中,已经涵盖这两种方式。
关于上报数据可以通过input_report_key和input_sync去完成。
dev->open()和dev->close()
如果驱动程序必须重复轮询设备,因为它没有来自它的中断,并且轮询太昂贵而无法一直进行,或者如果设备中断资源比较稀缺,可以使用open和close回调来通知设备何时可以停止轮询或释放中断以及何时必须重新开始轮询或再次获取中断。为此,我们将以下代码添加到示例驱动程序:
static int button_open(struct input_dev *dev) { if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) { printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq); return -EBUSY; } return 0; } static void button_close(struct input_dev *dev) { free_irq(IRQ_AMIGA_VERTB, button_interrupt); } static int gpio_demo_probe(struct platform_device *pdev)t(void) { ... button_dev->open = button_open; button_dev->close = button_close; ... }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
请注意,输入内核会跟踪设备的用户数,并确保仅在第一个用户连接到设备时调用dev->open(),并在最后一个用户断开连接时调用dev-> close() 。对两个回调的调用都是序列化的。
open()回调应该在成功的情况下返回0,或者在失败的情况下返回任何非零值。close()回调(无效)必须始终成功。
其他事件类型,处理输出事件
到目前为止的其他事件类型是:
EV_LED - 用于键盘LED。
EV_SND - 用于键盘蜂鸣声。
它们与按键事件非常相似,但它们朝另一个方向 - 从系统到输入设备驱动程序。如果您的输入设备驱动程序可以处理这些事件,则必须在evbit中设置相应的位, 以及回调例程:
button_dev->event = button_event; int button_event(struct input_dev * dev,unsigned int type, unsigned int code,int value){ if(type == EV_SND && code == SND_BELL){ outb(value,BUTTON_BELL); return 0; } return -1; }
1
2
3
4
5
6
7
8
9
10
这个回调例程可以从一个中断或一个BH调用(虽然这不是一个规则),因此不能休眠,并且不能花太长时间才能完成。
查看input device信息
系统启动之后,可以通过cat /proc/bus/input/devices来查看当前系统中已经注册的input device信息,这里可以看到已经注册成功的input-demo
附录
#include
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
258
259
260
261
262
263
264
265
266
267
268
Linux
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。