嵌入式开发|键盘驱动程序的修改

1、需求
原有BSP中,键盘使用了GPIO的16根引脚,8根输入、8根输出。而用户提供的硬件一共使用了9根GPIO的引脚,5根输入、5根输出,按键一共17个,分别是0-9、F1-F5以及CLS和FIX,除了数字以外的其它7个键都有要求返回的具体值,也就是键盘的虚拟码,其中,F1-F5与系统中定义的值相同,而CLS和FIX分别对应了系统中另外的两个Fn。

2、分析
想要实现键盘的功能首先要配置与它相关的GPIO引脚功能,这个需要根据用户提供的硬件说明来做。然后,需要测试它的当前对应得虚拟码,如果说正常就可以了,不需要再做太多的改动了。

3、对应需求的具体步骤
【嵌入式开发|键盘驱动程序的修改】1)、配置键盘的功能码。
所有GPIO引脚的相关配置(也就是MFP相关的功能)文件,都集中在wince60/PlatForm/XXX/src/driver/xllp_plat/source目录下,以“xllp_”为前缀,再加上具体配置的功能,后缀可能还会有“_plat”,比如说对于现在的键盘功能的配置,需要修改:xllp_keypad_plat.c文件。需要修改的主是配置相关的列表,包括引脚的偏移量列表、引脚功能列表、引脚驱动强度列表等等,以上列出的这三个是主要的功能配置,它们会在XllpMfpSetAfDs_List()被使用;中断相关配置的列表,通过XllpMfpConfigureWakeup_List()函数可以来完成对每个引脚的中断配置(这里说是中断可能并不是很准确);还有其它需要对应的list表 。
对于引脚的偏移量列表、引脚功能列表的修改有两种方法:①修改头文件的相应宏定义,把相应的引脚宏对应成为需要的GPIO引脚偏移量的宏,这样的话, 引脚的偏移量列表不需要再改动,但需要把多余的引脚注释掉(对于这些多余的引脚,在头文件中相应得宏定义最好也注释掉)②直接修改引脚的偏移量列表,在该列表中直接使用所需GPIO引脚偏移量的宏定义,注释掉多余的引脚。对于两种方法,各有利弊,前者修改了头文件,将会影响到引用它的所有文件,有可能带来一些问题;后者只修改了对应的列表,但是因为这些引脚功能已经变化,之前使用它们的地方现在并不知道它们的功能已经发生变化,可能错误地使用(这些完全是个人看法)。
按照硬件引脚的使用说明,做出了相应得修改后,重新编译生成了NK.bin文件
2)、利用测试程序简单测试每个按键的虚拟码的当前值,目的当然是想看看可不可以偷懒。结果,有的重复了、有的没响应,结论:键盘的映射有很严重的问题,导致映射到上层的虚拟码出现了极大的偏差。没办法,学习键盘的驱动代码,一层函数一层函数的查看,然后大概确定了需要该得文件和可能的修改方法。
这里,把整个keypad驱动的工作流程大概总结了一下,并不是很全面的,只是在修改过程中需要修改或者说要了解的东西:(以下是按照从最低层GPIO寄存器中读取数据、得到最底层的ScanCode、经过两次映射得到虚拟码这样的顺序来记录的)
XXX/ SRC/SoC/PXA310…/xllp_processor/source/xllp_keypad_proc.c文件中,使用函数:read_scan_code_automatically() ,该函数直接从键盘对应的寄存器中读取数据,然后把该数据做相应处理后,作为输出参数返回,同时返回读取状态。这个返回参数作为索引(ScanCode_index)在最底层的ScanCode_List进行查找时使用
XXX/SRC/driver/xllp_plat/source/xllp_keypad_plat.c文件中,使用函数:XllpReadScanCode(),该函数调用①中的函数获得索引值(ScanCode_index),在ScanCode_List中查找,再将找到的ScanCode_Value作为参数返回。该返回值将作为第一层影射的索引,在XllpScanCodeToWinCeScanCodeTable查询时使用。
XXX/ SRC/SoC/PXA310…/keypad/keypadcommon/keypad.cpp文件中,有KeyPadPdd_GetEventEx2()和KeyPadDataRead()函数。KeyPadDataRead()函数直接调用②中的函数,获得ScanCode_Value。KeyPadPdd_GetEventEx2()调用其获得ScanCode_Value,稍作检测和少许处理后在XllpScanCodeToWinCeScanCodeTable(该表在④的文件中被定义)中寻找ScanCodeLocal_Value,并作为参数返回(这里的参数是一个数组,大小为16,他可以存放若干个KeyEvent所对应的ScanCodeLocal_Value)。这个返回值会在最后一层影射中作为索引来使用。
KeyPadPdd_GetEventEx2()函数会在KeyPad产生中断时,被中断线程调用。KeyPad::IsrThreadProc()初始化中断的成功之后,会把它赋值给KEYBD_IST结构的变量KeyPadIst,然后,执行语句:KeybdIstLoop(&keyPadIst);
XXX/ SRC/SoC/PXA310…/keypad/BuiltInKeypad_**/ BuiltInKeypad_**.cpp文件中使用(**是数字),初始化函数BuiltInKeypad()会把其参数PDEVICE_LAYOUT pDeviceLayout赋值为dlBuiltInKeypad,即初始化。
static DEVICE_LAYOUT dlBuiltInKeypad =
{
sizeof(DEVICE_LAYOUT),
KEYPAD_PDD_ID,
rgscvkBuiltInKeypad_Tables,
dim(rgscvkBuiltInKeypad_Tables),
BuiltInKeypad_RemapVKey,
};
其中,rgscvkBuiltInKeypad_Tables是一个ScanCodeToVKeyData的结构的2元数组,通过这个结构以及函数BuiltInKeypad_RemapVKey,我们可以完成最后一层映射工作。
static ScanCodeToVKeyDataMainScanCodeToVKeyTableInfo=
{
0,
MainScanCodeTableFirst,
MainScanCodeTableLast,
(UINT8 *) &MainScanCodeToVKeyTable[0]
};
static ScanCodeToVKeyDataUniqueKeyScanCodeToVKeyTableInfo=
{
UNIQUE_KEY_SC_PREPEND_MSK,
UniqueKeyScanCodeTableFirst,
UniqueKeyScanCodeTableLast,
(UINT8 *) &UniqueKeyScanCodeToVKeyTable[0]
};
static ScanCodeToVKeyData *rgscvkBuiltInKeypad_Tables[] =
{ &MainScanCodeToVKeyTableInfo, &UniqueKeyScanCodeToVKeyTableInfo };
3)、具体的修改
了解了键盘驱动的大支流程之后,发现没有必要修改太多代码,只要修改映射表中的值基本就可以搞定问题。于是从最底层开始添加调试信息,查看低一层映射表返回给高一层映射表的值(即作为高一层映射的索引值)、以及通过该索引在高一层映射表中对应的值有什么差别和问题。
根据调试信息显示,以寄存器中读到的数据作为索引,在ScanCode_List查询已经发生了错误,无法正确和上层的进行映射。同时,不希望修改UniqueKeyScanCodeToVKeyTable表中的值(感觉这个表中的值应该是映射最后一层时比较重要的,是一组连续的16进制数据,一共有16个;另外,希望修改的地方尽量少),于是,从最底层得到的数据开始,修改映射表的具体值。
然后,修改XllpScanCodeToWinCeScanCodeTable(通过ScanCode_List检索到的值会作为它的索引来使用),在这个表中检索到的数据对应了UniqueKeyScanCodeToVKeyTable中所有值(16个)。
最后,修改MARKER_VK_MAP结构的markerVkMapping表,在这个表里,会最终找到系统使用的虚拟码,比如说:如果你按了‘0’这个键,返回给系统0x3048)这个值。
如果你的键盘是4*4的,那么通过以上修改,应该就OK
但板子上有18个按键(其中一个按下以后,寄存器没有值,忽略不计,那么就是17个),如何在16个的map中对应呢?最后,使用了不怎么好的方法,但这是能想到的唯一方法,如果谁有更好的建议,不防提出来看看。
把除了XllpScanCodeToWinCeScanCodeTable以外的上层映射表容量加1个、添加一个需要的值,这样,就会出现17个映射了,只是需要修改一些与表的容量相关的宏定义就可以。

[小结]通过以上的修改,新的键盘已经可以正常使用了,但是这个是在英文(默认的)环境中使用,不适合多语言的键盘,至少目前看来是这样的,我们添加了多语言的支持后,发现键盘映射好像完全没有作用,在上层的测试程序中没有得到任何虚拟码。对于多语言的对应以后再好好研究,谁有什么好的建议不妨将将看。

    推荐阅读