30天自制操作系统-第07天-FIFO与鼠标控制
1.鼠标按键编码(/07_day/hrib04a)
1)中断处理函数:
#define PORT_KEYDAT 0x0060
void inthandler21(void)
{
......
unsigned s[4];
io_out8(PIC0_OCW2,0x61);/*通知PIC IRQ_01以及受理完毕 0x60 + IRQ号*/
data = io_in8(PORT_KEYDAT); //读取键盘编码 端口0x60
sprintf(s,"%02X",data);//格式化键盘编码为16进制串
putfonts8_asc(binfo->vram,binfo->scrnx,0,16,COL8_FFFFFF,s);//显示键盘编码16进制
}
注意:读出的是扫描码
2)HariMain函数片段:
{
......
for (;;) {
io_cli();
if (keybuf.flag == 0) {
io_stihlt();/*sti,hlt 这两条指令之间的中断不受理*/
} 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);
}
}
}
2. 完善FIFO队列(07_day/harib04e/fifo.c)
使用一个先进先出的队列记录数据(键盘或鼠标以及其他设备产生的),加快处理速度
1)队列结构定义
struct FIFO8 { unsigned char *buf; int p, q, size, free, flags; };
2)队列初始化
void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf)
{
fifo->size = size;
fifo->buf = buf;
fifo->free = size; /* 缓冲区大小 */
fifo->flags = 0;
fifo->p = 0; /* 下一个数据写入位置*/
fifo->q = 0; /* 下一个数据读出位置*/
}
3)写队列函数
int fifo8_put(struct FIFO8 *fifo, unsigned char data)
{
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;
}
4)读队列函数
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;
}
5)队列状态函数
int fifo8_status(struct FIFO8 *fifo)
/* 报告一下积攒的数据量, */
{
return fifo->size - fifo->free;
}
3.鼠标初始化
1)鼠标有效
鼠标控制电路(包含在键盘控制电路里),鼠标本身
2)鼠标键盘控制电路准备
void wait_KBC_sendready(void)
{
/* 等待键盘控制电路准备完毕 */
for (;;) {
if ((io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) == 0) {
//从设备号码0x0064处读取数据的倒数第2位为0时,说明键盘控制电路可以接收CPU指令了
break;
}
}
return;
}
3)初始化键盘
void init_keyboard(void)
{
/* 初始化键盘控制电路 */
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE);//设定指令模式为0x60
wait_KBC_sendready();
io_out8(PORT_KEYDAT, KBC_MODE);//设定鼠标模式
return;
}
4)鼠标激活
void enable_mouse(void)
{
/* 激活鼠标*/
wait_KBC_sendready();
io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE);
//向键盘控制电路写入0xd4后,下一个数据就会自动发送给鼠标
wait_KBC_sendready();
io_out8(PORT_KEYDAT, MOUSECMD_ENABLE);//使鼠标能够使用,成功的话向CPU发送一个0xfa作为答复。
return; /*键盘控制其会返回ACK */
}
4.从鼠标接收数据
1)鼠标处理中断
struct FIFO8 mousefifo;
void inthandler2c(int *esp)
/* 来自PS/2鼠标的中断 */
{
unsigned char data;
io_out8(PIC1_OCW2, 0x64); /* 通知PIC IRQ-12 已经受理完毕 */
io_out8(PIC0_OCW2, 0x62); /* 通知PIC IRQ-02 已经受理完毕 */
data = io_in8(PORT_KEYDAT);
fifo8_put(&mousefifo, data);
return;
}
2)鼠标数据接收(与键盘代码一样)
fifo8_init(&mousefifo,128,mousebuf);//鼠标数据量大,队列设置为128字节
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);
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)