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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上   6 e* c' l4 A7 }0 S2 {! r; r

6 c' z3 K- i9 @9 `& N' y; L4.2.7 Command# }5 l2 I6 i/ }' o" a6 y% z# v
) m9 X5 {  e9 ~
通过8042芯片,可以:- R3 ^6 f6 n8 Q. ^; n2 ]4 F7 j+ `' M
向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。$ M4 Z0 g3 m. p/ B2 m7 F; V6 D
读取Status Register的内容(通过64h);
# q  r7 F5 u) T向8048发布命令(通过60h);
* z& f: J9 x# [5 r读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。
8 z6 ~+ R! L8 S8 v1 p
5 m* h" D* A  V0 p: Q7 A4 @; k再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。$ i6 {& s0 H( p5 X: Y# d
0 L. k- k' [( x) Y6 U

! S) o% D# [0 S8 r/ }3 [" t
, O+ Q! _. G. ]* b0 `# g0 d8 z. f    * 64h端口(读操作)# t0 h3 a; k( \/ M% M

( \# @# c' e& i
6 P- r% f- `: D( R8 o) D2 T对64h端口进行读操作,会读取Status Register的内容。+ T' d2 Z4 q& Q! B( q* X1 y

2 N5 w, H0 P2 j1 iinb %0x64
6 I: W. i' D7 |2 G/ F" ~执行这个指令之后,AL寄存器中存放的就是Status Register的内容。& J: P- b/ B7 E! l

5 y: x, t# ~; x) T    * 64h端口(写操作)
/ R! y' t& W( w5 E5 Y
0 C3 ~" D& ?  {4 P  m/ f- ]向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
6 `* W/ ?' w! p9 vŸ. x  v  [' V: A
写入的字节将会被存放在Input Register中;
3 K) `/ H8 b$ o# e! y; wŸ) W( Y) M, {/ I: l% Z8 L
同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;7 b; w6 G2 p: u
Ÿ* n) d+ L/ \9 G3 F$ h
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;* e1 v7 _, ]1 {% u. m* o2 {0 w
Ÿ1 w3 W8 S, `6 m. Z. Z% e. O* x
在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。0 h3 Z* @" M+ N& @( ], R

: n' j! z7 \; ]void wait_input_empty(void)8 \0 X: |$ V6 {
{0 |) L/ \' x9 ^% t6 U
   char __b;
: ^0 Q- Q" O+ b# z# S8 m, i  g! i4 E0 x/ ~  n# p
   do{8 L( H6 |6 [3 M5 A
     __b = inb(0x64);
9 L# J# Y0 ?+ {8 T8 j2 G6 ?9 Q6 w   }while(!(__b&0x02));
; }) [& {/ Z/ c}2 k/ r- b+ Y& U7 w

# a* h3 D- j% P7 @# O% ^void disable_keyboard(void), ?! c  j- T9 C0 R. u0 o
{
% n9 L9 s% C# }$ s4 u   wait_input_empty();* \9 S0 q) Z( _5 d1 ?! K. t
   outb(0x64, 0xAD);/ f  A, I* z+ p0 E) O
}[size=+0]
0 |) ]7 ^. ~  U
8 e! Y2 |  [* R    * 60h端口(读操作)% ?6 \2 W, q- L, w  |* d

0 ~0 z' ]) f" r; t. x对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:
5 ?$ q- V$ u+ u% R( R! t( C2 CŸ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。
0 B& S% h4 L; D6 QŸ           通过64h端口对8042发布的命令的返回结果。
# N" ?6 }5 I& T5 k6 U$ ^
* t  m, W8 r, [5 a在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。- @9 ~% i- ~$ `8 N* b- W
void wait_output_full(void)
$ V1 e3 c9 m- A) @{
2 x2 Q# }8 \, r6 u" U   char __b;
7 F/ ]$ @, L  I. `: s2 V: S
8 G1 I) R$ E# f% \( G, n6 D. w% P   do{* {- w2 ^6 `+ I$ H
     __b = inb(0x64);
" T0 d- N& S+ g' Q/ E$ S+ F   }while(__b&0x01);: T8 Z; o/ l' D# r3 J' z) d& _
}" n6 P7 J! A2 c% `$ w4 l* a

8 N7 U5 H0 n  Z. R% G' Ounsigned char read_output(void)
! a) f" I0 Q. J+ _0 ^& n; N1 E{
. _+ m" P1 q! D) X+ B; h/ Q4 o4 r- S   wait_output_full();2 B4 a4 g) Z& f. ~
   return inb(0x60);+ {& G: Q1 i7 _& b
}6 s) G6 I# N3 Q0 H& X0 o6 h
9 C' b( x8 I, g: V+ d' I$ U9 E' N
    * 60h端口(写操作), X0 x1 G; i2 {# s5 `0 O9 P% m

0 g9 f8 [6 {6 v向60h端口写入的字节,有两种可能:' n7 l8 m+ I) P) V6 z7 l7 Z+ k, N
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
/ g3 K( H, u' [7 y. |6 e2.否则,此字节被认为是发送给8048的命令。
6 a1 p* k0 L6 k& ?: h
+ o/ l; v8 j/ V在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。. [- R+ v) L) a, `( H1 z

8 i( x6 k6 _  t! i
& x) z4 {" N: I: A/ w8 n[size=+0]4.2.7.1 发给8042的命令
' c9 \, C3 U) I! n, t) |  T" m8 c6 Y; H3 m& e
    * 20h
8 O% z: i+ |, n: n
& @" h8 N  l2 a6 v  u( w% p准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。5 Y) z; u" u: G9 t6 b. B

) E5 U# C# v( {8 @/ i% J+ _3 @7 u2 Z6 B) {1 p  c& \5 q# u8 j- E- v
unsigned char read_command_byte(void)2 b# Y; w+ l  ^1 Z/ i2 e+ h$ u+ |6 B
{1 z3 S( {- y( |5 M6 ~9 g% U
   wait_input_empty();
  n$ Z) q$ v6 [; ^4 ~$ n. \7 ?. R   outb(0x64,0x20);
. Y1 M6 B4 i% O' B7 c, R   wait_output_full();! k" s8 |, a  m7 ^( P& i0 Q
   return inb(0x60);   ( `% h, I7 @( Z
}! t0 |! O8 l! t, d! C$ R/ h% `4 H

5 t! N& U* c$ P, R    * 60h. |0 K9 c/ ?. j4 v

: M0 u. X! F& c- N% D% b5 F准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
. F9 G9 ]3 i/ v# t( T6 e2 k% j& p" O- P1 \0 d' _5 q* X
4 P5 U% b) \" \2 {5 G7 N1 O
void write_command_byte(unsigned char command_byte)! Q* e1 d! k2 N4 C6 |5 B
{
* R' Z0 a  }7 |9 L4 T, x   wait_input_empty();( X* b: t& l; R* t7 K
   outb(0x64,0x60);
4 }8 @; |- T* h: a2 s% V   wait_input_empty();' l7 F; F1 C+ m9 o
   outb(0x60,command_byte);
9 v; G2 q/ W$ {- S. ]}
7 c- ^2 _' H' x0 ~& v7 Q
+ d! U' i' V8 h1 w, G% m& n2 V7 H  |* l$ m. ^( ?! h
    * A4h
( Y- \: @3 Y# o4 A
9 s1 z" {0 W! p2 w, r8 `测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
, h: x; ?8 K! x% Fbool is_set_password(void)+ I( L  L' `5 U6 G" h. l
{
) r. H6 b! t! Y& t3 p   wait_input_empty();2 ?: G; j) S# F, W4 q
   outb(0x64,0xA4);& K0 L  n# I; o% P. G
   wait_output_full();9 W9 [. _/ K# `9 P* K
   return inb(0x60)==0xFA?true:false;   9 \+ g0 q5 C- S0 g8 |7 A" L' O
}. _' G& {5 W+ O
3 c6 @; e4 q9 H& n; T" ^
    * A5h
  ~( y* z- ]# T, d" L
) e0 J  Q- a; y! f3 m* M设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
6 u) V4 K6 q8 b" ovoid set_password(unsigned char* password)7 a: U* I8 z8 v+ F4 |
{- ?- {& U$ w8 Y9 |& }
   char* p = password;$ {5 I4 I( s( q5 \( B9 w/ ?# {
; t7 ?+ e5 N; w: _+ K/ s
   if(p == NULL)# v$ W9 h  F! T# [
      return;
& l( P1 r0 E9 a6 l) }  K
+ Y! r( T& d3 n7 O( z, O   wait_input_empty();0 |) h4 M7 f5 V/ V  p5 H7 E
   outb(0x64,0xA5);
6 b% Y  O. I  |% W
$ ?/ h+ s0 O3 M% Z0 _5 ^( F2 o8 A   do{; g6 Z1 R4 i- v6 _+ G4 P
      wait_input_empty();  m5 ^. Q! U9 |; Q& c
      outb(0x60, *p);8 ^3 |" ~. D- m8 S3 O6 V4 E! P/ W
   }while(*p++ != 0);
" Q7 _7 w# ?7 G0 Z. o# v}
# |6 I: S3 G3 l7 C" s7 B+ w! ?
6 X& h2 r% }$ m( _7 V( D    * A6h- }7 |- G  f; e7 L; I: C
# o# u( |/ t: p: @) d$ _
让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。7 O7 r/ X+ [+ @; e) E
void enable_password(void)4 @, L, _1 {, D; E" Y, x5 z7 w; J0 [
{" W9 t' J+ z( f4 S
   if(!is_set_password())
2 [! ?' ?# v3 W      return;6 O1 @" u$ D: K

3 ?1 P; `) e8 Y* G1 G   wait_input_empty();
. f5 u& X0 y9 j" I, L1 W   outb(0x64,0xA6);   & r6 Q2 ]& D% V( Q4 @
}4 d1 G0 M& o$ A

* Q, L& C: Z) s( `- n9 L    * AAh* X6 ]" v- j$ v2 F0 p  z( k
& J4 ^/ ^4 b# e- m2 D3 T* p5 M
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。9 `, k" q/ @( N# V: a/ S* t

# D: R" s% p* Q. J/ S6 C6 Z$ N" ~; ?  R) p3 n! A- p: c
bool is_test_ok(void)8 f* g" y7 F2 h$ S6 _& F# \) x
{4 v. v) p( [* t9 y# U0 D$ [
   wait_input_empty();
% i2 C$ }( I0 A+ r6 ^8 A7 ~   outb(0x64,0xAA);
1 J' s+ Y& U6 L6 {- y2 s0 j4 T  e) Y- o

$ H% X# i* g! ~( ~/ Q6 H   wait_output_full();
4 H& S# H0 v4 }+ L7 G* u- o   return inb(0x60)==0x55?true:false;   
# X  G0 E2 D5 {+ b}
3 }+ a5 p3 R8 X! H  \: C' {4 O( B# O0 A+ @3 C2 V

% A# O* ^3 ~$ {4 V    * ADh
# c# ]! `& H/ Z/ M3 p. ]
3 o6 L" v6 f$ Q+ P, U9 q禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
: T* `0 q0 {- Pvoid disable_keyboard(void)
2 P1 Y3 o% I9 v- X$ q{9 L% c. h* s: g6 V/ C+ X6 p
   wait_input_empty();
4 J. T. {* u& ]* q. A$ u   outb(0x64,0xAD);
1 s( F) r4 V8 v
3 \$ {5 u" K' c  H( u. \1 [}
1 C! s6 M4 B- g8 k" {1 g3 w  @# A% q2 ~9 J- N- W  l4 k: h9 M
    * AEh
0 U% I8 N. j/ c0 ~7 y2 e. Z
. w$ f+ r1 w: t$ L  I/ q打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。  m$ T, @) |* \8 i
void enable_keyboard(void)% z* T8 |. H/ {( ?! a% }2 f) l
{( L' j! p2 r3 M4 O2 ]% Q0 l- D
   wait_input_empty();
6 Y' f" E) H6 z& X  V! V7 U2 n. S   outb(0x64,0xAE);$ d3 n. _1 h" f

2 n& ?; Z6 p3 i* h* W0 ~}
% Z# v# f2 O3 t/ ^- G8 x
7 P$ {* J" X) W# I    * C0h
+ L& U5 I  h$ D: A4 m# g4 j! O* W8 N. w* f2 |8 }# s
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。1 o6 i' E6 G, m# U
unsigned char read_input_port(void)
. b2 ]* s1 b1 y  Q4 J1 d- ~+ B, [{' F4 Z( F* M4 {: U( e
   wait_input_empty();+ s, l- w9 ]0 ~/ k% y* `+ U1 B: e- }
   outb(0x64,0xC0);# p! b. G6 [; D, N

9 \6 |. i% n7 }) S4 M; w   wait_output_full();) y' s# h+ ~* H$ Z- v  D
& B, |( t$ a3 {% ]! b5 n/ b  @
   return inb(0x60);5 ^7 {& c1 y6 T. x% P
}
2 p6 `* b2 x: z3 E. _
: N- s$ w8 M& {& N% F    * D0h0 x& s/ w0 {4 C- o4 S- c
3 O+ P- D9 j9 w8 w, |0 E9 P
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。
/ N8 g" |; H& ]/ j4 |1 `/ Funsigned char read_output_port(void)$ c) }6 v& e1 [# A8 E( C+ Z
{9 z7 O5 ~  o1 A
   wait_input_empty();
* }! m1 s* J, w. Y! E2 O   outb(0x64,0xD0);" b4 I) f9 ]$ e
! j1 w. S$ V. C
   wait_output_full();+ Z. Q$ D7 X5 |* A; Q/ w
/ X) q. o; h2 I2 Z5 W8 H) l0 r* q  F. T
   return inb(0x60);
$ w7 k' S- P9 c9 D% J}' D% O6 h4 u8 ^5 \

" n7 o5 m3 O6 ?: W. i& D    * D1h
" r8 d# r* `. ?: t5 @: s6 l, t/ F4 [/ D- w1 C  N+ H# a2 }# ?
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。
+ U6 F$ y' g6 t1 W$ |  Bvoid write_output_port(unsigned char __c)  K/ m4 L# K7 y; Q
{
/ v3 L$ u* O* y/ }' D   wait_input_empty();
8 O" Q8 b$ j- Z   outb(0x64,0xD1);% f8 Z' U4 X7 c; v. X( l
6 j4 Y0 G4 T1 g& d9 q% _, r  A
   wait_input_empty();/ I. @; A# W6 ?. i' e& I
   outb(0x60,__c);
1 `9 k9 d9 K2 u3 S" R) u4 r, b0 d) m; h; w* ^. F+ z, B
}
' j0 w! G; i6 C: e4 Q( }- Z' S. B0 R& T3 x

  D( k. a* m: ^) u# [    * D2h6 a* N9 B6 E# w( |
% j9 W, v1 \1 z2 y1 p* F1 u, G* [
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。3 M: r+ T/ G* y! n. M
void put_data_to_output_register(unsigned char __data)6 m, @4 v4 L) h  H- i8 S
{) H0 o" ~6 c  G# o; @, z2 t, [# `
   wait_input_empty();
, ^+ m8 B3 O2 Y4 y; A6 P   outb(0x64,0xD2);, M7 ^# M3 _0 c' K# N. s
5 E4 m3 z2 L8 A9 R( @' r% l( R
   wait_input_empty();0 w3 \  `* L4 s) N- e  g
   outb(0x60,__c);
6 Q* T* I) \' s; Z9 V# q}5 b$ I  U# j+ Y0 ?

! c6 G+ T* a* ]1 E6 D4.2.7.2 发给8048的命令& J) E! r! l: D* E. S, {' W

- J  g* b$ \4 [* M# ~9 K& L3 S/ Z8 L& R& e7 q$ s; b$ m( G5 x, C
    * EDh, ?( U) f! S, d! d- f
1 V. e) q, m$ L& C
设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。
& d% h- c/ l% @9 e* ^2 E% L% N: O  ]# n6 N3 z3 v
    * EEh! A% t8 N0 H+ B8 y- ]

: }3 X7 q$ i' P9 X# N4 T! e- N- J诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
2 p7 Z4 e" e: @1 R; p/ X3 \7 w& w% f2 [) U: f: D8 ^
    * F0h; p" D( v. o# D+ E
! d' ?5 C2 \* y% f0 m
选择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代码所要求的。# q4 @0 @  K5 u7 }

! P, c: k6 @: R7 D& e7 `    * F25 V( C( a9 p! ?8 r( p" `
, D: x/ E0 f9 @6 P: M1 I+ w% R! w
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。
+ j: S: J% f6 M& _+ _* T
$ j) e! Y0 p5 E3 @/ F! G! `    * F3h2 g0 k4 k8 j4 r) @$ j. S6 l: S

/ s4 F/ W: ^8 \5 C0 N; x2 G2 L设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。- N! b9 ^- i+ M: ]; D+ Y; t9 \

( b9 {+ c' b1 \* M    * F4h" x/ s. R3 x6 }6 h. b% }; n! r9 S7 E

2 D$ F9 O9 ~+ Q# M清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
) j- L5 f' ?& ?+ {  e
8 u0 Q: _' n+ D* E    * F5h) Z- A. `/ u/ d; W1 c

6 U* x7 ]. j- `设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。
! _. x! k+ Q* L* H' P1 D7 f" K$ @  U/ e6 C4 H5 d2 S1 ^
    * F6h
6 ^3 f% E' Q, X! W; s" o0 u) \3 u- N  p$ V
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。' D4 |: u1 [* O9 Y$ F' D/ n; @
6 I( T9 }. y0 F) S, ^2 ]. p
    * FEh  |3 o* a% g9 J9 h  x
3 q& t: T% {. G4 S* E: u
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
  T; F$ l" ^) _; E( }1 Z9 d2 n1 D6 ~6 o: O7 Y$ W  k( y
    * FFh
9 I0 h$ s( U! G% ~2 i/ e, O, `' D8 t
Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!
$ ]$ Z( |' I: {0 G" `0 |非常详细!
# v% F$ t2 m" h4 }+ L9 n1 M谢谢!
回复

使用道具 举报

发表于 2009-2-25 17:37:28 | 显示全部楼层
2楼好帖!在helppc的Hardware Data and Specifications栏里有相应的寄存器和命令详细描述。9 X; W5 C/ a& F5 J* z

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-12 07:28 , Processed in 0.197978 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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