1序言
Linux因为其具有内核强悍且稳定,便于扩充和裁减,丰富的硬件支持等众多优点linux按键驱动,在嵌入式系统中得到了广泛的应用。好多嵌入式Linux系统,非常是一些具有与用户强交互的嵌入式系统,常常须要配备一个特殊按键,此时开发者须要依照实际情况,为自己的特殊按键编撰驱动程序。
2Linux按键驱动简介
Linux中的大多数驱动程序都采用了层次型的体系结构,鼠标驱动程序也不例外。在Linux中,鼠标驱动被界定成两层来实现。其中,下层是一个通用的按键具象层,完成按键驱动中不依赖于底层具体硬件的一些功能,但是负责为底层提供服务;上层则是硬件处理层,与具体硬件密切相关,主要负责对硬件进行直接操作。按键驱动程序的下层公共部份都在driver/keyboard.c中。该文件中最重要的就是内核用EXPORT_SYMBOL这个宏导入的handle_scancode函数。handle_scancode完成的功能是:首先将扫描码转换成键码,接着按照shift,alt等扩充键的按下情况将键码转换成目标码,通常情况下是ASCII码,最后将该ASCII码放在终端设备的缓冲区中,但是调度一个tasklet负责将其在显示器上回显下来。可以看出,这个函数完成的是鼠标驱动程序中最核心的一些工作,而这种核心的逻辑功能是不依赖于底层硬件的,所以可以将其独立出来,但是导入给底层的硬件处理函数调用。在这个文件中还定义了其它几个反弹函数,它们由鼠标驱动程序中的下层公共部份调用,并由底层硬件处理函数实现。比如kbd_init_hw,kbd_translate,kbd_unexpected_up等等。其中kbd_translate由handle_scancode调用linux按键驱动,负责将扫描码转换成键码;按键驱动程序的底层硬件处理部份则按照不同的硬件有不同的实现。诸如PC平台上标准按键的底层硬件处理函数都集中在driver/Pc_keyb.c中。这个文件包括了按键中断处理函数keyboard_interrupt,扫描码到键码转换函数pckbd_translate等其他一些与底层硬件密切相关的函数。
在这些体系结构下,要添加一块特殊按键到系统中就变得愈发清晰。开发者只需为其编撰驱动程序中的底层硬件处理函数,就可以将该按键驱动上去。通常说来,底层硬件处理函数中最重要的工作就是在鼠标中断处理中获取被按下键的扫描码,但是以它为参数调用handle_scancode,该扫描码可以自己定义,但它必须惟一地标识出被按下键在鼠标上的位置。据悉,开发者还须要提供对应的从自定义扫描码到键码的转换函数kbd_translate。具体的键码转换,将目标码放在终端的输入缓冲区linux教程下载,以及回显等工作都由handle_scancode负责完成。在此我们也可以看出,内核导入函数handle_scancode在整个按键驱动程序中,起着将下层通用具象层和底层硬件处理层粘和上去的关键作用。
3应用实例
下边我们将以一个具体的应用实例来说明在嵌入式Linux系统中给一个特殊按键编撰驱动程序的具体过程。
3.1硬件模块描述
本系统的建立选用了三星公司的S3C2410开发板作为硬件平台。特殊按键的硬件模块主要由两个SN74hc164芯片和一个4行16列的矩阵扫描电路构成。SN74hc164是一个8位的串形输入并形输出移位寄存器,它的内部由8个D触发器串联而成。其工作原理简单说来是这样的,SN74hc164芯片在时钟CLK脉冲的上升沿将A,B引脚上的串形输入在8个时钟脉冲之后并行输出到输出引脚QA到QH。其真值表见图1所示。
两个SN74hc164芯片先串联后,将它们的CLK引脚和CLR引脚分别接到S3C2410开发板的GPB2和GPB4端口上,而且将第一个SN74hc164芯片的A,B引脚接到开发板的GPB1端口上,这三个GPIO端口配置成输出端口。这样我们就依靠于两个SN74hc164寄存器,实现了只占用3个GPIO端口,给矩阵扫描电路的16列提供输入,因而既节省了成本,又杜绝了GPIO资源的浪费。但这同时也给按键驱动程序的实现带来了一定的麻烦,驱动程序首先要将SN74hc164驱动上去,之后才会对矩阵电路的16列进行控制。该矩阵电路的4个行引脚分别被接到S3C2410的GPG6,GPG7,GPG8,GPG9端口上,但是这四个端口被配置成中断源。无键按下时直接读为高电位,使用时通过SN74hc164芯片先将鼠标的16列置低电位,任何一个键被按下,相应的行GPG端口都会有从高到低的电流跳变,因而触发一次中断。
3.2软件模块描述
初始化部份。这部份包括硬件层和软件层上的初始化。在本例中,须要先对矩阵电路和SN74hc164芯片所使用到的GPIO端口作配置,以使CPU可以对它们进行控制和访问。为了要将某个GPIO端口配置成输入输出或则是中断源,须要在对应的GPIO控制寄存器中设置正确的值,具体的值可以通过查阅S3C2410开发板指南来获得。例如,为了将GPB1设置成SN74hc164的输入端,须要将GPBCON这个控制字中2,3两位设置成二补码的01,为了将GPG6设置成电抬高跳变中断源,须要将GPGCON中12,13两位设置成二补码的10。在完成了硬件初始化操作之后,就是软件层上的初始化了。首先将鼠标中断处理函数注册到系统,之后设置好一个定时器结构,便于在中断发生时将其挂到内核的定时器队列中去,该定时器将触发对按键的扫描操作。最后通过SN74hc164将矩阵电路的16列置零。
中断处理部份。如前所述,这部份软件应当完成的工作就是扫描特殊按键,确定那个键被按下,但是领到稳定的扫描码,之后调用内核导入函数handle_scancode。在这个应用中,该特殊按键的布局与PC标准按键的布局比较相像,所以我们直接将PC鼠标上对应键的系统扫描码作为我们特殊按键上各个键的扫描码,同时我们将PC鼠标驱动程序中扫描码到键码的转换函数pckbd_translate作为我们的kbd_translate函数。
确定哪一个键被按下的算法如下。在中断到来时,我们早已可以按照中断号确定被按下的键在哪一行,我们还须要确定被按下的键在哪一列。因此,我们先给串联的两个SN74hc164芯片送一个CLR讯号,清零,之后送16个1,促使特殊按键的列均为高电位,此时我们在鼠标的行端口读到的都是高电位。在16个时钟脉冲下,给SN74hc164芯片送入1个0和15个1,致使0在每一列上都惟一出现一次,于此同时在鼠标行端口进行扫描。当被按下键所在列置0时,其所在行都会读到一个低电位。使用这些“走0法”,我们就可以确定出按键上那个键被按下了。并且这些简单的扫描算法还不够,由于在这种类型的矩阵扫描鼠标中,键的每次按下和举起就会有10~20ms(这段时间的长短由硬件特点决定)的毛刺晃动存在,如图2所示,所以为了获取稳定的键盘信息,必需要想办法去除这种晃动,能够防止将用户的一次按钮误当成几次按钮来处理。去毛刺的一种常见的方式是在有按键中断抵达时,并不立刻去扫描按键,而是先等待一段时间linux压缩命令,等跳过毛刺晃动之后再去扫描按键,其伪代码如下所示: