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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上  
8 [. m: i1 j* Y, u7 S
; q$ F- K: x( J  {! [4.2.7 Command2 u& E. \% c& S  o, Z0 a

2 p" j8 A6 J/ y3 b. ]5 z通过8042芯片,可以:
) i% f2 u3 W! S. \/ ~4 @" z! x向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
& Z$ M/ ~& x. Y' @( t4 _读取Status Register的内容(通过64h);$ L. A# G3 i! x) K' a8 L
向8048发布命令(通过60h);
& A) s/ q, s" A2 W5 @: G5 V读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。* t- t: A/ M: D1 z0 w
+ Y1 n9 c7 `. l2 f  J4 n
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
5 Y( k, L+ W# t7 E- L( v; q
% F  W( g1 z+ B' h$ l$ A" i  r" S5 l' A' A8 m# y
5 ~3 y3 p' K( j$ F( y) B' w) }
    * 64h端口(读操作)
4 u/ B1 [9 u& U7 W
% V. I) ^( H5 n, V) n: z, i6 k
# N# s& h5 H8 r. x, m- X0 @1 h对64h端口进行读操作,会读取Status Register的内容。6 Q- C8 G( O9 H6 f2 P7 V; k

) A5 i; B/ E  _inb %0x64
$ ^  R! o# s5 |/ e% M3 h8 J3 ^0 T执行这个指令之后,AL寄存器中存放的就是Status Register的内容。
2 M( g1 D& s4 F9 Q4 {3 [6 d2 P9 |  n  ?; B) z
    * 64h端口(写操作)0 }5 X# _" n. x% J0 I- p, \+ s4 T

5 a! R) q$ K( }) X" c向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):$ `; W# `' T" Q# c
Ÿ4 N1 j+ X' A/ b
写入的字节将会被存放在Input Register中;; V  p7 W4 X" T- n1 M" V; a
Ÿ1 L* a2 B2 Z$ V
同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;" Y: e9 \2 B# U; T. h
Ÿ
! ^% e: v% }5 k, _1 A. r# b在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;
0 g2 A" `* B7 d$ x) W" m( `1 t3 IŸ; w7 X  d+ T% ]7 G$ j
在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
9 J% t; Q" L4 m$ Y- k! R8 L& F  a6 h" ~& b
void wait_input_empty(void)# Y! Q: \& X8 Q( n+ M4 E! s0 o
{
- r6 M( S+ `1 H7 O) I   char __b;
, p3 B  X) |6 r4 y2 X- J8 X) H+ \" u& e
   do{
7 N. D. ]% B! a& V* J' o' t     __b = inb(0x64);; [. X4 f1 V6 y+ g" e; D
   }while(!(__b&0x02));$ X" K, u/ q+ B. e& |; k, L
}
" y1 h. n  r3 f. ^( z; `0 U% y' Z) O0 }; r9 P
void disable_keyboard(void)
% k3 O5 S) n7 i3 L2 c  t" R{( N/ N0 n8 i  }3 S1 n  A4 {
   wait_input_empty();
8 e# Z- T7 j7 Y( X3 @" c( ?( `   outb(0x64, 0xAD);
/ S# _8 i0 Q0 |; F}[size=+0]
% m) `  s. v0 j/ F. j7 k+ l: ^9 ^' @5 q; x  u+ r& x4 L0 Z4 b+ n
    * 60h端口(读操作)
/ T' x* u& g! u* ]. K% |0 X) ~1 v+ N7 `! @3 m& r% p
对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:
  O# Y) Y7 P: w& u( p6 D4 D* l" x/ h+ RŸ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。8 F! n: {" C( @8 V2 d1 N4 H; g
Ÿ           通过64h端口对8042发布的命令的返回结果。
2 g2 }' }: `6 q/ x# S2 P! l
  V" g* T6 c8 n在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。: w+ P& q5 q+ p) Z  k& t. |7 o
void wait_output_full(void)
7 d2 T+ K6 h+ P7 K1 Z{3 R/ q2 r3 w5 K9 o/ L1 m( D, ~, N
   char __b;3 T7 w8 o' w) F5 V- u5 @& D
0 l+ c5 \; s$ c4 L5 A& R0 ~
   do{
' g/ @" c+ X1 T. _     __b = inb(0x64);
9 a$ a- _8 C9 a& t   }while(__b&0x01);- T$ S. z  C9 `
}+ y5 b# j9 y( g, H! A

  Z3 O8 q8 L7 ^unsigned char read_output(void)# V) F: {; ?: H  Q
{
: M4 }% o9 i$ Z! c+ n   wait_output_full();
- L1 r. J3 M6 G. n* k3 F) R   return inb(0x60);# {0 ?  v) o# ^' B5 r
}0 ], |( ~0 A& X1 s! [2 H
# G% S0 x% {' V$ ~# h; x/ n
    * 60h端口(写操作)
% z) A0 q( A; ]% S3 C- n8 p
0 F& ]: k, I. {- b- ?+ N向60h端口写入的字节,有两种可能:$ R4 S0 W% o  v+ W8 T- A" c
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;7 ]+ M8 ~0 @0 q3 V8 Q4 B4 b" x2 I  K: V
2.否则,此字节被认为是发送给8048的命令。
' m, Y  k: g5 P5 t2 @9 h2 x  k
/ P" `' j/ t7 b' D% n在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。9 F* ^+ K8 A3 s& O8 [" `: U

5 N* V8 [) `& W& A# ~. t5 g
. X5 D/ X! S% F3 _6 l& ][size=+0]4.2.7.1 发给8042的命令8 ^  h5 u+ B2 }. S+ a1 M9 {

& Q  G' o# x+ }2 @- u    * 20h
# s  a3 U4 l- y9 G( T
( f. g6 M7 H2 f% K准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
3 z5 q8 l* y' ^  n# L# K, S1 Y- E; m) L& F) M* u( |$ X' t* z

: b+ x- n; `! ]  l3 X9 u9 kunsigned char read_command_byte(void)
4 X0 B, _8 W7 }  x3 }{
4 A, |) T$ D' M/ o   wait_input_empty();8 {" V1 M! x1 I9 S" }' }
   outb(0x64,0x20);. \9 K7 T6 [3 k7 u
   wait_output_full();6 V* U" R" \; n& f( L
   return inb(0x60);   
- d  T) U" K' d2 Q}7 o/ ~5 N( _" l) p. K* f1 K

5 F$ ~) ?# n( D+ V5 @6 I    * 60h' I+ p0 i, O2 ]; a0 E" x& @8 m0 \
* R$ Q( n7 |' ]+ N; P$ W* G
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
% ?* q0 ]4 P0 K8 \$ D# c8 ]8 K
( n% s, d4 P4 Q& l, p/ V' ]
& ~/ N" c6 `3 qvoid write_command_byte(unsigned char command_byte)* D" p2 t/ ^8 Y# q4 c! n( e
{
2 o7 b# K$ L5 H, y& @0 U0 B   wait_input_empty();
9 d" G/ f7 R/ _, h; b( D   outb(0x64,0x60);
8 k1 r! Z# W+ V# X   wait_input_empty();' q2 B& S+ @& N, c: z* y2 @) S% K
   outb(0x60,command_byte);) N5 _  F9 n5 Y# n4 A8 m0 M
}
- B! ]  a+ Q0 a* L; K+ m8 K1 e/ F: E2 l  _, m4 u

1 c  a" w! F1 {0 ^" v9 C( D    * A4h% v9 D  X, \8 ^

2 ?7 v! W& g# x6 F3 w  N2 w测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
7 \7 o% X7 O/ @' N( o0 ~bool is_set_password(void)
& C$ H$ D9 Q+ u  u{
) Q" X1 ^- \1 @2 S9 _/ S) _* v6 D   wait_input_empty();% w1 U3 [- n9 D5 w( S# u
   outb(0x64,0xA4);. J' q; V6 `7 ^
   wait_output_full();
# c: I  y* ^7 v$ l% `   return inb(0x60)==0xFA?true:false;   " j; g: |: B! c! B9 p+ W+ X% e% C
}9 P+ w& C$ }! F7 A& Z* u( ], _' p" t
# \! b; z4 O# l2 G- T+ S
    * A5h
0 _- e, S6 ~! r2 K% X
* }3 L) g: {! b& C& t2 p; _设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。! d- `( q7 w: U' ]
void set_password(unsigned char* password)/ j/ P. Q' {( B$ H/ v4 e3 e0 U/ _
{2 t- @* h2 A& n/ K$ J
   char* p = password;
8 a4 {/ }% @1 j1 F9 p' ?% \( C
- |( [5 N- b; Y7 d   if(p == NULL)5 B. n: i/ g: p+ Z: `$ y
      return;
: o4 v7 }2 i6 r# C7 t$ ?. p
) u/ L5 I; k$ E. V, F   wait_input_empty();
4 n7 \" `" \8 |: g# i9 Z   outb(0x64,0xA5);
0 @1 s% y" \4 t( q( Z+ L7 D& m' x8 c$ d
   do{
4 t+ S% I, P- n2 d. b) D- e      wait_input_empty();/ s4 S4 b* e( w; a' @8 Z9 f; c
      outb(0x60, *p);
3 @( m& v" N: a   }while(*p++ != 0);
6 e  X; W  b. ~& t. {5 j}
  U! z6 h6 _- Y3 Y: a; f) ^* N5 D, g+ Y  T; b" T
    * A6h5 L8 b( |3 Q, _0 X7 S/ w4 Q0 F

: w: ^8 r& K; f# o让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。
5 ?6 @( C( t8 J; c$ cvoid enable_password(void)
5 y  A% `. Z1 Q: G% |: l( G{
3 Z$ r2 }  u5 R) q. }( `   if(!is_set_password())
' Z, _$ I2 O. w! {      return;" e/ J, G3 g/ V) [% D4 B) l$ t
# C/ N& M, N8 J
   wait_input_empty();! G2 Q3 S  R! n! O0 T$ S
   outb(0x64,0xA6);   4 O0 j# H) t$ A6 k( J3 ?
}
" G) @' N' f- k8 f* K- ]
" m. [5 |9 s8 Z; e$ u5 K    * AAh9 t: C2 w  u& s7 ?6 U
6 `" S# E0 M  M# z8 R
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。$ d6 I  x! n; q6 @

5 j" \1 t* A$ N" J$ D2 I% j% u) q8 w# ~& G  B5 w9 Q( i$ I
bool is_test_ok(void), k5 c3 I# M" Q* T
{3 n' ]9 @+ m. D% a
   wait_input_empty();
  p. {8 D1 E: L* H5 S$ [   outb(0x64,0xAA);
# `8 Z1 n. R$ |! E( l1 ?$ n4 z& c: ]6 C$ s  ^9 v

! x/ F- F$ U! g7 F. P3 ^& D8 E   wait_output_full();  }- W$ y4 Z: H: Y5 p$ M: G
   return inb(0x60)==0x55?true:false;   7 D  G4 x- x' C1 p4 k
}
6 K, l) r# E2 ^' \8 V6 `! r4 c) K) b7 k0 D1 e: \2 W. D

4 Y# `  d8 K  e9 O! G    * ADh$ J6 t8 R" V' ?* c) B

  v) w0 V& F7 `0 n2 S: y+ D禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
5 R2 S( W/ v3 h* K  q- Q8 U/ Svoid disable_keyboard(void)- f! K. [. @" w+ i4 T
{" x& y( a: c5 L6 M0 C
   wait_input_empty();
2 P; g5 Q( t- A( X# E0 \0 |   outb(0x64,0xAD);, t( Q2 `: W4 R5 Q
  v* z( u4 S; j: v7 B  C
}
* E. B" Y+ P  a0 X9 p8 f
' T5 h9 x+ ?4 V' Y; D: Y    * AEh
5 U4 C6 t2 j/ `: t; _
( U. q( \3 v- G打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。
0 D, A9 z# b' x5 |$ c5 u8 ~  @: X- @, rvoid enable_keyboard(void)
; y4 M' M/ a  u0 b{6 r+ b- ]1 t/ f( A" i
   wait_input_empty();0 P  e% `8 l7 R
   outb(0x64,0xAE);
8 X7 `9 G$ i" _: {9 q
0 b8 _. t  f5 W' B7 \}
- w+ {5 I$ _$ }4 c+ \: U3 D' n, e7 p' z
    * C0h
/ ]& w. N9 N, b" y" \% M8 H% N6 n& _; I4 m2 L( b
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。4 X- W, U, y' i# V' @) a5 w
unsigned char read_input_port(void)
; X: k! Z, J- o& ]8 Z{# L* E4 G* T$ K' v- r. l
   wait_input_empty();
- v& |% Y* J6 G; g   outb(0x64,0xC0);
# _' B  z0 i6 [2 u9 b+ ^$ e+ s# m
   wait_output_full();* h" q' p+ b4 I+ O. [- Z% {3 v

) S5 k2 b" j* H3 O' K! z   return inb(0x60);+ N9 Y7 P( j% D8 U6 G! x
}
+ N2 V) B1 y. T# n' b& p+ A- h
+ G3 v  l! ?& O1 p# S6 H    * D0h; @+ t* t) n6 ^) d
2 I. b# _3 {1 M6 V  k. O1 R: s
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。
$ o7 k( Y9 Y4 K" _' |4 ?# i' Iunsigned char read_output_port(void)7 l# h4 H. H! j* p3 _- o9 y  F
{
, P& O6 }8 g9 |% K0 A% _3 \   wait_input_empty();
2 `, S7 m& ~8 J; F' J   outb(0x64,0xD0);# s5 n: U3 S$ @2 l% i
2 d$ z1 N- J3 U
   wait_output_full();
5 y+ K: D" {" V8 ~
  M# ?3 f* l5 @0 ^   return inb(0x60);2 ~+ I; _; P7 B  @7 ?4 M) V
}; g3 j2 ~: Q1 }1 }

8 r0 u0 K% E8 ]5 G5 o    * D1h$ d" w' C# {3 n* v( `+ o+ H3 g

  {- X6 b/ S2 [8 h. P准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。
& u4 l  c/ N; w/ X0 Yvoid write_output_port(unsigned char __c)3 q$ S- {% F; t$ p/ L7 C$ S8 D8 ~
{
' \& k. j3 i- P  _( T8 g3 U   wait_input_empty();
5 \; B4 N; C5 ]" P   outb(0x64,0xD1);
  L7 m8 h9 Q9 x. ~/ Z0 V( `
* m7 t: ?2 g+ M: @! v. \   wait_input_empty();* C: F$ g4 m- n# M/ p6 }
   outb(0x60,__c);
# E6 b( \/ W8 {& [3 J! S
2 }! U4 ?6 V- B: [# Z}
5 p. z. D6 I) H
9 p( Z$ Y4 F7 @( m3 ^% r$ e3 t% w% d. d2 S3 ~  \$ f6 s! s
    * D2h4 E3 |, s( f6 u
* `# \: V" d# l) k" E
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。5 S; S1 U0 t/ P2 H' ?6 D
void put_data_to_output_register(unsigned char __data)) G, j+ I  p# N1 M5 L: `
{6 d! X& S0 ]- K: b7 }
   wait_input_empty();
: Z! O. x8 m, s1 Z) _  e5 Q   outb(0x64,0xD2);- \; t( e) y: i7 W" ~. j* h5 ^; q
" T! l' X1 j- e: i, B1 u! W
   wait_input_empty();
$ h# W0 F' e) ]% \& Z, _+ j9 S   outb(0x60,__c);, M2 y. F# ?4 b% ]. c. s8 Q9 O3 q
}' |* m4 j2 z+ b

4 L9 o5 M- @5 Y  R# s* g4.2.7.2 发给8048的命令, a2 \  H. N# q  |& h

  E4 x2 l- J$ Z3 S* j2 {$ H& r+ p: }! a7 ~) Y$ L& M9 n
    * EDh
/ }; p0 e- w, J4 M# }
9 b% K" b4 V& i5 h4 O+ ]设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。) T. }+ N, W2 |5 y

  N: Y) ?9 m+ p1 q: V" G    * EEh
8 y# S9 @" y. h  B7 g3 _* P2 i# M- \* l  C, O' e( f: g# Z
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。2 A% b, q( T, x& q& B/ K

, R# _) [# Y, H  X7 [, u    * F0h4 E" y2 S6 [) Y

/ w9 L- z* |0 M: m8 U- ~# G选择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代码所要求的。
6 r1 w0 R0 Y: p  y9 v; u4 H9 Z
+ O& K" V5 h% @1 b! p    * F2
9 l6 R; r5 ^8 U# B2 U7 T" U. u7 W1 q5 l# M5 E' C8 e$ `: L* u
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。1 k8 m& p1 x6 z  T% T. S- n
, o: \  B( N) y7 K9 [8 g
    * F3h
( Q4 }8 T* ~+ I& U. C( S6 x3 u3 j! i1 H" ~- T2 v0 `3 j4 L6 b
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。
& N  r; Z2 T# Z
8 [& e* p( \' L8 P1 r* P8 P    * F4h
9 M/ {: q5 z! }/ z7 c/ Z4 p: H4 F6 E* n
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
& p) Q, @( r; i* Z: x( f0 M; }2 s3 C# a* \
    * F5h
0 u3 _; K5 p; X( q1 Y
: W$ l; o) u+ g+ P! p设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。2 @* |. Q; P( M( D% w
4 J* z# Q0 I! Z7 y) f  f
    * F6h
3 \; r$ B/ Y% |5 Z
" g, p* Q0 ?* [9 m: Z( ]设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
# {) E! N. y8 e# \7 |! k" a2 C2 f- K: H
    * FEh  n) C% V: d5 |* _% K3 ]/ s
* I: F; }1 ?" E/ Q
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
$ W5 l' Y" C1 z7 A
8 S8 ?5 o* b: H: B    * FFh  y$ X! [8 h! x0 P0 X% x1 @9 {

- M4 f0 D1 V  q! oReset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!
! ]. \: i6 [  m7 ?, o* t' t: ~. G非常详细!
9 h$ P8 Y/ D3 A5 h) U谢谢!
回复

使用道具 举报

发表于 2009-2-25 17:37:28 | 显示全部楼层
2楼好帖!在helppc的Hardware Data and Specifications栏里有相应的寄存器和命令详细描述。  B% d: x" x$ N
% Y5 j! h0 G6 A
我的问题是,上述描述应该是针对老的8042的,在目前的使用EC的系统中,这些status register和command描述在哪个文档中可以找到?比如intel的santarosa,使用renessas的H8s 2104 EC,按道理上述状态寄存器,命令等的描述应该在2104 datasheet里,但是我怎么找都没有。还是有某个spec定义了这些命令格式?新手问题,高手莫笑
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-4-19 23:41 , Processed in 2.342439 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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