上一章的最后,实现了键盘的中断反馈,但是鼠标依然没有反应,所以承上启下,本章要做这么几个事情,(1)将中断接收到的数据,拿到中断外面来处理,以减少中断中的 *** 作,加快程序运行(这边很好理解,不再赘述);(2)建立FIFO缓冲区,以便快速稳定地读写键盘/鼠标的活动数据;(3)键盘控制电路的初始化,并激活鼠标,应用建立的FIFO缓冲区读写鼠标的活动数据;
一 建立FIFO缓冲区 缓冲区是一个队列结构,先进先出,队列长度可以在初始化中自行定义。
这边主要构建了以下几个 *** 作函数:
【1】FIFO缓冲区初始化----fifo8_init:
这个函数用于初始化一个缓冲区结构体,缓冲区的读写采用双指针的控制方法,所以这边用p、q两个指针来指代缓冲区数组下标。 长度可以根据情况自行定义(
void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf)
/* FIFO缓冲区初始化 */
{
fifo->buf = buf; //缓冲数据区
fifo->p = 0; //缓冲区写指针
fifo->q = 0; //缓冲区读指针
fifo->size = size; //缓冲区总长度
fifo->free = size; //缓冲区剩余长度
fifo->flags = 0; //缓冲区溢出标志位
return;
}
【2】FIFO缓冲区写数据----fifo8_put:
int fifo8_put(struct FIFO8 *fifo, unsigned char data)
/* 向FIFO传送数据并保存 */
{
if(fifo->free == 0)
{
/* 如果缓冲区满,则溢出标志位置1,写不进新的数据 */
fifo->flags |= FLAGS_OVERRUN;
return -1;
}
fifo->buf[fifo->p] = data;
fifo->p ++;
fifo->free --;
if(fifo->p == fifo->size)
{
fifo->p = 0;
}
return 0;
}
【3】FIFO缓冲区读数据----fifo8_get:
int fifo8_get(struct FIFO8 *fifo)
/* 从FIFO取一个数据 */
{
int data;
if(fifo->free == fifo->size)
{
/* 如果缓冲区为空,则直接返回,读不到数据 */
return -1;
}
data = fifo->buf[fifo->q];
fifo->q ++;
fifo->free ++;
if(fifo->q == fifo->size)
{
fifo->q = 0;
}
return data;
}
【4】FIFO缓冲区状态查询----fifo8_status:
int fifo8_status(struct FIFO8 *fifo)
/* 查询使用了多少数据 */
{
return fifo->size - fifo->free;
}
有了上面的几个FIFO *** 作函数,就可以在主函数以及中断处分别添加读、写 *** 作:
中断处写FIFO:
void inthandler21(int *esp)
{
unsigned char data;
io_out8(PIC0_OCW2, 0x61); /* 通知PIC,IRQ1受理完成 */
data = io_in8(PORT_KEYDAT);
fifo8_put(&keyfifo, data); /* 将接收到的键盘 *** 作符,写缓冲区 */
return;
}
主函数处读FIFO:
void HariMain(void)
{
//display...
fifo8_init(&keyfifo, 32, keybuf);
for (;;) {
io_cli();
if (fifo8_status(&keyfifo) == 0) {
//缓冲区为空则等待
io_stihlt();
} else {
//读缓冲区一个字节
i = fifo8_get(&keyfifo);
io_sti();
sprintf(s, "%02X", i);
//刷新这一块字符区(若不刷新,则出现字符重叠的情况)
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
//打印键盘 *** 作符
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);
}
}
}
二 鼠标控制
上一章的最后,实现了键盘的中断反馈,但是鼠标依然没有反应,原因在于,主板上虽然做了鼠标用的电路,但只要不执行激活鼠标的指令,就不产生鼠标的中断信号。
鼠标的使用包含两个部分,一个是控制电路的激活,第二个是鼠标 *** 作符的接收。
【1】鼠标的控制电路包含在键盘的控制电路中,鼠标的激活需要键盘控制电路的初始化:
#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(void)
{
/* 等待键盘控制电路准备完毕 */
for (;;) {
if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {
break;
}
}
return;
}
void init_keyboard(void)
{
/* 初始化键盘控制电路 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, KBC_MODE);
return;
}
#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4
void enable_mouse(void)
{
/* 激活鼠标控制 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
return; /* 顺利的话,键盘控制其会返回ACK(0xfa) */
}
【2】鼠标 *** 作符的接收:
与键盘 *** 作相比,鼠标这部分区别不大。
区别在于中断中的处理(这边为了方便对比,把键盘的处理也一并贴出来):
键盘的处理如下:
struct FIFO8 keyfifo;
void inthandler21(int *esp)
{
/* 来自PS/2键盘的中断 */
unsigned char data;
io_out8(PIC0_OCW2, 0x61); /* 通知PIC0 IRQ-01的受理已经完成 */
data = io_in8(PORT_KEYDAT);
fifo8_put(&keyfifo, data);
return;
}
鼠标的处理如下:
struct FIFO8 mousefifo;
void inthandler2c(int *esp)
/* 来自PS/2鼠标的中断 */
{
unsigned char data;
io_out8(PIC1_OCW2, 0x64); /* 通知PIC1 IRQ-12的受理已经完成 */
io_out8(PIC0_OCW2, 0x62); /* 通知PIC0 IRQ-02的受理已经完成 */
data = io_in8(PORT_KEYDAT);
fifo8_put(&mousefifo, data);
return;
}
由上面可以看出,键盘因为是IRQ1中断,只需要通知一次PIC0即可。 然而鼠标是IRQ12中断,IRQ12是由PIC1控制,而PIC1是由PIC0上的IRQ2控制,所以这边需要分别通知
主函数中的处理与键盘没有区别,所以这边不再赘述(设定的键盘缓冲区是32,鼠标缓冲区是128)。
至此,鼠标和键盘的初始化、激活以及 *** 作符的反馈已经完成。
但是目前鼠标的 *** 作符返回的东西看不懂,还不能实际使用,对其的解读下一章会介绍。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)