Appearance
day7FIFO与鼠标控制
获取按键编码
c
#define PORT_KEYDAT 0x0060
void inthandler21(int *esp)
{
//初始化相关的数据
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
unsigned char data, s[4];
io_out8(PIC0_OCW2, 0x61); /* IRQ-01的PIC已经受理完毕 */
data = io_in8(PORT_KEYDAT); //获取键盘的返回值
sprintf(s, "%02X", data);
//对获取的键盘的值进行打印
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 0, 16, 15, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 16, COL8_FFFFFF, s);
return;
}
在告诉收到信号的时候, 实际输出的是'0x60 + IRQ号码', 执行之后PIC会继续进行检测
把处理函数放在中断函数之外
c
struct KEYBUF {
unsigned char data, flag;
};
struct KEYBUF keybuf;
void inthandler21(int *esp)
{
unsigned char data;
io_out8(PIC0_OCW2, 0x61); /* 清空中断标志位 */
data = io_in8(PORT_KEYDAT);
if (keybuf.flag == 0) {
keybuf.data = data;
keybuf.flag = 1;
}
return;
}
c
for (;;) {
io_cli();
if (keybuf.flag == 0) {
io_stihlt();
} else {
i = keybuf.data;
keybuf.flag = 0;
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);
}
}
修改main函数
io_stihlt();这里使用这个函数是因为如果在sti函数之后发生中断数据就会存入, 但是没有被察觉到, 如果两个指令在一起CPU会屏蔽中间的中断
这时候的键盘返回的数据如果有两个会被吞掉, 因为一次按键只会产生两个中断, 但是直接收了每一次中断输出的第一个数据, 第二个数据在第二次中断的时候被舍弃了, 因为第二个数据到来的时候第一个数据没有处理完, 这时候会进入睡眠而不是进入再次处理
引入数据结构FIFO
c
/* FIFO */
#include "bootpack.h"
#define FLAGS_OVERRUN 0x0001
void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf)
/* FIFO初始化 */
{
fifo->size = size;
fifo->buf = buf;
fifo->free = size; /* 空き */
fifo->flags = 0;
fifo->p = 0; /* 書き込み位置 */
fifo->q = 0; /* 読み込み位置 */
return;
}
int fifo8_put(struct FIFO8 *fifo, unsigned char data)
/* FIFO放入数据 */
{
if (fifo->free == 0) {
/* 检测是否溢出た */
fifo->flags |= FLAGS_OVERRUN;
return -1;
}
fifo->buf[fifo->p] = data;
fifo->p++;
if (fifo->p == fifo->size) {
fifo->p = 0;
}
fifo->free--;
return 0;
}
int fifo8_get(struct FIFO8 *fifo)
/* FIFO会的一个数据 */
{
int data;
if (fifo->free == fifo->size) {
/* 数组为空返回-1 */
return -1;
}
data = fifo->buf[fifo->q];
fifo->q++;
if (fifo->q == fifo->size) {
fifo->q = 0;
}
fifo->free++;
return data;
}
//存放数据的个数
int fifo8_status(struct FIFO8 *fifo)
{
return fifo->size - fifo->free;
}
鼠标
在初期的时候大多数的操作系统不支持鼠标, 所以鼠标的电路在不被激活的时候
在不激活的时候, 鼠标是不会产生中断的, 需要让鼠标的控制电路以及鼠标本身有效, 鼠标的控制电路包含在键盘的控制电路里面, 键盘的控制电路初始化的时候鼠标的初始化也就完成了
c
#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;
}
在确认可以发送信息之后设置模式的命令是0x60, 使用鼠标的模式是0x47
c
#define KEYCMD_SENDTO_MOUSE 0xd4
#define MOUSECMD_ENABLE 0xf4
void enable_mouse(void)
{
/* 激活鼠标,先对键盘发送0xd4,之后的数据就会发送给鼠标 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
wait_KBC_sendready();
io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);
return; /* 顺利的话的返回ACK(0xfa) */
}
这时候因为会返回一个数值, 所以会直接产生一个中断
对从鼠标获取的数据进行处理
c
struct FIFO8 mousefifo;
void inthandler2c(int *esp)
/* 来自鼠标的中断 */
{
unsigned char data;
io_out8(PIC1_OCW2, 0x64); /* 通知PIC1 IRQ12的中断已经响应 */
io_out8(PIC0_OCW2, 0x62); /* 通知PIC0 IRQ12的中断已经响应 */
data = io_in8(PORT_KEYDAT);
fifo8_put(&mousefifo, data);
return;
}
c
void HariMain(void)
{
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
char s[40], mcursor[256], keybuf[32], mousebuf[128];
int mx, my, i;
init_gdtidt();
init_pic();
io_sti(); /* 初始化结束之后打开中断 */
//初始化两个FIFO
fifo8_init(&keyfifo, 32, keybuf);
fifo8_init(&mousefifo, 128, mousebuf);
io_out8(PIC0_IMR, 0xf9); /* 许可中断 */
io_out8(PIC1_IMR, 0xef); /* 许可中断 */
//初始化键盘
init_keyboard();
//初始化花瓣
init_palette();
init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);
mx = (binfo->scrnx - 16) / 2; /* 画面中央になるように座標計算 */
my = (binfo->scrny - 28 - 16) / 2;
init_mouse_cursor8(mcursor, COL8_008484);
putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);
sprintf(s, "(%d, %d)", mx, my);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);
//初始化鼠标
enable_mouse();
for (;;) {
io_cli();//关闭中断
if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {
//没有数据打开中断进入睡眠
io_stihlt();
} else {
if (fifo8_status(&keyfifo) != 0) {
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);
} else if (fifo8_status(&mousefifo) != 0) {
i = fifo8_get(&mousefifo);
io_sti();
sprintf(s, "%02X", i);
boxfill8(binfo->vram, binfo->scrnx, COL8_008484, 32, 16, 47, 31);
putfonts8_asc(binfo->vram, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
}
}
}
}