代码的调试和运行,以及更详细的讲解,请参看视频:
Linux kernel Hacker, 从零构建自己的内核
上一节,我们成功实现了键盘按键的中断响应,本节,我们看如何响应鼠标的中断信号,并做相应处理。
如果大家还记得描述8259A中断控制器那一小节的话,鼠标发送中断信号的数据线在从8259A芯片的IRQ4信号线,因此,为了接收鼠标中断信号,我们在初始化中断控制芯片时,必须启用该信号线,同时,从8259A芯片是通过主8259A的IRQ2信号线连接在一起的,所以,也必须同时启动主8259A芯片的IRQ2信号线,这样,我们在内核中要对init8259A代码段做一些改动:
init8259A:
...
mov al, 11111001b ;允许键盘中断
out 021h, al
call io_delay
mov al, 11101111b ;允许鼠标中断
out 0A1h, al
call io_delay
ret
mov al, 11111001b 这一句指令,启用了主8259A芯片的IRQ1和IRQ2两根信号线,mov al, 11101111b 这句指令启用了从8259A的IRQ4信号线,这根信号线就是用来发送鼠标信号的。
我们上几节说过,只要是外接硬件,要想使用,就得对其进行配置和初始化,就像我们前面看到的,硬件的初始化,一般就是对给定端口发送几个数据而已,鼠标自然也不例外。
鼠标电路的初始化
鼠标电路对应的一个端口是 0x64, 通过读取这个端口的数据来检测鼠标电路的状态,内核会从这个端口读入一个字节的数据,如果该字节的第二个比特位为0,那表明鼠标电路可以接受来自内核的命令,因此,在给鼠标电路发送数据前,内核需要反复从0x64端口读取数据,并检测读到数据的第二个比特位,知道该比特位为0时,才着手发送控制信息,代码如下:
#define PORT_KEYDAT 0x0060
#define PORT_KEYSTA 0x0064
#define PORT_KEYCMD 0x0064
#define KEYSTA_SEND_NOTREADY 0x02
#define KEYCMD_WRITE_MODE 0x60
#define KBC_MODE 0x47
void wait_KBC_sendready() {
for(;;) {
if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {
break;
}
}
}
for循环一直从端口读取数据,然后检测比特位,只有对应比特位是0时,才返回。大家看到,上面代码中,居然有一个端口是 0x60, 你可能会困惑,0x60不是键盘电路的端口吗?没错,鼠标的初始化,就是得通过键盘电路来实现的,当对应比特位为0,也就是鼠标可以接收数据了,这时候,我们就得通过向端口0x60发送数据来配置鼠标:
void init_keyboard(void) {
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
wait_KBC_sendready();