6 总算讲到鼠标了(harib04f)
现在到了让大家期待已久的讲解鼠标的时间了。首先说一说,为什么虽然我们的电脑连着有鼠标,却一直不能用的原因。
从计算机不算短暂的历史来看,鼠标这种装置属于新兴一族。早期的计算机一般都不配置鼠标。一个很明显的证据就是,现在我们要讲的分配给鼠标的中断号码,是IRQ12,这已经是一个很大的数字了。与键盘的IRQ1比起来,那可差了好多代了。
所以,当鼠标刚刚作为计算机的一个外部设备开始使用的时候,几乎所有的操作系统都不支持它。在这种情况下,如果只是稍微动一动鼠标就产生中断的话,那在使用那些操作系统的时候,就只好先把鼠标拔掉了。IBM的大叔们认为,这对于使用计算机的人来说是很不方便的。所以,虽然在主板上做了鼠标用的电路,但只要不执行激活鼠标的指令,就不产生鼠标的中断信号(1)。
所谓不产生中断信号,也就是说,即使从鼠标传来了数据,CPU也不会接收。这样的话,鼠标也就没必要送数据了,否则倒会引起电路的混乱。所以,处于初期状态的鼠标,不管是滑动操作也好,点击操作也好,都没有反应(2)。
总而言之,我们必须发行指令,让下面两个装置有效,一个是鼠标控制电路,一个是鼠标本身。通过上面的说明,大家应该已经明白了,要先让鼠标控制电路有效。如果先让鼠标有效了,那时控制电路还没准备好数据就来了,可就麻烦了,因为控制电路还处理不了。
■■■■■
现在来说说控制电路的设定。事实上,鼠标控制电路包含在键盘控制电路里,如果键盘控制电路的初始化正常完成,鼠标电路控制器的激活也就完成了。
bootpack.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; }
首先我们来看函数wait_KBC_sendready。它的作用是,让键盘控制电路(keyboard controller, KBC)做好准备动作,等待控制指令的到来。为什么要做这个工作呢?是因为虽然CPU的电路很快,但键盘控制电路却没有那么快。如果CPU不顾设备接收数据的能力,只是一个劲儿地发指令的话,有些指令会得不到执行,从而导致错误的结果。如果键盘控制电路可以接受CPU指令了,CPU从设备号码0x0064处所读取的数据的倒数第二位(从低位开始数的第二位)应该是0。在确认到这一位是0之前,程序一直通过for语句循环查询。
break语句是从for循环中强制退出的语句。退出以后,只有return语句在那里等待执行,所以,把这里的break语句换写成return语句,结果一样。
下面看函数init_keyboard。它所要完成的工作很简单,也就是一边确认可否往键盘控制电路传送信息,一边发送模式设定指令,指令中包含着要设定为何种模式。模式设定的指令是0x60,利用鼠标模式的模式号码是0x47,当然这些数值必须通过调查才能知道。我们可以从老地方得到这些数据。
这样,如果在HariMain函数调用init_keyboard函数,鼠标控制电路的准备就完成了。
■■■■■
现在,我们开始发送激活鼠标的指令。所谓发送鼠标激活指令,归根到底还是要向键盘控制器发送指令。
bootpack.c节选
#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)*/ }
这个函数与init_keyboard函数非常相似。不同点仅在于写入的数据不同。如果往键盘控制电路发送指令0xd4,下一个数据就会自动发送给鼠标。我们根据这一特性来发送激活鼠标的指令。
另一方面,一直等着机会露脸的鼠标先生,收到激活指令以后,马上就给CPU发送答复信息:“OK,从现在开始就要不停地发送鼠标信息了,拜托了。”这个答复信息就是0xfa。
因为这个数据马上就跟着来了,即使我们保持鼠标完全不动,也一定会产生一个鼠标中断。
■■■■■
所以,我们将enable_mouse也做成了从HariMain中调用的形式。好,我们马上测试一下。运行“make run”。
鼠标中断终于出来了。这可是很了不起的进步哟。