主板的键盘有一块专用的接口芯片,一般是采用一块单片微处理器8042(现在大多已集成在南桥或SIO里)。它控制整个键盘的工作,包括加电自检、键盘扫描码的缓冲以及与主板的通讯。
两个重要的中断:
INT 09H是H/W中断,对应IRQ1,INT 16H是一个S/W中断。当键盘的一个键被按下时,键盘接口芯片根据被按下的位置,INT 09H负责把键值转换成INT16H认识的值,返回给INT 16H。INT 16H再把该值根据OS所选定的不同语系键盘而转换成相应的二进制字符传给OS或应用程序。当用户敲击键盘速度过快,使主CPU来不及处理时,则先将所键入的内容送往住存储器的键盘缓冲区,等CPU能处理时,便从缓冲区中取出,送入CPU进行分析和执行。一般在PC机的内存中安排了大约20个字符的键盘缓冲区。
主板的键盘有一块专用的接口芯片,一般是采用一块单片微处理器8042(现在大多已集成在南桥或SIO里)。它控制整个键盘的工作,包括加电自检、键盘扫描码的缓冲以及与主板的通讯。
(Award Code ,In file ATORGS.ASM, INT 09h( KBDINT_VECT JMP KBC_INT<at AKBRD.ASM> ) and INT 16h(KBD_VECT JMP keyboard) )
对缓冲和命令的处理:
8042分输入缓冲和输出缓冲,它的数据传输在I/O口60H和64H进行。基本上,I/O 64H是命令和状态口,I/O 60H是数据口,它们同时可做读写动作,在读和写时有着不同的意义。I/O 64H的bit 0、1置位分别代表输出/输入缓冲满。如果发现输入缓冲满(即判断出I/O 64H[1]=1),要从I/O 60H将数据读完。BIOS在自检时如果确定输入/输出缓冲都没有问题,会发“AAH”给I/O 64H,让它自测试。等到输入缓冲空(说明上一个命令已执行完),输出缓冲满(KB控制器对自测试命令有反应),再读I/O 60H是否为“55H”(IBM PC/AT规范)。如果是,则表示KB没有问题,若等不到输出缓冲满,说明有问题。
在写命令之前,必须对I/O 64H口送一个60H的值,并等到输入缓冲空,再操作I/O 60H。同样,在读状态之前,也必须对I/O 64H口送一个20H的值,并等到输出缓冲满(表示有状态输出),再操作I/O 60H。这时,我们可以把64H看作索引口,而60H看作数据口。
A20地址线的切换:
键盘接口芯片除了接受来自键盘的信息外,还要负责A20地址线的切换,因为当CPU从实模式切换到保护模式时便是通过A20地址线的切换完成的。平常A20为“0”时,CPU工作于DOS的实模式;当A20切换为“1”时,便可进入保护模式。但由于键盘接口芯片切换A20地址线的速度不够快,目前多由主板上的芯片组以模拟方式取代,这样也就省去了一块键盘接口芯片。
8042 端口的操作:
通过8042芯片,可以:
1. 向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
2.读取Status Register的内容(通过64h);
3.向8048发布命令(通过60h);
4.读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
64h端口(读操作)
对64h端口进行读操作,会读取Status Register的内容。
in al, 0x64
执行这个指令之后,AL寄存器中存放的就是Status Register的内容。
64h端口(写操作)
向64h端口写入的字节,被认为是对8042芯片发布的命令(Command): 写入的字节将会被存放在Input Register中; 同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;9 J; |9 l0 @; H. S* g
在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。" {/ }9 l: p' t G2 _
计匠网论坛/ A% W- C a' `
60h端口(读操作)
对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是: . 来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。 . 通过64h端口对8042发布的命令的返回结果。www.ufoit.com: j: v: u1 c3 ]/ o
在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)
60h端口(写操作)% b9 N5 /# B' I# s2 I7 L( s) ^- e
向60h端口写入的字节,有两种可能: 1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据; 2.否则,此字节被认为是发送给8048的命令。 在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
R_ALT E0,38 E0,B8
UP ARROW E0,48 E0,C8
PG UP E0,49 E0,C9
R ARROW E0,4D E0,CD
D ARROW E0,50 E0,D0
PG DN E0,51 E0,D1
INSERT E0,52 E0,D2
DELETE E0,53 E0,D3
R GUI E0,5C E0,DC
APPS E0,5D E0,DD
PRNT SCRN E0,2A, E0,37 E0,B7, E0,AA
PAUSE E1,1D,45 E1,9D,C5 -NONE
这里说几句对驱动没有帮助的题外话,记不清是由于先有了关于 Scan Code 的值的猜测,才去按这个顺序列 Scan Code ,还是先这样列 Scan Code ,才有了关于 Scan Code 的值的猜测。总之,用这个 Make Code 的顺序,和我们现在键盘上键的布局做对照,我们大致就能猜到为什么 A 键的 Make Code 值为 0x1e,为什么 H 键的 Make Code 值为 0x23。我们拿其中的一小段举例子,A 1E,S 1F,D 20,F 21,G 22,H 23,看看键盘上 A,S,D,F,G,H 的位置吧。能感觉到些什么吧,感觉不到就算了,这个和驱动是无关的。从 Scan Code Set 1,可能还能推测出来最早的键盘的样子。以及发生在键盘上的一些变化。我们注意到 F10 和 F11,F12 的 Make Code 不是连在一起的,估计比较早的键盘只有10个功能键,而不是现在的12个功能键。从键的 Make Code 来看,有可能曾经使用的一些键,现在已经不出现在键盘上了。
Status Register(状态寄存器)
Bit6: RCV-TMOUT(R_T): 接收超时,置1
Bit5: TRANS_TMOUT(T_T): 发送超时,置1
Bit4: KYBD_INH(K_I): 为1,键盘没有被禁止。为0,键盘被禁止。
Bit3: CMD_DATA(C_D): 为1,输入缓冲器中的内容为命令,为0,输入缓冲器中的内容为数据。
Bit2: SYS_FLAG(S_F): 系统标志,加电启动置0,自检通过后置1
Bit1: INPUT_BUF_FULL(I_B_F): 输入缓冲器满置1,i8042 取走后置0
BitO: OUT_BUF_FULL(O_B_F): 输出缓冲器满置1,CPU读取后置0
Output Buffer(输出缓冲器)
Input Buffer(输入缓冲器)
Control Register(控制寄存器)
Bit6: 将第二套扫描码翻译为第一套
Bit5: 置1,禁止鼠标
Bit4: 置1,禁止键盘
Bit3: 置1,忽略状态寄存器中的 Bit4
Bit2: 设置状态寄存器中的 Bit2
Bit1: 置1,enable 鼠标中断
BitO: 置1,enable 键盘中断
驱动中把 0x64 叫命令端口
1.5.1 发给i8042的命令
准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。
D2h
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。
1.5.2 发给8048的命令
设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
选择Scan code set。Keyboard系统共可能有3个Scan code set。当Keyboard收到此命令后,将回复一个ACK,然后等待一个来自于60h端口的Scan code set代码。系统必须在此命令之后发送给Keyboard一个Scan code set代码。当Keyboard收到此代码后,将再次回复一个ACK,然后将Scan code set设置为收到的Scan code set代码所要求的。
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
1.5.3 读到的数据
00h/FFh
当击键或释放键时检测到错误时,则在Output Bufer后放入此字节,如果Output Buffer已满,则会将Output Buffer的最后一个字节替代为此字节。使用Scan code set 1时使用00h,Scan code 2和Scan Code 3使用FFh。
BAT完成代码。如果键盘检测成功,则会将此字节发送到8042 Output Register中。
Echo响应。Keyboard使用EEh响应从60h发来的Echo请求。
在Scan code set 2和Scan code set 3中,被用作Break Code的前缀。
ACK。当Keyboard任何时候收到一个来自于60h端口的合法命令或合法数据之后,都回复一个FAh。
BAT失败代码。如果键盘检测失败,则会将此字节发送到8042 Output Register中。
Resend。当Keyboard任何时候收到一个来自于60h端口的非法命令或非法数据之后,或者数据的奇偶交验错误,都回复一个FEh,要求系统重新发送相关命令或数据。
当键盘收到一个来自于60h的F2h命令之后,会依次回复83h,ABh。83AB是键盘的ID。
除了上述那些特殊字节以外,剩下的都是Scan code。