PS2键盘鼠标驱动开发文档
-------以及USB的HID keyboard/mouse验证
目录索引:
二. PS2鼠标驱动的软件层次.
三. USB的HID keyboard/mouse验证.
一. PS2键盘鼠标驱动的硬件相关部分.
文件: linux-
同类参照文件: linux-
基于w83977的键盘及鼠标设备,是完全与标准的8042键盘兼容的,因此本驱动基本直接从8042的标准驱动pc_keyb.c来进行修改,当中须要修改的地方相当的少,主要集中如下几点:
1. 中断的设置.
edb9302_enable_eint1()
ü 键盘的中断为EGPIO[0].
ü 鼠标的中断为EGPIO[3].
有关这一部分,也是必须进行相关改动的地方,主要是配置w83977的设备以及设备GPIO中断等,在这相关设备的初始化函数当中调用,主要包括如下几个简单的函数:
此处须要修改的地方如下:
[1]. pckbd_init_hw函数当中加入如下键盘GPIO中断设置函数:
// houhh 20070809, init the keyboard gpio int...
w83697uart_set_gpio(GPIO_INT_A, GPIO_KEYB_BITPOS);
[2]. psaux_init函数的mouse中断设备及w83977内部中部设备:
// houhh 20070809...
w83697uart_set_gpio(GPIO_INT_A, GPIO_MOUSE_BITPOS);
w83977mouse_set();
2. 键盘设备的读写, 其读写具体定义如下,与具体的平台相台,在w883977当中键盘的I/O定义如下:
#define EDB9302_VIRT_8042 IO_BASE83977_VIRT
#define kbd_read_input() __raw_readb(EDB9302_VIRT_8042 + 0x60)
#define kbd_read_status() __raw_readb(EDB9302_VIRT_8042 + 0x64)
#define kbd_write_output(val) __raw_writeb(val, EDB9302_VIRT_8042 + 0x60)
#define kbd_write_command(val) __raw_writeb(val, EDB9302_VIRT_8042 + 0x64)
#define kbd_request_irq(handler) request_irq(IRQ_GPIO, handler, SA_SHIRQ, \
"keyboard", "kbd"); \
edb9302_enable_eint1(1);
此处须要修改的地方如下:
[1]. 键盘与鼠标数据读写均建立在此四个宏之基础上,其实是两个宏, 这其实是本驱动中修改最多的部分了J,构成与底层硬件通信的最基础.
[2]. edb9302_enable_eint1(1) 是打开设备相应的GPIO中断位使能, 也是必须修改成与自己设备相关的部分.
3. 中断处理
须要修改的地方基本已经在前面的1/2点中指出来了, 一共是四处修改,此时即已经完成了驱动,下面具体了解一下有关中断的处理:
keyboard_interrupt()是中断处理程序,虽然他的名字叫做keyboard什么的,但是其实它是键盘与鼠标两个中断的入口,因为他们俩共用一个系统中断向量. 叫断到来时根据不同的GPIO位来判断应该处理什么中断,但实际上处理时是根据读写具体设备的相关状态是判断处理的,具体如下处理在handle_kbd_event()函数当中:
static unsigned char handle_kbd_event(void)
{
…
{
if (status & KBD_STAT_MOUSE_OBF)
handle_mouse_event(scancode);
else
handle_keyboard_event(scancode);
}
status = kbd_read_status();
}
if (!work)
printk(KERN_ERR "pc_keyb: controller jammed (0x%02X).\n", status);
return status;
}
根据硬件寄存器读取的状态,进行区别是应该处理什么中断, 具体的硬件寄存器的状态可以参见手册,这里因为没作任何修改,因此不进行说明了, 至于具体的中断内部的处理流程参看源码.
二. PS2鼠标驱动的软件层次.
1. 键盘设备初始化部分.
void __init pckbd_init_hw(void)
这个初始化的调用者有必要指出来,请看keyboard.h文件中有如下定义:
#define kbd_setkeycode pckbd_setkeycode
#define kbd_getkeycode pckbd_getkeycode
#define kbd_translate pckbd_translate
#define kbd_unexpected_up pckbd_unexpected_up
#define kbd_leds pckbd_leds
#define kbd_init_hw pckbd_init_hw
#define kbd_sysrq_xlate pckbd_sysrq_xlate
kbd_init_hw调用者是上一层的键盘共用部分代码kbd_init, 该函数位于 keyboard.c文件, 调用层次关系如下
chr_dev_init()àtty_init()àkdb_init()àkbd_init_hw();
__initcall(chr_dev_init); 为__initcall机制,在系统初始化完成后调用.
在此函数的调用中,完成键盘硬件的初始化以及检测配置等,最后就是安装键盘中断处理程序,键盘中断使能.
另外如果已经打开了鼠标支持选项, 则还会调用mouse初始化程序.
#if defined CONFIG_W83977_PSMOUSE
psaux_init();
#endif
2. 鼠标设备初始化部分.
上面已经提到了鼠标设备如果打开了,则是在键盘设备当中附带初始化的,鼠标设备与键盘初始化时有个不同的地方,那就是要建立一个设备节点如下:
static struct miscdevice psaux_mouse = {
PSMOUSE_MINOR, "psaux", &psaux_fops
};
if ((retval = misc_register(&psaux_mouse)))
return retval;
MISC类型为杂类设备,其主设备号为10, 因此这个ps2 mouse的设备节点为/dev/psaux, 主设备号为10, 次设备号为1; 这里应该讲讲为何键盘设备没有设备节点了,这也是开始时我比较困惑的问题,但经实际源码的分析,得知键盘设备其实就是针对当前终端的,在一开始初始化时就已经完成硬件设备初始化,也挂上了中断服务程序并打开了中断,而且在键盘输入时,直接就是针对当前的TTY设备, 因此键盘设备并不须要一个设备节点来打开它,如果你要读取键盘设备的数据,其实就是读取当前终端即可,这一点要弄清楚.
既然有moues设备节点,那就有打开设备以及打开设备号的相应文件操作,具体在如下定义,关于每一项并不做具体说明,可能见源码.
struct file_operations psaux_fops = {
read: read_aux,
write: write_aux,
poll: aux_poll,
open: open_aux,
release: release_aux,
fasync: fasync_aux,
};
3. 键盘数据的接收.
刚才在上面也讲到了键盘数据没有对应文件结构,并不是通过普通的文件读写操作来处理的,那么他具体是如何处理键盘接收的?现在进一点来看keyboard.c这个公用部分的键盘数据接收机制:
首先列出具体的键盘中断的处理代码,我们将分两部分来讲解以下三个问题:
[1]. 按下弹起这个过程是如何接收的?
[2]. 重复键盘是如何实现的?
[3]. 键盘功能灯是如何处理的?
static inline void handle_keyboard_event(unsigned char scancode)
{
#ifdef CONFIG_VT
kbd_exists = 1;
if (do_acknowledge(scancode))
handle_scancode(scancode, !(scancode & 0x80));
#endif
tasklet_schedule(&keyboard_tasklet);
}
带着如上的三个问题,来看上述的中断处理,结论如下:
1. handle_scancode()带这个公共部分负责完成一次按下与弹起的工作,将键盘最终通过调用put_queue(scancode);来将按键交给当前终端缓冲区, 查看这个函数的代码,我们会发觉与串口的处理相当类似,也是首先将中断中收到的数据插入一个flip缓冲区,然后再启动终端的一个tasklet来完成缓冲区数据的取走加工,这当然是异步的.
void put_queue(int ch)
{
if (tty) {
tty_insert_flip_char(tty, ch, 0);
con_schedule_flip(tty);
}
}
2. 对于后面的两个问题,其实是一并处理的,用的机制当然也是我们已经反复提到的tasklet机制,如果对这个机制还不太了解,可以参考” UART串口驱动开发文档.doc”驱动一文件中的详细关于“软中断的机制的原理介绍”, 至此我应该可以深刻的体会软中断做为一种异步机制,在内核应用广泛程度了!
处理键盘按键不放,以及键盘功能灯的bh函数为static void kbd_bh(unsigned long dummy), 这个函数的具体代码不详细贴出,它完成的工作如下:
[1]. 调用kbd_processkeycode(kbd_repeatkeycode, 0, 1), 以完成须要处理重复按键产生的情形.
[2] 处理当前终端变化的情况, 如果终端变化后才按键数据送向新的终端.
[3]. 如果键盘功能灯的状态有变,即进行响应, 如此软件即可以设置功能灯的状态了.
三. USB的HID keyboard/mouse验证.
这个驱证在驱动方面没有任何的代码修改,主要涉及到两个方面:
1. 参照DG930x-linux下面的readme.txt来打开USB模块,以及打开Input core模块,并打开键盘鼠标设备的支持,这在readme文档中已经有详细的说明了.
2. 参照minigui的配置文档MiniGUI.cfg的说明,打开输入设备的配置.
[1]. USB MOUSE配制:
# IAL engine
ial_engine=console
#ial_engine=dummy
mdev=/dev/input/mice
mtype=IMPS2
[2]. PS2 MOUSE配制:
# IAL engine
ial_engine=console
#ial_engine=dummy
mdev=/dev/psaux
mtype=IMPS2
3. 参照建立mouse的usb设备节点名/dev/input/mice.
4. 编译minigui时,如果要移动窗体必须打开可移动窗体的配制选项, 这此配置在提交的minigui当中已经全部修改完成,可以参照配置文件buildlib-ep9302.
没有评论:
发表评论