SmlOS七-PS2鼠标键盘功能支持
我们前面已经进行了鼠标键盘中断相关的设置,但是这还不够。
在对键盘和鼠标操作之前,需要激活键盘控制器,它们负责于鼠标和键盘通信,不开启它们,我们无法收到鼠标键盘的中断信号。
i8042 键盘控制器介绍
intel 8042 芯片,位于主板上,CPU 通过 IO 端口直接和这个芯片通信,获得按键的扫描码或者发送各种键盘命令。
键盘控制器是外部设备,需要使用OUT指令进行初始化,与之前的外部设备操作类似。
//端口常量
#define PORT_KEYDAT 0x0060 // i8042的数据端口号
#define PORT_KEYSTA 0x0064 // i8042的状态端口号
#define KEYSTA_SEND_NOTREADY 0x02 // 用来判断i8042的输入缓冲区是否满
#define KEYCMD_WRITE_MODE 0x60 // 发送给i8042的命令 下面有详细解释
#define KBC_MODE 0x47 // 将被设置为i8042的控制寄存器的值
//初始化键盘控制电路
void Init_Keyboard(void)
{
//等待i8042的输入缓冲区清空
wait_KBC_sendready();
//该命令表示准备写入i8042的控制寄存器
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
//等待i8042的输入缓冲区清空
wait_KBC_sendready();
//允许鼠标中断和键盘中断
io_out8(PORT_KEYDAT, KBC_MODE);
return;
}
激活完控制器之后,就可以收到鼠标键盘中断。
我们需要对鼠标键盘数据的解析。
键盘数据的解析只是接受到一个字节的内容,在中断程序里存入fifo缓冲区后立即退出,比较简单。
而鼠标数据的解析,则略微复杂,这里讲解下鼠标数据的解析。
一次鼠标操作会产生三个中断,分别是:
- 鼠标的按键信息
-
鼠标移动的横坐标偏移
-
鼠标移动的纵坐标偏移
我们用了一个结构体存放鼠标中断产生的信息:
// 鼠标缓冲区结构
struct MOUSE_DEC
{
unsigned char buf[3], phase;
int x, y, btn;
};
这里解释下鼠标数据 第横纵坐标的解析。
在mdec鼠标描述结构体中,mdec->x,mdec->y中放的是补码
补码知识点回顾:
补码的表示方法是:
正数的补码就是其本身
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
我们通过不同阶段的判断把相应信息,填入了MOUSE_DEC结构体
解析核心代码如下:
/* 接收鼠标数据 */
int Mouse_Decode(struct MOUSE_DEC *mdec, unsigned char dat)
{
if (mdec->phase == 0)
{
// 等待鼠标的0xfa阶段
if (dat == 0xfa)
{
mdec->phase = 1;
}
return 0;
}
if (mdec->phase == 1)
{
// 等待鼠标的第一字节阶段
if ((dat & 0xc8) == 0x08)
{
mdec->buf[0] = dat;
mdec->phase = 2;
}
return 0;
}
if (mdec->phase == 2)
{
// 等待鼠标的第二字节阶段
mdec->buf[1] = dat;
mdec->phase = 3;
return 0;
}
if (mdec->phase == 3)
{
// 等待鼠标的第三字节阶段
mdec->buf[2] = dat;
mdec->phase = 1;
// 取BYTE1的低3位 按键状态
mdec->btn = mdec->buf[0] & 0x07;
// 保存x,y的位移
mdec->x = mdec->buf[1];
mdec->y = mdec->buf[2];
// 判断x的符号位
if ((mdec->buf[0] & 0x10) != 0)
{
mdec->x |= 0xffffff00;
}
// 判断y的符号位
if ((mdec->buf[0] & 0x20) != 0)
{
mdec->y |= 0xffffff00;
}
// 鼠标的y方向与画面符号相反
mdec->y = - mdec->y;
return 1;
}
return -1;
}
发表评论
要发表评论,您必须先登录。