30天自制操作系统-第七天

来源:互联网 发布:用友软件官网 编辑:程序博客网 时间:2024/05/17 03:33
FIFO与鼠标控制
        学习目标:1、获取按键编码,以及加快中断处理;2、制作FIFO缓冲区;3、改善FIFO缓冲区;4、整理FIFO缓冲区;5、从鼠标接收数据。
        1、获取按键编码
        将所按键的编码在画面上显示出来,在int.c程序中的inthanddler21函数中添加如下代码:
#define PORT_KEYDAT0x0060 ;//  设备的编号为0x0060
void inthandler21(int *esp){struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;unsigned char data, s[4];io_out8(PIC0_OCW2, 0x61);/* 通知PIC已经知道发生中断的是IRQ-01中断*/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;}
       中断处理,基本上市打断CPU本来的工作,所以必须完成得干净利索。而且中断处理期间,不再接受别的中断,所以如果中断程序太长,处理会比较慢,就会出现鼠标的运动不连贯、不能从网上接受数据得情况。
        另一方面,字符显示要花大量时间处理,对于重复的字符,可以查看其标志位来。
struct KEYBUF keybuf;void inthandler21(int *esp){unsigned char data;io_out8(PIC0_OCW2, 0x61);/* IRQ-01庴晅姰椆傪PIC偵捠抦 */data = io_in8(PORT_KEYDAT);if (keybuf.flag == 0) {keybuf.data = data;keybuf.flag = 1;}return;}

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);}}
         键盘控制器(设备号码0x0060)是在“想去厕所,快忍不住了”(=品比中断的情况下),等待着程序处理。但是这对于硬件来讲,实在有点太勉为其难了。在这里还
struct KEYBUF {unsigned char data[32];int next;};#define PORT_KEYDAT0x0060struct KEYBUF keybuf;void inthandler21(int *esp){unsigned char data;io_out8(PIC0_OCW2, 0x61);/* IRQ-01庴晅姰椆傪PIC偵捠抦 */data = io_in8(PORT_KEYDAT);if (keybuf.next < 32) {keybuf.data[keybuf.next] = data;keybuf.next++;}return;}

得修改一下程序,让它再聪明点。
        2、制作FIFO缓冲区
         
struct KEYBUF {unsigned char data[32];int next;};struct KEYBUF keybuf;void inthandler21(int *esp){unsigned char data;io_out8(PIC0_OCW2, 0x61);/* IRQ-01庴晅姰椆傪PIC偵捠抦 */data = io_in8(PORT_KEYDAT);if (keybuf.next < 32) {keybuf.data[keybuf.next] = data;keybuf.next++;}return;}

for (;;) {    io_cli();    if (keybuf.next == 0)    {io_stihlt();    }    else     {i = keybuf.data[0];keybuf.next--;for (j = 0; j < keybuf.next; j++)         {     keybuf.data[j] = keybuf.data[j + 1];}    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);    }}
      3、改善FIFO缓冲区
struct KEYBUF keybuf;struct KEYBUF {unsigned char data[32];int next_r, next_w, len;};void inthandler21(int *esp){unsigned char data;io_out8(PIC0_OCW2, 0x61);/* IRQ-01庴晅姰椆傪PIC偵捠抦 */data = io_in8(PORT_KEYDAT);if (keybuf.len < 32) {keybuf.data[keybuf.next_w] = data;keybuf.len++;keybuf.next_w++;if (keybuf.next_w == 32) {keybuf.next_w = 0;}}return;}
        
for (;;) {    io_cli();    if (keybuf.len == 0) {io_stihlt();    } else {    i = keybuf.data[keybuf.next_r];    keybuf.len--;    keybuf.next_r++;    if (keybuf.next_r == 32)     {keybuf.next_r = 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);    }}
        4、整理FIFO缓冲区
struct FIFO8 {unsigned char *buf;int p, q, size, free, flags;//缓冲区大小保存在变量size里;free用于保///存缓冲区没有字节的数量;p代表下一数据写入的地址;q代表下一数据要读出的地址};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;}
          5、从鼠标接收数据
       虽然主板上做了鼠标用的电路,但只要不执行激活鼠标的指令,就不产生鼠标的中断信号。所谓鼠标的中断信号:(1)控制电路不向CPU发出中断;(2)鼠标也不向控制电路报告任何信息。
       我们必须发行指令,让下面两个装置有效,一个是鼠标控制电路,一个是鼠标本身。通过上面的说明,大家应该已经明白了,要先让鼠标控制电路有效。如果先让鼠标有效了,那时控制电路还没准备好数据就来了,可就麻烦了,因为控制电路还处理不了。
       现在来说说控制电路的设定。事实上,鼠标控制电路包含在键盘控制电路里,如果键盘控制电路的初始化正常完成,鼠标电路控制器的激活也就完成了。
       
#define PORT_KEYDAT0x0060#define PORT_KEYSTA0x0064#define PORT_KEYCMD0x0064#define KEYSTA_SEND_NOTREADY0x02#define KEYCMD_WRITE_MODE0x60#define KBC_MODE0x47void 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_MOUSE0xd4#define MOUSECMD_ENABLE0xf4void 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)偑憲怣偝傟偰偔傞 */}
        这个函数与init_keyboard函数非常相似。不同点仅在于写入的数据不同。如果往键盘控制电路发送指令0xd4,下一个数据就会自动发送给鼠标。我们根据这一特性来发送激活鼠标的指令。
        既然中断已经来了,现在就让我们取出中断数据。前面已经说,鼠标和键盘的原理几乎相同,所以程序非常相似。
        
struct FIFO8 mousefifo;void inthandler2c(int *esp)/* PS/2儅僂僗偐傜偺妱傝崬傒 */{unsigned char data;io_out8(PIC1_OCW2, 0x64);/* IRQ-12庴晅姰椆傪PIC1偵捠抦 */io_out8(PIC0_OCW2, 0x62);/* IRQ-02庴晅姰椆傪PIC0偵捠抦 */data = io_in8(PORT_KEYDAT);fifo8_put(&mousefifo, data);return;}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);}    }}