键盘驱动的原理
http://blog.csdn.net/zhenwenxian/article/details/6064299
键盘驱动的设置
1,一般要初始化矩阵键盘的行数和列数,设置矩阵的扫描驱动线的开始gpio,设置矩阵的扫描输入线的开始gpio,利用循环分别对每个扫描驱动线的gpio初始化为输出脚,利用循环分别对每个扫描输入线的gpio初始化为输入脚。
2, 在模块加载函数中注册输入设备。
注册输入设备的函数为:
int input_register_device(struct input_dev *dev); |
3,在probe函数
申请一个输入设备,告知input子系统它可以报告的事件。
设备驱动通过set_bit()告诉input子系统它支持哪些事件,如下所示:
set_bit(EV_KEY, button_dev.evbit); |
初始化键盘的映射表,申请键盘中断,打开中断。
4,实现中断处理函数,中断处理函数是响应中断,读出键盘的按键缓冲区的数据,对每个比特检查,看那个按键按下,将扫描码转换为按键码通过
input_report_key() 报按键
后面跟input_sync()用于事件同步,它告知事件的接收者驱动已经发出了一个完整的报告。
getevent & sendevent
getevent监控当前的事件,鼠标事件,按键事件,拖动滑动等
在命令行通过pc键盘输入getevent可以监控当前的事件
# getevent
getevent
add device 1: /dev/input/event0
name: "qwerty2"
/dev/input/event0: 0001 001e 00000001
/dev/input/event0: 0001 001e 00000000
其中/dev/input/event0是device的名字 0001是type, 001e是键码, 最后一个根据type不同而不同
比如上面的倒数第二条就是按下a键的keydown,最后一个是按下a的keyup
具体的type,code,value的定义可以在源码/frameworks/base/core/java/android/view/KeyEvent.java中找到
sendevent发送时间,格式和上面的一样,需要注意的是在get中code显示的是十六进制,而send中需要用十进制,例如
# sendevent /dev/input/event0 1 5 1
这个命令就是发送数字4的keydown消息,所以在屏幕上就会一直打印出很多个4(因为没有发送keyup)
static const uint32_t hs_key_map[] = {
KEY(HS_PWR_K, KEY_POWER),
KEY(HS_END_K, KEY_END),
KEY(HS_STEREO_HEADSET_K, SW_HEADPHONE_INSERT),
KEY(HS_HEADSET_SWITCH_K, KEY_MEDIA),
0
};
static int hs_find_key(uint32_t hscode)
{
int i, key;
key = KEY(hscode, 0);
for (i = 0; hs_key_map[i] != 0; i++) {
if ((hs_key_map[i] & 0xff000000) == key)
return hs_key_map[i] & 0x00ffffff;
}
return -1;
}
static void report_hs_key(uint32_t key_code, uint32_t key_parm)
{
int key, temp_key_code;
if (key_code == HS_REL_K)
key = hs_find_key(key_parm);
else
key = hs_find_key(key_code);
temp_key_code = key_code;
if (key_parm == HS_REL_K)
key_code = key_parm;
switch (key) {
case KEY_POWER:
case KEY_END:
case KEY_MEDIA:
input_report_key(hs->ipdev, key, (key_code != HS_REL_K));
break;
case SW_HEADPHONE_INSERT:
report_headset_switch(hs->ipdev, key, (key_code != HS_REL_K));
break;
case -1:
printk(KERN_ERR "%s: No mapping for remote handset event %d/n",
__func__, temp_key_code);
return;
}
input_sync(hs->ipdev);