i8042与i8048键盘控制器芯片端口操作总结

主板的键盘有一块专用的接口芯片,一般是采用一块单片微处理器8042(现在大多已集成在南桥或SIO里)。它控制整个键盘的工作,包括加电自检、键盘扫描码的缓冲以及与主板的通讯。

6 a% p0 [8 A0 q0 o9 B* x0 N
两个重要的中断:计匠网论坛" L; }+ _. d1 y9 a" ?* o
INT 09H是H/W中断,对应IRQ1,INT 16H是一个S/W中断。当键盘的一个键被按下时,键盘接口芯片根据被按下的位置,INT 09H负责把键值转换成INT16H认识的值,返回给INT 16H。INT 16H再把该值根据OS所选定的不同语系键盘而转换成相应的二进制字符传给OS或应用程序。当用户敲击键盘速度过快,使主CPU来不及处理时,则先将所键 入的内容送往住存储器的键盘缓冲区,等CPU能处理时,便从缓冲区中取出,送入CPU进行分析和执行。一般在PC机的内存中安排了大约20个字符的键盘缓 冲区。 , O0 I. K3 n2 O4 i# a& z
主板的键盘有一块专用的接口芯片,一般是采用一块单片微处理器8042(现在大多已集成在南桥或SIO里)。它控制整个键盘的工作,包括加电自检、键盘扫描码的缓冲以及与主板的通讯。   D) f, C# Z% t# I
计匠网论坛, D2 M+ N0 c5 P   N
(Award Code ,In file   ATORGS.ASM, INT 09h( KBDINT_VECT   JMP KBC_INT<at AKBRD.ASM> ) and INT 16h(KBD_VECT JMP keyboard) )www.ufoit.com% J; F" ^& B2 f% L! ^2 y

对缓冲和命令的处理:
       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地址线的切换:* o; I2 D- h3 u   |
; t! ~0 E* l5 H2 N
  键盘接口芯片除了接受来自键盘的信息外,还要负责A20地址线的切换,因为当CPU从实模式切换到保护模式时便是通过A20地址线的切换完成的。平常 A20为“0”时,CPU工作于DOS的实模式;当A20切换为“1”时,便可进入保护模式。但由于键盘接口芯片切换A20地址线的速度不够快,目前多由 主板上的芯片组以模拟方式取代,这样也就省去了一块键盘接口芯片。 & Y+ W& S& T" g! ~

8042 端口的操作:

通过8042芯片,可以:
1. 向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
2.读取Status Register的内容(通过64h);
3.向8048发布命令(通过60h);
4.读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。 & x5 ]   z   i. {- D$ P   [
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
- l: [5 z

64h端口(读操作)
       对64h端口进行读操作,会读取Status Register的内容。
     in al, 0x64 计匠网论坛" z( @" P/ A8 }   A4 V) O! o+ o
   执行这个指令之后,AL寄存器中存放的就是Status Register的内容。

64h端口(写操作); ?* {) h8 r& _9 N1 K
    向64h端口写入的字节,被认为是对8042芯片发布的命令(Command): 写入的字节将会被存放在Input Register中; 同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;
计匠网论坛8 G% Z, n% F. G* F
   在向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)。

***********************************************************************************
***********************************************************************************
B5
R_ALT E0,38 E0,B8
HOME E0,47 E0,C7
UP ARROW E0,48 E0,C8
PG UP E0,49 E0,C9
L ARROW E0,4B E0,CB
R ARROW E0,4D E0,CD
END E0,4F E0,CF
D ARROW E0,50 E0,D0
PG DN E0,51 E0,D1
INSERT E0,52 E0,D2
DELETE E0,53 E0,D3
L GUI E0,5B E0,DB
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 来看,有可能曾经使用的一些键,现在已经不出现在键盘上了。

还有一个值得注意的是,如果有 Make Code 为 0x60 的键,那么它的 Break Code 应该为 0x60+0x80=0xE0。那么这个键的 Break Code 将会和 表示扩展码的 0xE0 搞混。不过还好,并没有 Make Code 为 0x60 的键,所以不会发生搞混的情况。
1.4 i8042 键盘控制器
    键盘驱动直接读写 i8042 芯片,通过 i8042 间接的向键盘中的 i8048 发命令。所以对于驱动来说,直接发生联系的只有 i8042 ,因此我们只介绍 i8042 ,不介绍 i8048。
    象 i8042,i8048 这样的芯片,本身就是一个小的处理器,它的内部有自己的处理器,有自己的 Ram,有自己的寄存器,等等。
    i8042 有 4 个 8 bits 的寄存器,他们是 Status Register(状态寄存器),Output Buffer(输出缓冲器),Input Buffer(输入缓冲器),Control Register(控制寄存器)。使用两个 IO 端口,60h 和 64h。

Status Register(状态寄存器)
状态寄存器是一个8位只读寄存器,任何时刻均可被cpu读取。其各位定义如下
Bit7: PARITY-EVEN(P_E): 从键盘获得的数据奇偶校验错误
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(输出缓冲器)
输出缓冲器是一个8位只读寄存器。驱动从这个寄存器中读取数据。这些数据包括,扫描码,发往 i8042 命令的响应,间接的发往 i8048 命令的响应。

Input Buffer(输入缓冲器)
输入缓冲器是一个8位只写寄存器。缓冲驱动发来的内容。这些内容包括,发往 i8042 的命令,通过 i8042 间接发往 i8048 的命令,以及作为命令参数的数据。

Control Register(控制寄存器)
也被称作 Controller Command Byte (控制器命令字节)。其各位定义如下
Bit7: 保留,应该为0
Bit6: 将第二套扫描码翻译为第一套
Bit5: 置1,禁止鼠标
Bit4: 置1,禁止键盘
Bit3: 置1,忽略状态寄存器中的 Bit4
Bit2: 设置状态寄存器中的 Bit2
Bit1: 置1,enable 鼠标中断
BitO: 置1,enable 键盘中断
2个端口 0x60,0x64
驱动中把 0x60 叫数据端口
驱动中把 0x64 叫命令端口
1.5 命令
驱动可以直接给 i8042 发命令,可以通过 i8042 间接给 i8048 发命令。命令这部分内容直接来自 < 参考资料 [1] >。

1.5.1 发给i8042的命令
驱动对键盘控制器发送命令是通过写端口64h实现的,共有12条命令,分别为
20h
准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
60h
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
A4h
测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
A5h
设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
A6h
让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。
AAh
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
ADh
禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
AEh
打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。
C0h
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。
D0h
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。
D1h
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。

D2h
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。

1.5.2 发给8048的命令
共有10条命令,分别为
EDh
设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED 设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED 设置会话结束。
EEh
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
F0h
选择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代码所要求的。
F2h
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。
F3h
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。
F4h
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
F5h
设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效—— Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘 接受击键输入,必须Enable Keyboard。
F6h
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
FEh
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
FFh
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。
AAh
BAT完成代码。如果键盘检测成功,则会将此字节发送到8042 Output Register中。
EEh
Echo响应。Keyboard使用EEh响应从60h发来的Echo请求。
F0h
在Scan code set 2和Scan code set 3中,被用作Break Code的前缀。
FAh
ACK。当Keyboard任何时候收到一个来自于60h端口的合法命令或合法数据之后,都回复一个FAh。
FCh
BAT失败代码。如果键盘检测失败,则会将此字节发送到8042 Output Register中。
FEh
Resend。当Keyboard任何时候收到一个来自于60h端口的非法命令或非法数据之后,或者数据的奇偶交验错误,都回复一个FEh,要求系统重新发送相关命令或数据。
83ABh
当键盘收到一个来自于60h的F2h命令之后,会依次回复83h,ABh。83AB是键盘的ID。
Scan code
除了上述那些特殊字节以外,剩下的都是Scan code。

你可能感兴趣的:(控制器)