找回密码
 加入计匠网
搜索
热搜: BIOS ACPI CPU Windows
查看: 24661|回复: 3

谁帮详细解释所有发给ec的60/64命令号码和意义

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上  
8 h3 a6 G8 k( ]. O
4 t" U! F. d! Y1 b, ]4.2.7 Command9 ]" i7 t; b8 {, K
" P1 Q3 w; I+ i. R
通过8042芯片,可以:
9 X& `  L& F" G9 ?向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
  B9 l9 ~4 G8 |读取Status Register的内容(通过64h);6 R. \: y, s) d
向8048发布命令(通过60h);6 q; q- O: C" {+ D0 Y1 r) ~
读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。6 D8 L" D9 a/ _

3 Y( l& r# H# @' Y! d5 u5 V5 N再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。* T- c3 i: |  f3 S) A, e9 p
: ~8 ]. }9 ]# E
' o" y. T3 W/ t$ \* S
( Z+ H9 @1 l8 q1 Z
    * 64h端口(读操作)
8 V$ a# b9 T0 l. c$ f1 N" I  t, j% j8 \# Y. z' d8 @

7 e  B! _# V' L7 p7 T4 O* X对64h端口进行读操作,会读取Status Register的内容。
5 k* W# @, o6 s+ u& D5 @! M+ O0 v. ?# S. i' A! {% A, U
inb %0x64& {6 z( ?" D) u$ C5 I1 k
执行这个指令之后,AL寄存器中存放的就是Status Register的内容。- }* Y" K* p9 k% c' B* i6 S

* F  h, i3 O+ l1 T3 O$ X    * 64h端口(写操作)
, }3 V+ x% @  E+ R' A( k% c
/ Q5 X  W, x* n向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):5 a. _( h% J5 }' C/ ~# W
Ÿ
" e6 R3 D( K$ [+ H' o- I写入的字节将会被存放在Input Register中;. w# h% [: x' R' b* q5 Q! M
Ÿ
+ J+ i1 a1 _, C同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;: J2 v- [" `' K% u  P9 W6 H! n' l
Ÿ
' U" B2 k+ [/ N在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;# f6 J  @! X  M+ |+ ]
Ÿ
& Z! \4 i/ T5 ~  s7 o! E/ A在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
9 |& i) J" l! b: D6 _
/ [1 x5 O- [9 |) N3 f! ]/ I% Jvoid wait_input_empty(void)
7 P& \+ {( A6 P* }2 }{
5 |% q9 w! O6 v7 `   char __b;( @, T) H9 B- w, Q  M7 s8 J9 A6 x
. P( q# [7 M, K0 x4 o5 ]
   do{: c3 [- K6 s; J0 ^+ q
     __b = inb(0x64);
( a* W) h& Y* [& r# o   }while(!(__b&0x02));- S% a* L* J- J+ [# @% p$ n
}# c6 C; m+ m; f4 ~% d: R
/ R% ^7 S% e5 s. B! q  `5 @
void disable_keyboard(void)8 o4 j, _: Y5 t2 _" \8 g3 G5 o
{6 k- j$ ?. I& ]$ X7 W+ p. ~
   wait_input_empty();; \6 I! l4 @+ F! y% ]
   outb(0x64, 0xAD);+ w2 e4 m% q/ [, I6 Y6 o5 c( {7 r
}[size=+0]
4 I8 {1 C$ d# Z. b
7 Q& g- U3 X- S9 F. h5 U; g    * 60h端口(读操作)
/ k3 T. ]1 w" p9 j6 d
% r3 {2 k% t3 Y1 t2 J* b对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:
. R+ b- n- |! A# lŸ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。1 W5 g4 P* B# D& g' P8 }9 H
Ÿ           通过64h端口对8042发布的命令的返回结果。
1 h  i( Y  g7 o: d# a
( i& o  v  |$ W* |! _4 |. T在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。
# a* v# A* [2 G! `; p9 ?+ Xvoid wait_output_full(void)
' w# q9 c9 x& J/ l1 Y& Y) z{9 H! H6 i3 m8 ?1 t
   char __b;! U8 f$ O' A  U) \+ g4 j  o
! R$ ~: G/ p( ?# {2 t6 A4 p9 w* {. l
   do{
- U$ A" ~: F- v/ w     __b = inb(0x64);8 f3 s& I7 i6 M: s
   }while(__b&0x01);' F4 V6 l% `9 R/ ]3 j# W, ^% K
}9 l& r5 ?( e: X- V. d

0 @  h) u: {  w: `. q8 q7 G% j9 L- @unsigned char read_output(void)! ]! G8 F( N7 ?7 r5 N) c+ R! p
{
( i2 D" K) z; B) N! c& A' p   wait_output_full();: m+ q( H; L8 |$ f
   return inb(0x60);
. @  {1 e: `/ c}
* j0 g: V4 W, U7 R" T  y9 X8 J1 V3 u1 G  U7 x! \$ `6 t# k
    * 60h端口(写操作)0 Y2 v. h" K( F  t' A. w

7 b3 x; l6 l/ b+ \" e  m向60h端口写入的字节,有两种可能:% {  g; T3 U6 F' V+ }; Q
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
6 C, ?" y: y$ Z! E# g2.否则,此字节被认为是发送给8048的命令。: r4 C) L+ E. \( V

: T5 y8 b/ k7 V6 D) ?: _6 U0 h在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
, L4 z+ p! o/ s; n; Y
% V- Z& b7 p$ }  N/ }! G5 _1 m
$ `0 g9 m, w" D/ Y0 s3 }5 i1 Z[size=+0]4.2.7.1 发给8042的命令: F& |9 _' l4 S8 ^7 R
. S* S; m. i$ V8 p/ n# r
    * 20h
2 k: t3 S- O0 \/ T# F5 r) R% c
准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。: |8 }4 C7 ?0 t8 x2 V( O
8 M7 P# g0 F  X( ]1 H# X

0 f! O& v) v5 B+ Hunsigned char read_command_byte(void)
+ ^' J( E' A0 |8 u4 d) l{
; ~( X7 s7 p. ]0 u* u7 U5 S   wait_input_empty();0 t2 D0 e& x8 t
   outb(0x64,0x20);1 f1 v' \: C0 x$ P; m' v
   wait_output_full();4 r& K+ C. @3 ~& k) l! q
   return inb(0x60);   : j/ e2 D" C6 W7 v- Y2 n. N
}" N  `0 z% w. w, q
8 e/ O" ~! {: Q$ V
    * 60h6 k1 R! {# ~" O5 y
$ v% ]5 t: k; F, }5 a( h9 ^
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。  |+ X+ C  L9 g3 W  E5 a, _
4 K% i9 F' s) o: y" @
/ W; q/ w4 G% C/ c
void write_command_byte(unsigned char command_byte)
8 G0 L5 G1 [- _{& E7 G7 O8 w  v: u) p
   wait_input_empty();
/ q! ~: L0 W8 E0 Z+ q, w; J& d   outb(0x64,0x60);4 e1 Q* |% [* ~9 U9 g3 C
   wait_input_empty();
( h. h6 ], J' p$ C   outb(0x60,command_byte);
% G) r9 S% U/ A! x" W9 `. V}
0 Q/ t+ w/ I! e% v, I3 s  G, d
) P7 U4 E4 D) l# p* M
% m, X% P; U' b; h3 A) `    * A4h
, w' z- H6 n1 `1 I( Z( G
1 w/ U; f+ f/ F+ l" M1 J测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
! J  S! |5 X5 i7 obool is_set_password(void)! S% s9 M0 v7 q1 g0 |' e* E( b! K* s) c8 R6 r
{
9 P/ Y; I' U& N3 i4 ~   wait_input_empty();+ c1 u' ~7 I' ?5 h! B/ W: r
   outb(0x64,0xA4);
$ Q# \# \8 q5 m# `   wait_output_full();2 o, T( S0 l  f7 F
   return inb(0x60)==0xFA?true:false;   
  M# x( F7 Z3 n8 i. {" [, i}2 v2 |/ W! Q6 _2 i4 ]

1 P6 Y# v/ }  L    * A5h( q% _* C$ l) S$ B( D- k

0 U  C# L8 K0 T5 f4 ^! R设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
! @4 T) @: B0 h/ O" Q- Q( qvoid set_password(unsigned char* password). ^. W3 o: x7 o. T3 T# \( x' K
{+ H/ c5 h* E7 {$ H8 T
   char* p = password;2 g1 e% c& D! j. ]% d

4 L; M- }8 H0 h8 z7 l8 v4 _6 L   if(p == NULL)
1 m( r( N. L0 ?) }$ `  V      return;) x( k4 _% N9 _4 }, X- T% F
0 f- u  e3 Y# [& y' w
   wait_input_empty();0 A& g2 |2 v: G/ }
   outb(0x64,0xA5);+ n. z/ x$ z- ?$ t

( Z. j) l, k; T) G) ~   do{) k/ s* X0 i5 a5 _9 J4 u, R# U
      wait_input_empty();
6 z2 l# ~) h5 j+ }" K' Z      outb(0x60, *p);& X4 \2 E( F% f
   }while(*p++ != 0);
. a, _0 N1 H6 x: k}- K/ a" C* s2 V' q

  x2 N4 f  S$ y, x& j# @; y/ a    * A6h" T6 V( x6 x% c  }1 z; ]* p

3 u1 F  A& f' t: V让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。& y! C9 Z1 i8 x6 s: }5 A+ E
void enable_password(void); i/ p2 i6 I3 Y  R/ z! \
{
& N: F* Q* L1 W4 S3 ~7 {9 P   if(!is_set_password())# u# c$ X' z- _% {/ }$ r
      return;3 o# L8 F$ W0 h. p

. |3 B2 w2 O8 \) n* d0 g% D! z0 R   wait_input_empty();
& m. q# |" h7 J" @6 m3 d   outb(0x64,0xA6);   
* L9 _" O  O" u% |}  o, [  Q( o- e4 |6 @) q

  c; ]& j' U; V& z1 S  Z( ^    * AAh
% {2 w2 P0 c$ Q( {- G
3 K. L8 k; y( P' u7 B& ~自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
- D( b* R$ t2 t$ [% M; r: ]( O8 a+ U+ e7 R2 h
6 O2 j  t7 T6 `$ |# W
bool is_test_ok(void)
! A% ]! ]# v1 U3 K* y{+ R  C  |  }. [  {
   wait_input_empty();
% H3 P3 W! J: J0 U$ z# ?) |1 k. D# T   outb(0x64,0xAA);# J* I5 d0 A- d; V' P4 g/ z

- \: E! I) f* E% q3 F' S0 P/ f" P3 G$ q4 j: d
   wait_output_full();
% E2 W5 z. g2 k/ D% ?% Z& S% ]   return inb(0x60)==0x55?true:false;   % w2 e9 e% E' j- Z/ |8 K  T
}
) x9 L4 u, c# v# g0 n1 v8 n7 \5 d
# R2 t: d" B" _# n6 }2 x% h0 r6 y% f4 ~  b* d, i, d& }% I$ }" R$ g
    * ADh, Z+ _. I) c8 `  P7 R3 T+ u" O

9 W  V$ x! A8 L+ K+ K5 {2 N禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
" p  u( V5 h. s- s( O% }7 q& Zvoid disable_keyboard(void)
  p4 `) G( q2 g, |{
! e+ h. @5 W5 I" c6 J( k   wait_input_empty();
5 H  c( Y! g4 q8 |   outb(0x64,0xAD);6 C) f5 ?  ?0 r% s: n- j* i/ s
6 B. s" Z: u. c7 o7 _0 I4 N
}
4 F6 g+ s1 j# f! N# t$ ?* m* ^
( h! M& \3 H; e# _    * AEh1 h  ?: }6 G& k, d) M
. t9 ]2 \; m0 ]# d4 n" i3 m0 x
打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。: r4 o9 @- z, X8 r" a
void enable_keyboard(void)8 k" V/ X  d" j+ |6 \
{9 T( _5 k' |( U8 v4 b- O
   wait_input_empty();$ M2 A/ V9 C0 H  N2 ~. x
   outb(0x64,0xAE);4 y( Z; J+ E' ?& z8 h3 x

$ @4 `0 s2 `' X* u* {7 V}! ]7 u( h5 J) K  k! e
& m/ S: p+ \# J  v
    * C0h5 m: I0 Q- P3 L, C7 i3 D
6 L. h' R3 s; c% U# V0 P
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。
" p2 u5 B' s- O! r3 W# L9 Z4 [unsigned char read_input_port(void)
  N8 m/ B6 Z( J' }2 y5 |/ N{, f5 W% p" h; F7 o8 |
   wait_input_empty();
6 E1 A  r/ [; r4 ~: ~0 b7 i& T   outb(0x64,0xC0);
" {6 |6 V5 }* s% Z3 Z  @5 ~- B( N1 j4 O0 B
   wait_output_full();
4 d  F$ i6 v* V* l4 k+ c
" c; f6 ^, ^. M6 g   return inb(0x60);: k: a0 F$ Y6 [) |$ T
}, ^9 ]7 ~3 M; b0 V

3 w1 F" Z& U2 r4 ]/ H5 Z& _- A/ L    * D0h) i6 z4 E( P% `" A

4 o+ `8 m0 i5 L9 w. p) U准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。
% ~3 i- O7 {4 m# W# runsigned char read_output_port(void)" K0 ~* Y  }( G+ W3 r
{
9 I( K& z* k( K   wait_input_empty();
' d2 S2 u5 q" W: i1 c, O: X9 P- ~   outb(0x64,0xD0);
- C  G$ a  t$ B! v7 w, L6 q& F
0 Q0 I$ n- s* S' d7 h$ ]   wait_output_full();
$ x8 f3 T' @. D* m2 f- i5 p' S% b  Z% ]. p! f0 z  f
   return inb(0x60);
8 g6 S. n) f: {  |' a- C. i7 O}. O8 f6 ?# x' S0 F: e7 R7 K* K5 r1 C, k
/ {3 q! x. r+ A
    * D1h1 ]; m. Y/ c0 R) a

6 H2 o. D- g# J准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。
) N. w) W% J' P* K2 ]) O. lvoid write_output_port(unsigned char __c)
, p, D) t7 V. [; r2 X{9 G# V9 Z" f* O; |) ~
   wait_input_empty();
/ @" a3 i& ]' e$ U) L   outb(0x64,0xD1);3 N/ B& a6 r) h1 `
6 ]. T1 D/ W! g8 s5 |* j# M3 s3 @# ]
   wait_input_empty();% R6 b1 ]) u; Z2 [) X
   outb(0x60,__c);6 l  N  u8 x' _1 D% _6 I  f
: L/ P" E/ H$ I
}
; ]& D/ a, k  ^% l
5 f+ F8 I% |  v" s% b+ g! V0 `) ?( I8 K7 d
    * D2h5 N8 s- o0 I/ q2 y

4 f3 ?: _; |" M# _( K准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。! j8 v% u0 L/ w& o. o! P* `
void put_data_to_output_register(unsigned char __data)
$ M( F9 n. G( D: ?4 a( T- s6 w{: o3 |% Q2 M- n6 \
   wait_input_empty();
& _$ `' g" h) A   outb(0x64,0xD2);$ ^1 w# g) V7 r, k
- c0 @  r- X8 M3 E) `, e
   wait_input_empty();
3 U$ K# B4 ]" z& F   outb(0x60,__c);
6 k$ O4 }7 _9 ^}9 ~* v& w9 N! T+ x
: Q$ b% |5 ~: l1 t/ S- H3 L2 W9 T
4.2.7.2 发给8048的命令
7 G/ k& x; P" I0 j5 X% a, K" |; i4 ~7 b, L! L3 D
/ f3 Q' v# f9 K- G9 G
    * EDh
; V4 X5 k- Q0 N3 A4 i6 q
/ \1 J6 v3 Y: V5 N设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。
8 D8 Y/ S0 c5 n  Y7 a" M+ u& c* w# _1 N, _) I  E4 \* L  d
    * EEh/ c1 k5 z6 s5 k+ R
* s+ f  V/ T0 z3 j; k7 l/ c$ C; Q
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。! N4 Y  G8 z! g1 `: y: T* h$ B
: j  P0 r. R2 k8 Q3 ^0 H- B
    * F0h$ q9 [  S# }" A
6 g9 I1 {  g5 T# _$ O6 u, B
选择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代码所要求的。
8 P$ l& k1 v, K8 z; E9 v# S- m) U8 Y0 S$ w  y
    * F2" n/ X1 s, V7 R5 L% x+ S
6 w4 X5 G3 y% Q1 g0 ~2 w
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。: |1 F' n, Q$ r  J9 }
) M: T* \; b/ u4 j1 \( [' h7 a. J; ]
    * F3h
# L0 p* c: c) L6 I' h; J! k% `+ Z" S) j* S7 `( B2 j7 F( ^; r
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。  J8 Y& p" u( l8 G

9 L5 K( ?% L5 F. q- G5 [7 G# _    * F4h0 Q5 z# D9 u* m5 j

* F. v% z3 U- N3 ^; r清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。5 m( A6 q4 i$ Q' H4 _  b) A% N: s

: d2 j: a, {/ I% }    * F5h
9 L3 e+ n. t* s, {4 k6 s" q; i. @( o% `/ E4 g0 [6 @
设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。
+ i4 W6 v. C' t2 D0 x
& d- d- ]5 L" B8 K! T    * F6h# n( B, p6 c/ g' l
; Y- @2 D* z/ J6 r
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。: G' N  `, D: i) G4 p1 M
4 E3 z/ c6 c+ H4 z
    * FEh
) B3 c4 E+ `# ~7 O  ]7 t" N/ U. ~! k) W: J) Z, r
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
2 U; U! c. E  ^# M/ d9 Y& f3 x
: q0 Y3 r4 p- q& s+ x" f5 ^! M    * FFh
1 U8 X7 q( ?8 J0 M
# ?" A. Z; J. ]1 @+ v/ R8 B9 aReset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!
& @" h9 i: [: L/ I8 L; R, X2 T非常详细!
* g3 h3 h  w, {3 J# \, Q谢谢!
回复

使用道具 举报

发表于 2009-2-25 17:37:28 | 显示全部楼层
2楼好帖!在helppc的Hardware Data and Specifications栏里有相应的寄存器和命令详细描述。) J6 `7 Y: R! s  |

* T8 `9 C9 H' i0 n我的问题是,上述描述应该是针对老的8042的,在目前的使用EC的系统中,这些status register和command描述在哪个文档中可以找到?比如intel的santarosa,使用renessas的H8s 2104 EC,按道理上述状态寄存器,命令等的描述应该在2104 datasheet里,但是我怎么找都没有。还是有某个spec定义了这些命令格式?新手问题,高手莫笑
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入计匠网

本版积分规则

Archiver|手机版|小黑屋|计匠网

GMT+8, 2026-7-22 16:33 , Processed in 0.050701 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表