Linux内核中按键驱动分为:较为复杂的【矩阵键盘keyboard Matrix】和简单的【按键驱动】。
【Matrix矩阵键盘】一般适用于多行多列多按键的情况,源码文件为:drivers/input/keyboard/matrix_keypad.c
【GPIO按键驱动】一般适用于少量按键,一个GPIO口对应一个按键的情况,源码文件为:driers/input/keyboard/gpio_keys.c
本次在imx6ul中实现矩阵键盘功能:Linux内核版本为4.1.15,cpu为imx6ul。
以下对矩阵键盘原理、源码、调试步骤等逐一进行分析,简单的单按键就暂时不写了。
一、功能实现(代码)
具体开发流程如下:
1.1 添加编译选项
内核源码根目录下执行make menuconfig,选中如下几个选项来添加Matrix相关编译选项:
Device Drivers --->
Input device support --->
<*> Event debugging (选中)
[*] Keyboards --->
<*> GPIO Buttons(选中)
<*> GPIO driven matrix keypad support(选中)
<*> IMX keypad support(选中)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
选中后,save保存,exit退出,使用【make zImage】编译生成新的zImage,路径为:【arch/arm/boot/】
lsy@ubuntu18:~/linux-4.1.15$ ls arch/arm/boot/
bootp compressed dts Image install.sh Makefile zImage
- 1
- 2
将新的zImage拷贝并烧写到板卡中,重启板卡,然后正式开始进行开发工作。
备注:如果觉得编译整个zImage麻烦,也可以使用【make modules】单独编译模块,将drivers/input/keyboard/matrix_keypad.c文件编译生成对应的.ko模块,然后使用insmod或者modprob加载到板卡内核中来进行调试也行。
1.2 添加设备树节点
此处以【8行*3列】矩阵键盘为例
一定注意:Linux内核中定义矩阵键盘必须且只能为:【行GPIO输入,列GPIO输出】!!!不能搞错!!!
1.2.1 添加kpp节点
备注:本示例中的linux,keymap按键映射以较为容易理解、且直观的方式实现,内核驱动源码中的示例以及网上很多demo中写法都是形如0x02010058的写法,这样不太直观,不好理解,后面会对这种写法含义做出说明,两种写法都是可以的。
/*lsy*/ &kpp { compatible = "gpio-matrix-keypad"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_key>;
debounce<span class="token operator">-</span>delay<span class="token operator">-</span>ms <span class="token operator">=</span> <span class="token operator"><</span><span class="token number">20</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">/*防反跳延时,即:去抖延时*/</span> col<span class="token operator">-</span>scan<span class="token operator">-</span>delay<span class="token operator">-</span>us <span class="token operator">=</span> <span class="token operator"><</span><span class="token number">400</span><span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">/*列扫描延时*/</span> <span class="token comment">/*8行*/</span> row<span class="token operator">-</span>gpios <span class="token operator">=</span> <span class="token operator"><</span><span class="token operator">&</span>gpio2 <span class="token number">11</span> GPIO_ACTIVE_LOW <span class="token operator">&</span>gpio2 <span class="token number">12</span> GPIO_ACTIVE_LOW <span class="token operator">&</span>gpio2 <span class="token number">10</span> GPIO_ACTIVE_LOW <span class="token operator">&</span>gpio2 <span class="token number">8</span> GPIO_ACTIVE_LOW <span class="token operator">&</span>gpio2 <span class="token number">9</span> GPIO_ACTIVE_LOW <span class="token operator">&</span>gpio2 <span class="token number">13</span> GPIO_ACTIVE_LOW <span class="token operator">&</span>gpio2 <span class="token number">14</span> GPIO_ACTIVE_LOW <span class="token operator">&</span>gpio2 <span class="token number">15</span> GPIO_ACTIVE_LOW <span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">/*3列*/</span> col<span class="token operator">-</span>gpios <span class="token operator">=</span> <span class="token operator"><</span><span class="token operator">&</span>gpio2 <span class="token number">16</span> GPIO_ACTIVE_LOW <span class="token operator">&</span>gpio2 <span class="token number">17</span> GPIO_ACTIVE_LOW <span class="token operator">&</span>gpio2 <span class="token number">19</span> GPIO_ACTIVE_LOW <span class="token operator">></span><span class="token punctuation">;</span> <span class="token comment">/* 举例释义:MATRIX_KEY(0x2, 0x1, KEY_X)表示将【第2行1列的按键】映射为【KEY_X】 */</span> linux<span class="token punctuation">,</span>keymap <span class="token operator">=</span> <span class="token operator"><</span> <span class="token comment">/*row0*/</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x0</span><span class="token punctuation">,</span> <span class="token number">0x0</span><span class="token punctuation">,</span> KEY_LEFT<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x0</span><span class="token punctuation">,</span> <span class="token number">0x1</span><span class="token punctuation">,</span> KEY_DOWN<span class="token punctuation">)</span> <span class="token comment">/* row1 */</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x1</span><span class="token punctuation">,</span> <span class="token number">0x0</span><span class="token punctuation">,</span> KEY_UP<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x1</span><span class="token punctuation">,</span> <span class="token number">0x1</span><span class="token punctuation">,</span> KEY_RIGHT<span class="token punctuation">)</span> <span class="token comment">/* row2 */</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x2</span><span class="token punctuation">,</span> <span class="token number">0x0</span><span class="token punctuation">,</span> KEY_M<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x2</span><span class="token punctuation">,</span> <span class="token number">0x1</span><span class="token punctuation">,</span> KEY_X<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x2</span><span class="token punctuation">,</span> <span class="token number">0x2</span><span class="token punctuation">,</span> KEY_ENTER<span class="token punctuation">)</span> <span class="token comment">/*row3*/</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x3</span><span class="token punctuation">,</span> <span class="token number">0x0</span><span class="token punctuation">,</span> KEY_N<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x3</span><span class="token punctuation">,</span> <span class="token number">0x1</span><span class="token punctuation">,</span> KEY_O<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x3</span><span class="token punctuation">,</span> <span class="token number">0x2</span><span class="token punctuation">,</span> KEY_I<span class="token punctuation">)</span> <span class="token comment">/*row4*/</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x4</span><span class="token punctuation">,</span> <span class="token number">0x0</span><span class="token punctuation">,</span> KEY_7<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x4</span><span class="token punctuation">,</span> <span class="token number">0x1</span><span class="token punctuation">,</span> KEY_8<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x4</span><span class="token punctuation">,</span> <span class="token number">0x2</span><span class="token punctuation">,</span> KEY_9<span class="token punctuation">)</span> <span class="token comment">/*row5*/</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x5</span><span class="token punctuation">,</span> <span class="token number">0x0</span><span class="token punctuation">,</span> KEY_4<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x5</span><span class="token punctuation">,</span> <span class="token number">0x1</span><span class="token punctuation">,</span> KEY_5<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x5</span><span class="token punctuation">,</span> <span class="token number">0x2</span><span class="token punctuation">,</span> KEY_6<span class="token punctuation">)</span> <span class="token comment">/*row6*/</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x6</span><span class="token punctuation">,</span> <span class="token number">0x0</span><span class="token punctuation">,</span> KEY_1<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x6</span><span class="token punctuation">,</span> <span class="token number">0x1</span><span class="token punctuation">,</span> KEY_2<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x6</span><span class="token punctuation">,</span> <span class="token number">0x2</span><span class="token punctuation">,</span> KEY_3<span class="token punctuation">)</span> <span class="token comment">/*row7*/</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x7</span><span class="token punctuation">,</span> <span class="token number">0x0</span><span class="token punctuation">,</span> KEY_MINUS<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x7</span><span class="token punctuation">,</span> <span class="token number">0x1</span><span class="token punctuation">,</span> KEY_0<span class="token punctuation">)</span> <span class="token function">MATRIX_KEY</span><span class="token punctuation">(</span><span class="token number">0x7</span><span class="token punctuation">,</span> <span class="token number">0x2</span><span class="token punctuation">,</span> KEY_DOT<span class="token punctuation">)</span> <span class="token operator">></span><span class="token punctuation">;</span> gpio<span class="token operator">-</span>activelow<span class="token punctuation">;</span> status <span class="token operator">=</span> <span class="token string">"okay"</span><span class="token punctuation">;</span>
};
- 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
1.2.2 在iomuxc中添加pinctrl_复用节点
&iomuxc { ......
<span class="token comment">/*lsy*/</span> pinctrl_key<span class="token punctuation">:</span> kppgrp<span class="token punctuation">{<!-- --></span> fsl<span class="token punctuation">,</span>pins <span class="token operator">=</span> <span class="token operator"><</span> <span class="token comment">/* row 8行 */</span> MX6UL_PAD_ENET2_TX_DATA0__GPIO2_IO11 <span class="token number">0xb0b1</span> MX6UL_PAD_ENET2_TX_DATA1__GPIO2_IO12 <span class="token number">0xb0b1</span> MX6UL_PAD_ENET2_RX_EN__GPIO2_IO10 <span class="token number">0xb0b1</span> MX6UL_PAD_ENET2_RX_DATA0__GPIO2_IO08 <span class="token number">0xb0b1</span> MX6UL_PAD_ENET2_RX_DATA1__GPIO2_IO09 <span class="token number">0xb0b1</span> MX6UL_PAD_ENET2_TX_EN__GPIO2_IO13 <span class="token number">0xb0b1</span> MX6UL_PAD_ENET2_TX_CLK__GPIO2_IO14 <span class="token number">0xb0b1</span> MX6UL_PAD_ENET2_RX_ER__GPIO2_IO15 <span class="token number">0xb0b1</span> <span class="token comment">/* col 3列 */</span> MX6UL_PAD_SD1_CMD__GPIO2_IO16 <span class="token number">0x70a1</span> MX6UL_PAD_SD1_CLK__GPIO2_IO17 <span class="token number">0x70a1</span> MX6UL_PAD_SD1_DATA1__GPIO2_IO19 <span class="token number">0x70a1</span> <span class="token operator">></span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
};
- 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
1.2.3 屏蔽其他设备节点占用的键盘GPIO
非常重要:dts中所有键盘使用的GPIO在其他设备节点要是被占用,要全部屏蔽掉,方法此处不再赘述。
1.3 内核源码中按键映射写法
网上很多demo,包括驱动源码中的demo按键映射写法是如下这样写的,这样写也是可以的,只是没有上述代码看起来直观,一眼就能看出来映射的哪个按键而已。
linux中的按键映射文件为:include/uapi/linux/input.h文件,该文件中有键盘所有按键对应的十进制数,查到以后需要换算成十六进制,然后写成下述格式。
linux,keymap = < /*row0*/ 0x00000069 /*Qt.Key_Left -> HEX:69 -> DEC:105 -> KEY_LEFT */ 0x0001006C /*Qt.Key_Down -> HEX:6C -> DEC:108 -> KEY_DOWN */
<span class="token comment">/*row1*/</span> <span class="token number">0x01000067</span> <span class="token comment">/*Qt.Key_Up -> HEX:67 -> DEC:103 -> KEY_UP */</span> <span class="token number">0x0101006A</span> <span class="token comment">/*Qt.Key_Right -> HEX:6A -> DEC:106 -> KEY_RIGHT */</span> <span class="token comment">/*row2*/</span> <span class="token number">0x0200004D</span> <span class="token comment">/*Qt.Key_M -> HEX:4D -> DEC:77 -> KEY_KP6 */</span> <span class="token number">0x02010058</span> <span class="token comment">/*Qt.Key_X -> HEX:58 -> DEC:88 -> KEY_F12 */</span> <span class="token number">0x0202001C</span> <span class="token comment">/*Qt.Key_Return-> HEX:1C -> DEC:28 -> KEY_ENTER */</span> <span class="token comment">/*row3*/</span> <span class="token number">0x0300004E</span> <span class="token comment">/*Qt.Key_N -> HEX:4E -> DEC:78 -> KEY_KPPLUS*/</span> <span class="token number">0x0301004F</span> <span class="token comment">/*Qt.Key_O -> HEX:4F -> DEC:79 -> KEY_KP1 */</span> <span class="token number">0x03020049</span> <span class="token comment">/*Qt.Key_I -> HEX:49 -> DEC:73 -> KEY_KP9 */</span> <span class="token comment">/*row4*/</span> <span class="token number">0x04000008</span> <span class="token comment">/*Qt.Key_7 -> HEX:08 -> DEC: 8 -> KEY_7 */</span> <span class="token number">0x04010009</span> <span class="token comment">/*Qt.Key_8 -> HEX:09 -> DEC: 9 -> KEY_8 */</span> <span class="token number">0X0402000A</span> <span class="token comment">/*Qt.Key_9 -> HEX:0A -> DEC:10 -> KEY_9 */</span> <span class="token comment">/*row5*/</span> <span class="token number">0x05000005</span> <span class="token comment">/*Qt.Key_4 -> HEX:05 -> DEC: 5 -> KEY_4 */</span> <span class="token number">0x05010006</span> <span class="token comment">/*Qt.Key_5 -> HEX:06 -> DEC: 6 -> KEY_5 */</span> <span class="token number">0x05020007</span> <span class="token comment">/*Qt.Key_6 -> HEX:07 -> DEC: 7 -> KEY_6 */</span> <span class="token comment">/*row6*/</span> <span class="token number">0x06000002</span> <span class="token comment">/*Qt.Key_1 -> HEX:02 -> DEC: 2 -> KEY_1 */</span> <span class="token number">0x06010003</span> <span class="token comment">/*Qt.Key_2 -> HEX:03 -> DEC: 3 -> KEY_2 */</span> <span class="token number">0x06020004</span> <span class="token comment">/*Qt.Key_3 -> HEX:04 -> DEC: 4 -> KEY_3 */</span> <span class="token comment">/*row7*/</span> <span class="token number">0x0700002D</span> <span class="token comment">/*Qt.Key_Minux -> HEX:2D -> DEC:45 -> KEY_X */</span> <span class="token number">0x0701000B</span> <span class="token comment">/*Qt.Key_0 -> HEX:0B -> DEC:11 -> KEY_0 */</span> <span class="token number">0x0702002E</span> <span class="token comment">/*Qt.Key_Period-> HEX:2E -> DEC:46 -> KEY_C */</span> <span class="token operator">></span><span class="token punctuation">;</span>
- 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
二、硬件电路
2.1 上拉模式:输入GPIO硬件设计为上拉
原电路图包含其他功能,此处不贴原图了,就上个示意图就好,每个交叉口代表一个按键。
按键原理此处不再赘述,只说大概(matrix_keypad.c源码中的键盘原理分析见后面)。
流程大致如下:
- 1、行:全部设置为输入,且上拉,则默认总是检测到高电平。
- 2、列:从左到右,逐列输出低电平(每次只能有一列是低电平)
- 3、行:从上到下,逐行检测哪行出现低电平。
- 4、检测到低电平的行,对应此时激活的列,就可以判断哪个按键导通(按下)了。
备注:
Linux内核本身自带的Matrix机制比这个稍微复杂一些,但是:检测当前每个按键的状态(按下还是弹起)逻辑跟这个是一样的,后面会详细讲到。
大致来讲:
Linux内核定义2个数组,分别用于保存:【上一次按键状态last_key_state[]】和【本次按键状态new_state[]】 ,通过对比两次按键状态发现状态改变的按键,并逐一上报内核。(按键按下或弹起都算状态改变)
2.2 下拉模式:输入GPIO硬件设计为下拉
另外,上图电路图中行(输入)为上拉,如果电路硬件设计为下拉的话,则设备树中可以做如下修改:
一、修改默认电平:
将设备树节点中行和列的【GPIO_ACTIVE_LOW】全部修改为【GPIO_ACTIVE_HIGH】
将【gpio-activelow;】修改为【gpio-activehigh;】
二、调整去抖延时和列扫描延时
debounce-delay-ms = <100>; /防反跳延时,即:去抖延时/
col-scan-delay-us = <2000>; /列扫描延时/
- 1
- 2
- 3
- 4
- 5
- 6
- 7
三、调试步骤
3.1 调试工具推荐
调试按键的时候,/dev/input/路径下:event0是矩阵按键设备,event1是普通按键设备,event2 是电阻屏触摸设备
3.1.1 hexdump命令
使用hexdump命令调试,按键按下以后产生的数据,以及含义解析如下:
root@imx6ulevk:~# hexdump /dev/input/event0
/* 事件序号 tv_sec tv_usec type code value */
0000000 ef7a 59c3 16e6 0006 0004 0004 0000 0000
0000010 ef7a 59c3 16e6 0006 0001 0069 0001 0000 <---------0x69按键按下
0000020 ef7a 59c3 16e6 0006 0000 0000 0000 0000
0000030 ef7a 59c3 c3f9 0007 0004 0004 0000 0000
0000040 ef7a 59c3 c3f9 0007 0001 0069 0000 0000 <---------0x69按键弹起
0000050 ef7a 59c3 c3f9 0007 0000 0000 0000 0000
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
这里只说右边4列含义:
右起第4列【type列】:事件类型,0001表示产生了按键事件,其他类型见【附加知识小节:Linux内核中的事件类型】
右起第3列【code列】:表示十六进制编码,如果是按键事件的话,则对应key的十六进制值,在内核源码include/uapi/linux/input.h中可以查到每个按键的十进制编码。
最右边2列【value列】:按键的值,0001 0000表示按下,0000 0000表示弹起
- 1
- 2
- 3
- 4
- 5
3.1.2 类hexdump工具源码(极力推荐,使用起来很方便)
该工具使用起来非常人性化,不像上面那样,每个按键,键值啥的十六进制、十进制还要转换,而且很难看。
-
工具源码见另一篇博客:hexdump调试小工具——获取event事件信息、键盘按键信息等
或github链接:【https://github.com/lishiyuan/tools_hexdump】
-
使用方法为:
将源码进行交叉编译,生成可执行文件read_linux_key_value(名字看自己喜好了),然后拷贝到板卡,使用命令
//Linux中交叉编译 arm-linux-gnueabihf-gcc -o read_linux_key_value xxx.c
//拷贝read_linux_key_value到板卡执行下面命令,
./read_linux_key_value 0 <––0表示设备event0
- 1
- 2
- 3
- 4
- 5
-
该工具使用效果如下:
root@imx6ulevk:~# ./read_linux_key_value 0 /dev/input/event0 evdev version: 1.0.1 name: 20b8000.kpp features: unknown keys/buttons reserved repeat /dev/input/event0: open, fd = 3 Thu Sep 21 17:27:47 2017.869136 type 0x0004; code 0x0004; value 0x00000000; Misc Thu Sep 21 17:27:47 2017.869136 type 0x0001; code 0x0069; value 0x00000001; Key 105 (0x69) press Thu Sep 21 17:27:47 2017.869136 type 0x0000; code 0x0000; value 0x00000000; Thu Sep 21 17:27:47 2017.998944 type 0x0004; code 0x0004; value 0x00000000; Misc Thu Sep 21 17:27:47 2017.998944 type 0x0001; code 0x0069; value 0x00000000; Key 105 (0x69) release Thu Sep 21 17:27:47 2017.998944 type 0x0000; code 0x0000; value 0x00000000;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
是不是很爽!
3.2 调试流程
3.2.1 大致调试流程如下图
备注:具体流程分析见下一小节
3.2.2 调试流程具体步骤描述如下
-
先将每个GPIO分别设置为普通IO口,验证输入输出均可控(不管是采用裸机方式还是GPIO export shell命令的方式都行,这里不再赘述方法)。
如果发现有GPIO不可控,则排查dts中是否有别的地方复用了该引脚,要全部屏蔽掉,或者检查硬件电路设计是否无误。
-
板卡【/dev/input/】目录下是否正确生成event0设备:
若否,则首先排查自己添加的kpp节点中【行列属性】以及【linux,keymap属性】中行列描述是否正确;
如果kpp正确,则排查板卡【/sys/firmware/devicetree/base】目录下设备kpp节点是否符合预期,自己的加的kpp是否生效:
备注:
【/sys/firmware/devicetree/base】目录就是整个dts,按照最顶层设备树文件imx6ul.dtsi中的设备节点逐个展开,整个dts的节点以及属性全部展现在sysfs中。此外,还有一个软连接也是指向该路径的【ls /proc/device-tree】。
具体可以查阅该博客【转:致驱动工程师的一封信】。
按照imx6ul设备树描述,追到最顶层设备树【imx6ul.dtsi】文件中,发现kpp节点描述有如下层级关系:
//imx6ul-14x14-evk.dts中引用了imx6ul.dtsi //追到imx6ul.dtsi中,该文件结构如下:
/ {
.......
soc {
.......
aips1: aips-bus@02000000 {
.......
kpp: kpp@020b8000 {
.......
}
.......
}
}
}- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
因此在板卡【/sys/firmware/devicetree/base/soc/aips-bus@02000000】目录下查阅该节点是否包含自己定义的节点信息,如果否,则说明自己定义的节点必定有问题,都未生效,功能肯定不对。
-
-
使用上面提到【hexdump /dev/input/event0】命令或【类hexdump工具】来进行功能验证,验证方法见上一小节【调试工具推荐】,如果发现按键数据不对,继续后续步骤
-
观察按键有无反应,用示波器抓波是否存在波形,分析波形是否符合预期;
-
阅读内核源码,在内核源码中增加log,打印输出,查看上报的数据是否正确;
备注:源码路径为【drivers/input/keyboard/matrix_keypad.c】,通常情况下,源码是无需更改的,除非自己要定制特殊功能!毕竟经过全世界各种大佬们的验证,肯定比自己牛x多了,出现逻辑问题的几率非常非常小。一般情况最多就是在源码中增加一些printk打印变量log,观测value,帮自己分析问题,定位问题。
-
具体问题具体分析,见下一节【调试过程中遇到的坑】
3.3 源码中添加调试log小技巧
-
在源码c文件中添加log的时候,这里推荐一个小技巧,在文件顶部定义如下宏:
//#define lsydebug(fmt,args...) printk(KERN_ERR "[lsy]:%s:%d:" fmt,__func__,__LINE__,##args) #define lsydebug(fmt,args...)
- 1
- 2
这样代码中添加log的时候可以像这样:
......
<span class="token function">memset</span><span class="token punctuation">(</span>new_state<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>new_state<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">lsydebug</span><span class="token punctuation">(</span><span class="token string">"row = pdata->num_row_gpios = %d\r\n"</span><span class="token punctuation">,</span> pdata<span class="token operator">-></span>num_row_gpios<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token function">lsydebug</span><span class="token punctuation">(</span><span class="token string">"col = pdata->num_col_gpios = %d\r\n"</span><span class="token punctuation">,</span> pdata<span class="token operator">-></span>num_col_gpios<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
当调试完毕以后,直接保留#define lsydebug(fmt,args…)即可,调试log也不会出现了,不用一个个全删除,其他好处自行体会。
-
-
备注:或者也可以这样:
//#define DEBUG 1
#ifdef DEBUG
#define lsydebug(fmt,args…) printk(KERN_ERR “[lsy]:%s:%d:” fmt,func,LINE,##args)
#else
#define lsydebug(fmt,args…)
#endif- 1
- 2
- 3
- 4
- 5
- 6
- 7
四、调试过程中遇到的坑
-
通常情况,源码matrix_keypad.c无需做修改,仅仅在调试的时候需要增加一些log信息用于观测变量值而已。也就是说配置内核自带matrix矩阵键盘功能只需要配置dts即可。
配置完dts后,如果无误,会在板卡/dev/input/目录下生成event0设备,如果发现该目录下并未生成该设备,则有很大一种可能性是:dts中配置节点行列有误,导致内核无法识别matrix,所以未生成event0设备,排查思路如下:
- 查看dts中节点【row-gpios、col-gpios行列描述】与【linux,keymap属性行列描述】是否正确,具体规则见后面几条。
- 查看【/sys/firmware/devicetree/base/soc/aips-bus@02000000】目录下查阅kpp节点是否包含自己定义的节点信息,若否,则必有问题,节点都未生效,功能肯定不对。
-
设备树中:行、列一定不能反!Linux内核规定matrix功能:行必须为输入,列必须为输出。
row-gpios成员为行,
col-gpios成员为列。
-
设备树中:linux,keymap属性键值映射,行列也不能反,反了就乱。
正确格式如下两种任选其一都行(推荐第一种,容易理解,且更加直观):
(1)MATRIX_KEY(0x3, 0x1, KEY_O):表示将第3行,第1列按键映射为KEY_O,
(2)0x03020069:表示将第3行,第2列按键映射为0x69对应的按键。按键键值可以在include/uapi/linux/input.h中找到,需要注意:该文件中#define键值为十进制。比如0x69对应十进制为105,在文件中查得105对应按键:KEY_LEFT
0x 00 00 0069 十六进制 行序号 列序号 按键十六进制键值 -
上述编译选项menuconfig中该打开的功能必须打开。
-
设备树中:延时一定要调整合适,否则可能会出现按下一个按键,整行按键都被上报到event设备中。
debounce-delay-ms = <20>; /*防反跳延时,即:去抖延时*/ col-scan-delay-us = <400>; /*列扫描延时*/
- 1
- 2
-
设备树中:kpp节点中如果定义了属性:gpio-activelow,就是告诉软件层面【低电平有效】,激活端口时,必须设置为低电平。应用在函数【__activate_col()】中。
五、Matrix内核源码逻辑分析
源码路径为【drivers/input/keyboard/matrix_keypad.c】,通常情况下,源码是无需更改的,除非自己要定制特殊功能!
此处对源码逻辑、扫描原理、以及代码中部分重要函数进行分析:
5.1 Matrix整体功能逻辑图
后续补充
5.2 键盘matrix_keypad_scan()函数扫描原理
5.2.1 键盘示意图
为了简单,以【3行,4列】键盘为例:
5.2.2 键盘和保存GPIO状态的数组定义
键盘原理中,列GPIO必须配置为输出,行GPIO必须配置为输入,注意一定更不能搞反!!
以【3行,4列】键盘为例,其中:
-
列GPIO:输出,4列
行GPIO:输入,3行
-
内核源码中定义了2个数组:【旧状态】数组last_key_state[],和【新状态】数组new_state[],都是u32类型(整型int)。
其中:
数组 含义 【旧状态数组 last_key_state[]】 用来保存上一次每行GPIO的电平状态 【新状态数组 new_state[]】 用来保存此次每行GPIO的电平状态 【数组成员】 键盘有m列,则数组就都有m个成员(数组角标为col)
一个数组成员,对应一列
如:
new_state[0] 用于保存第0列电平状态
new_state[1] 用于保存第1列电平状态
new_state[2] 用于保存第2列电平状态
new_state[3] 用于保存第3列电平状态
last_key_state[col]同理【数组每个成员bit位】 对应键盘n行,每个bit位的0/1代表每一行的状态(成员bit为row)
一个bit,对应一行
如:
每个成员的 bit0 用于保存第0行输入电平状态
每个成员的 bit1 用于保存第1行输入电平状态
每个成员的 bit2 用于保存第2行输入电平状态
last_key_state[col]每个bit位同理查找对应按键原理 这样,
1、函数外层for循环—>先匹配到数组成员(列),
2、然后函数函数内层for循环—>通过移位方式,匹配到某个bit位(行),
3、则自然而然的查找到【某列-某行】的按键。此例子中:
last和new数组分别都有4个成员(因为有4列),每个成员有效位为bit0、bit1、bit2(共3个有效bit,因为有3行)。
每个成员有效bit为代表了对应行的输入电平状态。
如下示意图:每一列就是一个u32位的变量,此例子中低3位有效,表示有效行3行。
LAST:上一个状态 last_key_state[0] last_key_state[1] last_key_state[2] last_key_state[3] col0 col1 col2 col3 row0 -- bit[0] bit[0] bit[0] bit[0] row1 -- bit[1] bit[1] bit[1] bit[1] row2 -- bit[2] bit[2] bit[2] bit[2]
NEW:当前状态
new_state[0] new_state[1] new_state[2] new_state[3]
col0 col1 col2 col3
row0 – bit[0] bit[0] bit[0] bit[0]
row1 – bit[1] bit[1] bit[1] bit[1]
row2 – bit[2] bit[2] bit[2] bit[2]- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
5.2.3 matrix_keypad_scan() 函数源码解析
该函数源码大体结构如下:
-
主要是2个双层for循环:
-
第一个双层for循环用于获取当前所有按键状态,保存在new_state[]矩阵中;
-
第二个双层for循环将new_state[]和last_key_state[]做比较,匹配每一个状态改变的按键,并将每个按键状态都上报input子系统。
-
-
备注:
第二个双层for循环中有一行异或操作需要注意:
bits_changed = keypad->last_key_state[col] ^ new_state[col];
- 1
不要把bits_changed的含义理解错了:
注意亦或的含义:不同为1,所以该条语句执行完以后,bits_changed对应bit是1的话,仅仅是标识哪一行电平状态改变了,并不是代表该行电平!!!该行电平在new_state[col]的对应bit位保存!!! -
下面是matrix_keypad_scan()函数的源码,我在里面加了一些注释如下:
/* * This gets the keys from keyboard and reports it to input subsystem */ static void matrix_keypad_scan(struct work_struct *work) { struct matrix_keypad *keypad = container_of(work, struct matrix_keypad, work.work); struct input_dev *input_dev = keypad->input_dev; const unsigned short *keycodes = input_dev->keycode; const struct matrix_keypad_platform_data *pdata = keypad->pdata; uint32_t new_state[MATRIX_MAX_COLS]; int row, col, code;
<span class="token function">dbg</span><span class="token punctuation">(</span><span class="token string">"Etnry scan!\r\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/* de-activate all columns for scanning */</span> <span class="token function">activate_all_cols</span><span class="token punctuation">(</span>pdata<span class="token punctuation">,</span> false<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*反激活全部列,扫描结束后再全部激活*/</span> <span class="token function">memset</span><span class="token punctuation">(</span>new_state<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>new_state<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*先清0当前按键状态矩阵,避免检测错误*/</span> <span class="token comment">/* assert each column and read the row status out */</span> <span class="token comment">/* 一、该双层for循环:按顺序依次改变每列电平并获取对应行电平,保存在new矩阵中,后面和last矩阵对比判断是否状态改变 */</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>col <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> col <span class="token operator"><</span> pdata<span class="token operator">-></span>num_col_gpios<span class="token punctuation">;</span> col<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token function">activate_col</span><span class="token punctuation">(</span>pdata<span class="token punctuation">,</span> col<span class="token punctuation">,</span> true<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*激活某列*/</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>row <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> row <span class="token operator"><</span> pdata<span class="token operator">-></span>num_row_gpios<span class="token punctuation">;</span> row<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> new_state<span class="token punctuation">[</span>col<span class="token punctuation">]</span> <span class="token operator">|</span><span class="token operator">=</span> <span class="token function">row_asserted</span><span class="token punctuation">(</span>pdata<span class="token punctuation">,</span> row<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator"><<</span> row<span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">;</span> <span class="token comment">/*获取每一行的电平,存放在对应bit*/</span> <span class="token punctuation">}</span> <span class="token function">activate_col</span><span class="token punctuation">(</span>pdata<span class="token punctuation">,</span> col<span class="token punctuation">,</span> false<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*反激活某列*/</span> <span class="token punctuation">}</span> <span class="token comment">/* 二、该双层for循环:将new和last作比较,每匹配到一个状态改变的按键,就向event设备发送一次数据*/</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>col <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> col <span class="token operator"><</span> pdata<span class="token operator">-></span>num_col_gpios<span class="token punctuation">;</span> col<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> uint32_t bits_changed<span class="token punctuation">;</span> <span class="token comment">/* * 先直接对整个变量(全部行状态)异或操作, * 如果任意一个bit(即:任意一行)状态改变,bits_changed必不为0 * 说明至少有一行状态有改变 */</span> bits_changed <span class="token operator">=</span> keypad<span class="token operator">-></span>last_key_state<span class="token punctuation">[</span>col<span class="token punctuation">]</span> <span class="token operator">^</span> new_state<span class="token punctuation">[</span>col<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>bits_changed <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment">/*若所有行均无变化,则继续下一列*/</span> <span class="token keyword">continue</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>row <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> row <span class="token operator"><</span> pdata<span class="token operator">-></span>num_row_gpios<span class="token punctuation">;</span> row<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>bits_changed <span class="token operator">&</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator"><<</span> row<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token comment">/*通过row的移位,逐个判断每个bit位(每行)的状态是否有变化*/</span> <span class="token keyword">continue</span><span class="token punctuation">;</span> <span class="token comment">/*若当前行无变化,则继续下一行*/</span> <span class="token comment">/*每碰到一个有变化的bit(即:变化行),则开始上报内核*/</span> code <span class="token operator">=</span> <span class="token function">MATRIX_SCAN_CODE</span><span class="token punctuation">(</span>row<span class="token punctuation">,</span> col<span class="token punctuation">,</span> keypad<span class="token operator">-></span>row_shift<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*确定变化的行列,就取出dts中定义的code*/</span> <span class="token function">input_event</span><span class="token punctuation">(</span>input_dev<span class="token punctuation">,</span> EV_MSC<span class="token punctuation">,</span> MSC_SCAN<span class="token punctuation">,</span> code<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*向输入子系统上报输入设备产生的事件*/</span> <span class="token function">input_report_key</span><span class="token punctuation">(</span>input_dev<span class="token punctuation">,</span> keycodes<span class="token punctuation">[</span>code<span class="token punctuation">]</span><span class="token punctuation">,</span> new_state<span class="token punctuation">[</span>col<span class="token punctuation">]</span> <span class="token operator">&</span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator"><<</span> row<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*上报按键事件*/</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token function">input_sync</span><span class="token punctuation">(</span>input_dev<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*通知接收者,一个报告上报完毕。至此通过双层for循环,上报了所有按下的按键*/</span> <span class="token function">memcpy</span><span class="token punctuation">(</span>keypad<span class="token operator">-></span>last_key_state<span class="token punctuation">,</span> new_state<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span>new_state<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*一次全键盘扫描完毕,当前状态覆盖上次状态*/</span> <span class="token function">activate_all_cols</span><span class="token punctuation">(</span>pdata<span class="token punctuation">,</span> true<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*扫描结束,激活全部列*/</span> <span class="token comment">/* Enable IRQs again */</span> <span class="token function">spin_lock_irq</span><span class="token punctuation">(</span><span class="token operator">&</span>keypad<span class="token operator">-></span>lock<span class="token punctuation">)</span><span class="token punctuation">;</span> keypad<span class="token operator">-></span>scan_pending <span class="token operator">=</span> false<span class="token punctuation">;</span>
enable_row_irqs(keypad);
spin_unlock_irq(&keypad->lock);
}- 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
5.3 其他几个重要函数
5.3.1 matrix_keypad_parse_dt()函数源码解析
-
该函数作用为:解析dts中矩阵键盘的配置
#ifdef CONFIG_OF /*解析dts中矩阵键盘的配置*/ static struct matrix_keypad_platform_data *matrix_keypad_parse_dt(struct device *dev) { struct matrix_keypad_platform_data *pdata; struct device_node *np = dev->of_node; unsigned int *gpios; int i, nrow, ncol;
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>np<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token function">dev_err</span><span class="token punctuation">(</span>dev<span class="token punctuation">,</span> <span class="token string">"device lacks DT data\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">ERR_PTR</span><span class="token punctuation">(</span><span class="token operator">-</span>ENODEV<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> pdata <span class="token operator">=</span> <span class="token function">devm_kzalloc</span><span class="token punctuation">(</span>dev<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token operator">*</span>pdata<span class="token punctuation">)</span><span class="token punctuation">,</span> GFP_KERNEL<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>pdata<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token function">dev_err</span><span class="token punctuation">(</span>dev<span class="token punctuation">,</span> <span class="token string">"could not allocate memory for platform data\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">ERR_PTR</span><span class="token punctuation">(</span><span class="token operator">-</span>ENOMEM<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> pdata<span class="token operator">-></span>num_row_gpios <span class="token operator">=</span> nrow <span class="token operator">=</span> <span class="token function">of_gpio_named_count</span><span class="token punctuation">(</span>np<span class="token punctuation">,</span> <span class="token string">"row-gpios"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*解析获取行、列总数量*/</span> pdata<span class="token operator">-></span>num_col_gpios <span class="token operator">=</span> ncol <span class="token operator">=</span> <span class="token function">of_gpio_named_count</span><span class="token punctuation">(</span>np<span class="token punctuation">,</span> <span class="token string">"col-gpios"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>nrow <span class="token operator"><=</span> <span class="token number">0</span> <span class="token operator">||</span> ncol <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token function">dev_err</span><span class="token punctuation">(</span>dev<span class="token punctuation">,</span> <span class="token string">"number of keypad rows/columns not specified\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">ERR_PTR</span><span class="token punctuation">(</span><span class="token operator">-</span>EINVAL<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">of_get_property</span><span class="token punctuation">(</span>np<span class="token punctuation">,</span> <span class="token string">"linux,no-autorepeat"</span><span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">)</span> pdata<span class="token operator">-></span>no_autorepeat <span class="token operator">=</span> true<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">of_get_property</span><span class="token punctuation">(</span>np<span class="token punctuation">,</span> <span class="token string">"linux,wakeup"</span><span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">)</span> pdata<span class="token operator">-></span>wakeup <span class="token operator">=</span> true<span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">of_get_property</span><span class="token punctuation">(</span>np<span class="token punctuation">,</span> <span class="token string">"gpio-activelow"</span><span class="token punctuation">,</span> <span class="token constant">NULL</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">/*如果定义了该变量,表示软件层面为低电平有效,则激活端口时必须设置为低电平,具体见函数__activate_col()*/</span> pdata<span class="token operator">-></span>active_low <span class="token operator">=</span> true<span class="token punctuation">;</span> <span class="token function">of_property_read_u32</span><span class="token punctuation">(</span>np<span class="token punctuation">,</span> <span class="token string">"debounce-delay-ms"</span><span class="token punctuation">,</span> <span class="token operator">&</span>pdata<span class="token operator">-></span>debounce_ms<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">/*消抖延时*/</span> <span class="token function">of_property_read_u32</span><span class="token punctuation">(</span>np<span class="token punctuation">,</span> <span class="token string">"col-scan-delay-us"</span><span class="token punctuation">,</span> <span class="token operator">&</span>pdata<span class="token operator">-></span>col_scan_delay_us<span class="token punctuation">)</span><span class="token punctuation">;</span> gpios <span class="token operator">=</span> <span class="token function">devm_kzalloc</span><span class="token punctuation">(</span>dev<span class="token punctuation">,</span> <span class="token keyword">sizeof</span><span class="token punctuation">(</span><span class="token keyword">unsigned</span> <span class="token keyword">int</span><span class="token punctuation">)</span> <span class="token operator">*</span> <span class="token punctuation">(</span>pdata<span class="token operator">-></span>num_row_gpios <span class="token operator">+</span> pdata<span class="token operator">-></span>num_col_gpios<span class="token punctuation">)</span><span class="token punctuation">,</span> GFP_KERNEL<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>gpios<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token function">dev_err</span><span class="token punctuation">(</span>dev<span class="token punctuation">,</span> <span class="token string">"could not allocate memory for gpios\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">ERR_PTR</span><span class="token punctuation">(</span><span class="token operator">-</span>ENOMEM<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> pdata<span class="token operator">-></span>num_row_gpios<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token comment">/*解析获取行GPIO*/</span> gpios<span class="token punctuation">[</span>i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">of_get_named_gpio</span><span class="token punctuation">(</span>np<span class="token punctuation">,</span> <span class="token string">"row-gpios"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span>i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> pdata<span class="token operator">-></span>num_col_gpios<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token comment">/*解析获取列GPIO*/</span> gpios<span class="token punctuation">[</span>pdata<span class="token operator">-></span>num_row_gpios <span class="token operator">+</span> i<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">of_get_named_gpio</span><span class="token punctuation">(</span>np<span class="token punctuation">,</span> <span class="token string">"col-gpios"</span><span class="token punctuation">,</span> i<span class="token punctuation">)</span><span class="token punctuation">;</span> pdata<span class="token operator">-></span>row_gpios <span class="token operator">=</span> gpios<span class="token punctuation">;</span> pdata<span class="token operator">-></span>col_gpios <span class="token operator">=</span> <span class="token operator">&</span>gpios<span class="token punctuation">[</span>pdata<span class="token operator">-></span>num_row_gpios<span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">return</span> pdata<span class="token punctuation">;</span>
}
#else
static inline struct matrix_keypad_platform_data matrix_keypad_parse_dt(struct device dev)
{
dev_err(dev, “no platform data defined\n”);<span class="token keyword">return</span> <span class="token function">ERR_PTR</span><span class="token punctuation">(</span><span class="token operator">-</span>EINVAL<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
#endif- 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
5.3.2 matrix_keypad_init_gpio()函数源码解析
-
该函数作用为:后续补充
- 1
六、附加知识
6.1 Linux内核中的事件类型
-
输入事件类型:可选的事件类型定义在 include/uapi/linux/input.h 文件中
#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 /* LED */ #define EV_SND 0x12 /* sound(声音) */ #define EV_REP 0x14 /* 重复事件 */ #define EV_FF 0x15 /* 压力事件 */ #define EV_PWR 0x16 /* 电源事件 */ #define EV_FF_STATUS 0x17 /* 压力状态事件 */
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
至此,结束!
</article>