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; 
}