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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上  
, {; E9 ~, ~  ]- M. P
2 {# j2 X' v6 b& o9 i& {4.2.7 Command  g/ e1 c8 ], r# v, G4 g
+ H7 @  D1 r5 j% F/ C0 f% O* F
通过8042芯片,可以:: C& C; [0 l8 z3 D
向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
" M) X/ E7 v9 ?) i! I# ^9 V4 h读取Status Register的内容(通过64h);
, R- K+ ?: D! L8 s/ E向8048发布命令(通过60h);
6 ?4 ?: }4 y' b6 [0 F( S1 Y" M9 F读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。
% j9 D& l5 g! ?  g7 p/ [+ x0 e% X  _; p' d
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
: @2 P" H5 n+ b* ^( Q9 Y4 d$ S$ w  t- Q$ z: |, z9 c

: G. I( N  W1 m6 ]8 M( ?3 U; a; p: H) O; A" L9 i8 {1 U
    * 64h端口(读操作)
- ]' R6 W) e% q% G# q
: a% W3 `5 G8 u3 _5 ~! b& a
+ K6 v/ x# Q+ Z* D- C6 E9 i3 `对64h端口进行读操作,会读取Status Register的内容。
0 @! r: E0 h0 ?- w+ @' ]: @3 x; F7 {' A
inb %0x64( S4 z3 t  x) V& @1 W
执行这个指令之后,AL寄存器中存放的就是Status Register的内容。+ w$ `# x8 N4 ~0 x

1 e. M/ P$ S* `6 v    * 64h端口(写操作); n9 X6 p! N7 `4 U  U
1 p. P$ E+ {$ Y4 o1 N, k) C
向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
, W, D$ ?. X5 Z+ eŸ% J2 w# d( v9 n- _
写入的字节将会被存放在Input Register中;! {' M6 m+ Q" ~
Ÿ3 ?$ s5 W* I) {
同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;9 P: b/ O* ^6 S3 c% G8 o4 v
Ÿ5 P+ M0 m( ?1 ]6 [
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;( b" [  A# g0 D" b9 o, t6 Q  S0 W
Ÿ
$ P. a$ B! K* b" w在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
- u' _7 q# [/ }/ X
9 b0 C6 B: ~  M% f+ ~4 evoid wait_input_empty(void); Z0 J9 r- s: h/ c- M# k
{% \) s! O0 \: r" ~
   char __b;
* l& f* o2 B8 U5 e& f/ c8 G9 Z
& Z1 x% z* f7 ^3 _5 U4 G$ j   do{
& _5 A- m8 [. c( I9 E! o     __b = inb(0x64);2 c2 v# n. [1 U2 m% X; _
   }while(!(__b&0x02));1 r- q) M5 G) g. k& u6 P
}! i+ z4 q7 k& g' w+ I

5 h! w3 r1 K: F" H  ?' m) r" b$ t3 Lvoid disable_keyboard(void)
+ b! [; l+ d1 L! X{: Y6 T5 N7 U- t/ u9 [1 \, |
   wait_input_empty();( u/ }  J6 ~# X/ O
   outb(0x64, 0xAD);0 n2 [+ K% P- c; R  h
}[size=+0]: A3 o! j' t6 Q" ]

  K, c3 U5 Q1 L6 U2 \. J" f    * 60h端口(读操作)) A+ J+ S# B; E" C9 k/ S! \
9 D/ `4 @( Y3 m  e+ ?( G9 G
对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:, N# \2 r% s2 t  ]8 \+ j: ^# V" U
Ÿ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。
+ ~% {1 O  p. t0 sŸ           通过64h端口对8042发布的命令的返回结果。8 j0 g- d8 D% K+ @) n; a/ u( Y

1 Z+ _' k& q" \) Z在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。( _" ]' y' ~# U; Y4 E
void wait_output_full(void)
0 h2 H8 @& o" Y- P/ t( y{; |, }+ [- M/ }! c
   char __b;
( ?- J6 w7 g/ Q" y3 j# k/ \, D" B" B4 k! C& T8 p
   do{
2 ]0 c; [! F. a$ _- v2 I     __b = inb(0x64);* I) s" |  ^/ O' i8 h; @
   }while(__b&0x01);& t) I5 d: J! M6 V
}9 t. g) {! B5 l

4 L0 @2 ]# y- B  }! u% Aunsigned char read_output(void)* j2 G/ F; D# Z. \' ~
{5 R+ u* [( [/ N, b
   wait_output_full();
  r  K) B. `' a9 ]' B: r  j   return inb(0x60);9 |4 J/ P9 D0 y$ v
}: Q+ p: i% p1 H! H  N0 T0 t
! g) h5 g1 O; r& C
    * 60h端口(写操作)3 `: V2 n2 v  S. ^: a$ E" a
: F% q' {7 r4 y; ]8 U) b
向60h端口写入的字节,有两种可能:
5 r/ q  h0 n# y4 w" V1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
$ L' Y( I  O: q! n$ ]* W% Q3 a+ t2.否则,此字节被认为是发送给8048的命令。3 M% C9 ^6 I+ f6 v2 V) ^/ v" w
- m0 }' |5 Q* z" L' K% [" H
在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。/ I: E5 d2 U. U: |

' ^5 u+ c# v+ i  p& a+ p# H
: O# i8 `1 n# m) x. N; Z- }" w[size=+0]4.2.7.1 发给8042的命令
8 {" U' P: I5 }
4 R0 z" L) r7 ~6 l* I- G    * 20h
. [; e+ i( K, j+ {
2 V6 Z  x1 Q* u准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
  z0 D) P- i2 F& x$ n6 i; j9 [$ ^
4 o6 M$ C) V2 h) Z9 R8 o
2 g% D/ @8 c4 h) t  h' Y- m' @unsigned char read_command_byte(void)* n- K, O, ^' V8 k
{, X- P+ a5 }' t
   wait_input_empty();
, a6 t* I+ M6 Z   outb(0x64,0x20);- C5 i  @5 K4 j6 Z# R/ ~" E/ _
   wait_output_full();
- m) q& f. O* O0 J   return inb(0x60);   9 T& t+ `. M& l
}  j& R" |% U8 o& v$ B: R  C/ ?; m

& i$ _% x( p$ w  r1 O9 X    * 60h# c" C0 w! }- d4 C

( `: E( J7 V& @3 C2 j' K8 S9 ]准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。1 B$ b- j' w2 G2 u% K, Q& I% d

( r4 w( C& h0 \4 x% W' ?
0 E! ^0 ~( ?$ Z& {6 E" G0 M0 Pvoid write_command_byte(unsigned char command_byte)
2 G$ L9 A2 d0 u+ R0 p' v; v" x: ^{
0 Z/ S3 P. x& c* h+ S: r1 D   wait_input_empty();
, v' N, U0 n" i6 \- i) [2 R/ Z   outb(0x64,0x60);6 x; A8 o. ?" A% c2 x
   wait_input_empty();0 d6 x( h, b: n' ]# h& g# X
   outb(0x60,command_byte);
! h) A- @1 j/ V4 P* k}  |" p4 V4 b# R! }) l8 s$ b

1 @7 O- n- F/ K  v: V3 }9 ^* M5 A1 ~* n. g: j7 [( [  N. a8 b
    * A4h
1 W7 H) O; V7 a* K) |" p* [* P- f+ }5 M: N
测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
3 g$ D& a4 T4 F+ v; Ubool is_set_password(void)
5 G9 N0 Q3 ~+ }4 S{
, v" Z7 y3 e% k& [   wait_input_empty();
5 Y3 y+ D/ q" l' x+ b8 f" y   outb(0x64,0xA4);) V( x7 K2 Y; s9 k* t
   wait_output_full();
) y3 v. Y% a1 X* r# D; F   return inb(0x60)==0xFA?true:false;   
8 G' N5 N7 h8 v; }4 w4 k}
# A- N: X0 W& F; Q  }$ Y
% n" `2 X" T" _7 W    * A5h
: Q1 A% t( V( i2 ^" z; B4 W9 X* A. z' H
设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
& _' t* @3 Q4 Q0 ?+ F, t1 J7 t- ?void set_password(unsigned char* password)9 p' C: ]! B/ B6 z( R* ^
{, h1 L, i. u9 P) O' W# V
   char* p = password;6 u6 D" r' C0 z" T1 `2 W$ ^
; E1 D  u) ^/ y/ H! O
   if(p == NULL)
3 D" [8 f  V# G5 A' s- Z. Q      return;! }+ Y+ [$ `; V2 Y/ @$ Z3 L

& [  z/ }& S+ M8 u$ R6 X; @   wait_input_empty();' i9 q  j/ Y, i# N! F7 O& k
   outb(0x64,0xA5);
! D3 @9 w9 c3 D1 q
/ v9 h+ W9 i$ h. P: `8 S   do{7 n4 I# Y6 o$ K$ z
      wait_input_empty();
3 e/ \6 o$ {8 p8 v. L. g* o* T      outb(0x60, *p);, J, E; e% w' K' ~) m. K. b% F
   }while(*p++ != 0);
3 o' c8 A7 m( ]! q1 ~}1 C0 U7 Q7 L2 D( o0 J! _

: |- [5 W: N% e* ^% \( q    * A6h
* o/ B% `3 r* t/ \" a* w
# Q* ?1 l5 R# _( k4 o让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。
- ]' L/ m3 F1 ~3 b/ R2 wvoid enable_password(void). ^% I& e3 T2 ^; T  T% @
{2 p, V) p# H' E) G2 [
   if(!is_set_password())4 ]. S% S& o1 V) c: F
      return;1 w) x8 j) S' k# C

+ A# v( w# ], j$ X6 |+ o5 I   wait_input_empty();& H! _2 G3 j+ z' o, _
   outb(0x64,0xA6);   
) N" [# p" ]5 R* K/ V4 m}& t  v1 m' o( b$ l/ E& S% c4 d
+ I- ~4 E3 K. g0 U
    * AAh8 L, z3 M, R, {. @% E6 [

& j: g$ R7 u% o$ p7 J自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。% ~9 w4 H! J* l

( U* S1 `3 z  v& p! T' r; g3 B: B* j  a* `$ p, Z
bool is_test_ok(void)
$ S% B1 T( `: N: j+ B{7 g, L% {* k* ]& K: R; [* m
   wait_input_empty();
! z- I0 P# k" ~% V- t0 I   outb(0x64,0xAA);
% j1 C) c6 f3 U2 g& [* D: [& ^6 N. B: J6 f; L' K1 s; Q4 D5 h8 a
; C9 d# {5 m. e# t/ i$ E+ x
   wait_output_full();+ o' I) \( S7 R8 M7 `
   return inb(0x60)==0x55?true:false;   
4 o4 C% s( b* w1 D}
; ~6 a/ m: c+ M. |1 [' S& Q2 I4 y+ {+ U; D
& B3 R  g) v2 i! a* b
    * ADh
9 S* V- e. P2 B& b
$ `4 n% z. J" V6 v+ `禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
$ I% h+ D& }! xvoid disable_keyboard(void)
  f2 _- u/ m/ |# o; v7 `{9 k+ c) ^7 V  A/ S7 t
   wait_input_empty();
9 v4 M6 D. H: Q3 c   outb(0x64,0xAD);# m4 [  h" E6 J$ h" D+ i' Z
/ C# B# S6 |# l! J) g# ~+ H: m
}
* J# k& N0 X' G. K( h4 s7 a- H, x# p1 V# o
    * AEh
4 e' n  `5 x. \) O+ w( f2 G" Y% q) j8 }+ O# ?  |4 p
打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。9 z1 \7 H7 q# x
void enable_keyboard(void)
! H7 X& ~: n4 h8 ~! T4 w2 {! n{
& Y9 [$ O+ N" s) o! C   wait_input_empty();
  ~& \7 x0 b9 @   outb(0x64,0xAE);' k  _4 M5 B# G5 k6 b
0 K1 f% Q$ d) |
}2 i- h/ n' _$ X5 Y$ a

& o# D+ f$ |4 R$ U$ G9 C* W% e    * C0h
/ R0 }4 [: [) L
" w6 g9 y& |5 L" d6 M, F准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。; B0 [: c" r1 i/ @7 U, H5 Q/ F
unsigned char read_input_port(void)% a1 K7 l2 l  S- t# ~) ]  j8 T
{$ r  ~" O* {( p
   wait_input_empty();
7 ~) M, `7 m0 H8 o( M   outb(0x64,0xC0);
+ @# M* [( p# X* Z# E. a0 c* ^' C* a7 W3 Z6 i
   wait_output_full();
- f5 u, M6 x* ^( D1 `9 f
; e( q% [! @. @5 N; P  v   return inb(0x60);9 i% d/ g" E) L% @! U6 V
}3 ]4 ?, f4 y& Y9 d

) I# u+ c' t4 B; t- c    * D0h
7 ?# ?/ o4 Z0 D  Z3 i& g8 c8 g( f
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。/ m. f" Q4 ]& o
unsigned char read_output_port(void)4 Q: a3 x3 ~0 u1 w5 p  D: z  ]
{
2 c1 U5 U' q  Q6 I- E   wait_input_empty();. @* E+ L  G6 N. b
   outb(0x64,0xD0);
$ w& o1 e  g. s- t( T
; s5 P7 v3 o6 `   wait_output_full();
8 l6 a" \  {% s( ]7 v: w" B
7 D. F' F' i% l* q( D" S   return inb(0x60);9 _  e4 z; h1 I2 z& I, J  z7 j
}: Q- V1 x8 y1 a/ O) f+ D9 ]1 y3 o* G+ {
* d' l* v2 d5 u8 @/ H$ }1 ?) @
    * D1h/ q) W9 S/ D$ U9 Y( R

! t7 q$ u' O2 C3 L* |# _& d; ~( z* q' n准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。
" x# f2 F7 ?; @" W& q% H8 N3 }void write_output_port(unsigned char __c)7 Z! {9 t% L# Q7 v2 p: t3 F3 a9 \
{
7 q9 Q3 }; [3 O$ y   wait_input_empty();
" e& G" h0 n8 D) C9 J! d   outb(0x64,0xD1);
( j1 h: S8 \* Z  o/ P  O) d' q9 G3 J. c; u- ?8 G0 ]" p; C
   wait_input_empty();% G' n7 Z/ W8 i& D
   outb(0x60,__c);9 c/ v, c" Y. b0 ~$ Y

1 N! q. v3 a# ~}
- q, |2 h' b: l, h; f* M0 }0 z9 \! O! v1 U
3 Y% h5 A8 b1 z- F2 F+ w. I! Z
    * D2h
" }& M) u) }. r% M. U0 }3 h, p
/ d5 K& W* t0 H! L准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。0 @. o( i4 l* O# `
void put_data_to_output_register(unsigned char __data)
) x  X% E" W/ V4 x/ ]8 z{  Y% u9 z$ i7 ~* P
   wait_input_empty();* X8 s; ?4 ~% [; T  ^
   outb(0x64,0xD2);
* j$ Z) \  r- M+ N! t/ U+ a& E: O' ~1 ~, G+ H
   wait_input_empty();
8 |- ^/ ^% J* k: X$ F+ O   outb(0x60,__c);
. l5 b7 B4 P1 ^}
6 E& b, X4 {: ^# G4 u9 u, E0 }# E7 P* g
4.2.7.2 发给8048的命令% T' C3 j, _; U, l% O$ A

1 G5 s# A1 w' k1 b2 U0 S! `( d% T. Z# ^" \" N) y  Y
    * EDh
. \( f# Y; w4 [( v, y6 L( B; V
9 \2 o% X! d: E; _, j3 y/ K; k设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。
1 @: D/ j8 T  z; K- M3 v0 w( l& [& Y1 ]! t. [4 `
    * EEh
! e' w9 x( {* ]7 K' C
& Z2 j) _  h8 u诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
# |# S! E9 T+ H0 A% ?+ r: O6 o1 ^& |% Y* x; T! n
    * F0h
7 a) M0 _+ f) y5 t  m; a8 W& W4 v1 l- Z) M9 U* D- r1 |7 w
选择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代码所要求的。/ p+ D1 Z  i. |* i, c9 Y# g

" N3 O4 b+ o) h2 `8 _# w    * F2' Q) V" W* L7 a  Y5 ?
" w6 U0 S6 z8 T. s. U
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。; h2 W" K$ F& n/ j( Y" J# m& E1 @1 {
$ n1 k5 [5 T8 q( r% {8 A* u' T
    * F3h
0 H' K. o  L% L( q- N+ I9 l& }( F0 E& z" r& k
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。
: P5 z, Y5 m$ I4 w' @6 |3 B
- E: D1 K; A1 v  w  ?. |" G    * F4h" ^  {/ P9 _/ K( _0 z
: C" Q* s  U. V( X$ c
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
4 L( ~0 N$ n' W, b2 m7 m2 d: @$ Y
4 `  R" a3 ]/ p. W; N. }    * F5h$ i2 f2 i0 Y9 [% c& Y6 S6 K

8 {. T& H" d, y5 h/ g/ R设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。9 a& q- b5 n" O+ {$ z

! v3 M& v# ^" A: P) r4 E/ Z    * F6h
9 O9 D. P( n0 [9 i: L6 Z, M; J& R0 s& f4 b$ i9 g
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
0 z6 f( R( z5 V9 K- j6 D
7 W. e8 H2 J8 b/ I3 F3 S. B1 U9 {    * FEh
# Z2 _$ k% ^8 I9 N8 s9 c4 Z4 d) F$ U" u3 }1 w" I  [3 l$ e; F
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。# M) ?5 {* g( |( ~

" ~+ P$ m+ f+ ~    * FFh/ C* F* c! ]3 E* k" \% C- V( T
# ]5 m/ r  w2 D  Y
Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!
3 U3 P; ^; O, i* z+ M5 h$ T非常详细!0 w! w* L% N& a& G
谢谢!
回复

使用道具 举报

发表于 2009-2-25 17:37:28 | 显示全部楼层
2楼好帖!在helppc的Hardware Data and Specifications栏里有相应的寄存器和命令详细描述。, H8 D7 C$ `  E; t( ^2 `9 Y

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-6-8 08:24 , Processed in 0.149320 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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