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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上  
( }  W* z. y6 O. m2 |
4 D+ E. A; o, O! w9 k0 M$ [4.2.7 Command
' ^1 }/ [: }  ]" X) T0 J7 n
; v3 j  Z" y& l" K5 i通过8042芯片,可以:
3 G" R- h2 k9 q+ o8 m- H0 o向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
9 _2 R5 c7 z9 V, Z( a0 b读取Status Register的内容(通过64h);. t5 T, x5 E3 I1 K" F4 X+ s
向8048发布命令(通过60h);
: {7 U" f* K+ z; G7 U) a! d: O) I- E读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。5 m2 O9 x3 [4 A
9 E2 A6 r6 ^) ]+ Z
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
% c4 K- u. K; y+ u( W  n9 e/ r* n
- Z8 y( J+ ^& R% D1 R& e

7 S7 o3 C, L$ V! J- T+ U! b3 ^    * 64h端口(读操作)
8 E0 s: w6 s5 ]1 P4 U9 s/ {" ^; m$ [

% x+ M) }; v; A对64h端口进行读操作,会读取Status Register的内容。$ K0 O, o4 I) L0 K6 {  A
3 E' m7 k( Q; h* f1 h0 W
inb %0x64
' Q$ h9 w; h: C0 }执行这个指令之后,AL寄存器中存放的就是Status Register的内容。4 U, {6 G7 t  S! j7 D

8 n# w/ {3 i% {* l    * 64h端口(写操作)& _3 K: R1 y1 K, i$ ^, I

$ ~, k# |$ m6 k9 ^7 I向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
+ _; ?2 ]4 h( g" E3 `+ J, Q) Y4 jŸ
' u- M) \! N) T6 m0 `- y写入的字节将会被存放在Input Register中;( a* n7 i/ p1 G# E# c7 f
Ÿ/ p3 P- M( E3 d
同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;* y; T9 j/ g9 s1 B: z
Ÿ; f" A! K9 M/ b( m& b2 |2 ?6 b
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;, q8 P$ U! e0 l% D; l& N
Ÿ
7 ^  ^- s4 U. \# T6 ?在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
" @4 H8 p4 Y" \1 o$ l0 W% L
2 s, i5 X8 a7 U' P5 {+ Mvoid wait_input_empty(void)3 d5 r+ \3 W7 @$ C
{
) U! |; N3 |3 M9 x% O* ^1 q5 d   char __b;
; B2 _6 Y! U1 Z1 u. f  ~( E# X$ ]( F# f" l6 W
   do{
9 s: y9 o) @$ x- Z0 o     __b = inb(0x64);/ z/ I( @" W/ j7 X7 w7 T% F. t; ^! U
   }while(!(__b&0x02));* W& ~( H1 ~4 F0 K! ?1 v( Q+ w
}0 B* v, E7 \; ~% p# `1 z
2 e6 c7 Y6 Q6 }$ a; b
void disable_keyboard(void)
$ L; r6 w8 I/ W& f+ g; r' w! O{
3 ^6 Y  Q' U, Z' N! v   wait_input_empty();
7 j5 @# p. n5 w8 d* ]: Y& s$ z5 A1 y   outb(0x64, 0xAD);9 a. f! P* K2 G5 F
}[size=+0]
/ d! K2 W7 A' ?9 N# y5 a, ~* ]/ ]
" [  p8 i; `9 }& i- l2 N    * 60h端口(读操作)0 Z& o6 ~7 x/ {; g
# E, R0 G' c0 M7 z) T0 U
对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:- C" h9 k0 S2 J2 u
Ÿ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。8 A1 @; t. Y" v' U  N2 q
Ÿ           通过64h端口对8042发布的命令的返回结果。% c/ |% \4 O4 P5 G$ p3 {  D" Z
7 X7 K, v) E  \1 |" {9 [
在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。2 ]2 t  G; D; e
void wait_output_full(void)
6 g9 B* y5 e  }: Z2 d# n{
4 F3 K8 J7 P' X. T( k5 S   char __b;  Q4 H5 z) A4 K+ s
5 J9 G* X, x; ]& V7 A
   do{. `$ T% `% k3 V. v6 x5 Z# a8 E7 t: g
     __b = inb(0x64);4 k8 n+ B1 n7 H+ Q' h. F0 K
   }while(__b&0x01);
0 F1 ?4 x: B' Q- Z8 ^: V5 }. C, w4 [}) o# N* O2 j( \6 F0 B9 ^2 f
' F( l9 a* ^8 S
unsigned char read_output(void)' e5 M( ^! ]. }5 X; ]( ]1 N
{% A: x$ U. q4 H0 g! t
   wait_output_full();
8 M8 L# G& C+ r$ n6 ^   return inb(0x60);) B3 R0 x9 w, T! R. _. t
}
( B6 n' P# x) T- }, S5 S
7 W$ \# ?* ?% L: U, `) \% e) b    * 60h端口(写操作)- h/ E6 o0 o. o$ ~0 z  r, v

6 c4 E1 ?; E' G, x$ ^向60h端口写入的字节,有两种可能:
5 g7 Y1 D) }, d+ p- h/ w1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
, J: B0 u  E. `- e2.否则,此字节被认为是发送给8048的命令。3 L' q3 K& Y) o

" f! h6 G; ?9 E! C$ U在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
( F5 k, s) I0 q" N2 U  d' N* y  H1 e8 B" m

8 D% D' H4 O8 Q8 j/ v[size=+0]4.2.7.1 发给8042的命令; g& j' ~6 ]" ~. V: {

5 D( {" G- Q# ^) p% X9 x; I; b: o    * 20h & T- @$ V/ _: p4 j1 {+ S" I4 K" W

  }3 y' p+ c5 ~6 l( r* ]9 f准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。1 z( E7 U' a5 d. s7 Q; `1 n/ L5 K

5 }) ?' g. Q# i$ F+ E4 ~; o  |# K3 J, {+ ?1 G! @" c
unsigned char read_command_byte(void)3 D! y" U! d( l
{* j' |# \. B# E; T
   wait_input_empty();0 Z/ [/ _8 b* g4 O$ e
   outb(0x64,0x20);
/ S& z$ L& ?8 x8 ~0 Z   wait_output_full();7 N1 A/ B0 ]5 \2 Q% k  Q( F
   return inb(0x60);   
3 @' X) d# i; L}# y! i$ x9 o$ @5 i6 ^

! x* h6 ]7 `. Z2 n1 H" l    * 60h" }. f  M! j: u1 C

# z2 _, U8 d9 s; n准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
5 R, q1 m, t* c' N4 `2 z5 G) t* }, F% j- J

) Z2 \: B! L, D0 [+ q2 Dvoid write_command_byte(unsigned char command_byte)# b( b( }4 Z; x5 c/ H* s9 X% D
{5 s7 U  O  B' `, t
   wait_input_empty();4 r& n  y7 K, D1 }3 I* c1 c& _( _
   outb(0x64,0x60);
: L6 X- d' I( a& F   wait_input_empty();" o: B4 i& X- Y  J6 B- |1 t: a
   outb(0x60,command_byte);
. y; ^; C0 e5 }3 O}
7 ?1 W8 O# _. c# i" U, O) w
4 O3 T+ \2 K1 O: H. M2 _
' Q/ V- O1 x4 y% b+ f    * A4h1 q5 g! ~, ]. S5 g- G4 m
' |- A5 i& ~* P0 Q! O/ P" x
测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。( ~9 `9 f9 O- X0 t0 j& {
bool is_set_password(void)
, P2 U/ ^% \7 Y, n{
7 E/ i8 ~, y! H2 |% U   wait_input_empty();
" X* |8 H0 E! n) P* N: \8 {5 R   outb(0x64,0xA4);
, i1 o) q5 `. |/ W   wait_output_full();: U8 T# [/ S* l, }' I+ e
   return inb(0x60)==0xFA?true:false;   
" h5 @1 E* `* {6 {- s}
0 i% O* W7 g7 e+ s, x
) J  F' t0 P- j9 w8 ^/ I8 K) ?    * A5h
# v# J) o) j4 v2 k2 v, _9 b& t/ ?
4 A, A" O4 N& l! y, {! _# l设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。% s3 V5 M- t9 C6 F
void set_password(unsigned char* password)( K3 c* b1 n  l
{
) D& t5 ]# \* X( }2 u& n   char* p = password;- N3 |/ P' S! ^% f, k
* _, ^- ^7 v  s4 I5 e, k; L5 Z
   if(p == NULL)2 a8 p( \( [* K- |4 ?. k7 [  j
      return;
- L! _2 Q: G) Z/ |$ h! [* g2 J1 ?3 {5 x  z+ j0 A; |5 a0 }
   wait_input_empty();% e' A  u2 f/ C0 `) V
   outb(0x64,0xA5);8 C9 Y$ v0 \. D6 s8 {
. {( c( q4 l6 \: w
   do{% f" k- b/ X5 m
      wait_input_empty();
& w. t. {) h( P! a1 S! N- A      outb(0x60, *p);
: z4 w4 s, x; f   }while(*p++ != 0);8 x% q; x# Y6 \# C5 Q
}
( K. p" L/ p, T* d1 v
/ h2 G% I" e, l    * A6h+ z! I1 q3 _* H; |  M

, ?) \) }: `) t: T让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。) |1 o8 `0 K* e
void enable_password(void): h4 K$ e9 W4 d
{. ~% I8 o, d( j9 s
   if(!is_set_password())# f7 v7 J$ h% J* p
      return;* v* z2 h2 l: m9 h  [" ^' [7 ~3 L
2 ~( v3 p2 Z2 U. P; K" \& I5 R
   wait_input_empty();
) T0 B4 j) V+ a   outb(0x64,0xA6);   ' e8 m  G& K3 Y* ^; Q6 K
}
8 u! K5 r9 O3 z1 U& g4 \( |; o6 H4 ~9 o' T5 k& {+ y1 ^! y  @. q% R
    * AAh. a7 E. S3 M) d3 H
8 A3 w: g2 W8 x
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。  c' A0 {% X) M2 C4 z
" L* ?; R' @* E/ @6 q8 Z4 s+ Y

5 ~1 F: O4 w7 z) _; P0 E0 jbool is_test_ok(void)
. [- t. D2 u9 ]0 r8 G1 \+ a9 u{
  q6 ?  I0 A+ c: d" T' `   wait_input_empty();
$ \% E* w( I6 E   outb(0x64,0xAA);
2 }: X9 F* m; K4 S" l7 E
5 ?& @3 S: L6 p! g3 p( Z) @* ^% N- t4 M0 r% d
   wait_output_full();! h! _( O/ [9 n2 N/ k
   return inb(0x60)==0x55?true:false;   
+ s- ?- k; r6 R( H, A4 y/ E* l, D1 t7 H}7 v4 L, {% Q2 e. j' J' k
8 l8 G6 P  @9 c: v

' P( F% U3 G7 R; u* @6 A    * ADh0 H7 c, Z4 B; s# {6 w
1 @; T  e; M) D( z% R% K
禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
1 |% C  T" J* A# X7 `5 Pvoid disable_keyboard(void)
9 b5 z# L$ ]" ~8 W{) o4 l( p( ~& ?( [/ K+ F8 R9 s) W
   wait_input_empty();4 q+ c: H" r) N& s
   outb(0x64,0xAD);5 ]( Q$ o  p1 c# C" _9 i+ |  E
; o/ V$ v! U) ]' }
}
- R6 N; V& k- h2 q! H, }, d
$ a, B$ z# K" _6 p# W; F/ o) M* @5 `    * AEh0 }  W& ?, f: `8 B6 C- K$ l; v

% P2 s5 C  x1 U' L4 s打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。
& _5 B. ~0 w) }# y0 K' kvoid enable_keyboard(void); [% |6 M' J+ h8 J6 ]
{- u- }5 W: f+ v' A0 {
   wait_input_empty();0 k- ~, X6 c/ A: I
   outb(0x64,0xAE);7 T: D& @( x6 b8 j8 \4 {
) C; [. ~" s- _1 M0 z
}! X3 Y) F9 n% y# r2 q
1 i) P* W9 E5 B* X2 G
    * C0h
5 D4 m: Y3 R( N: [# H$ K3 i$ k: Y- u/ h+ D6 J( p2 }! m
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。- l% Z9 d7 _3 z. Q
unsigned char read_input_port(void)
7 G0 f0 ^; Z/ U9 W4 H{. |8 {: a) ~4 c" J8 G( U) [
   wait_input_empty();  ]) x: {5 `% ]* p4 V7 u6 X& h
   outb(0x64,0xC0);' i% F, w) Y# c! ?. x, Y! f! j

) j# D- y' j9 I+ D6 V. P: n   wait_output_full();
4 P/ ^' I: b$ n% k6 a3 B/ o' D5 g% }$ a
   return inb(0x60);
7 u! b& s. ~  t3 |}8 X# {4 o+ L9 n; W' r% U" M) f
9 A, n8 \- t% q- c" d
    * D0h( C* y2 g6 q$ z( @1 F  I) H, H
* X6 f) w+ a) _! s7 W
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。; s4 N  U, z. {" {3 }, r" w! G( a
unsigned char read_output_port(void)% E9 }: n& X: p: f8 u
{
. _) f8 i7 {( `   wait_input_empty();' l* V: A! [1 ^1 Q/ e
   outb(0x64,0xD0);1 }5 U0 r# a) }6 O  Q
$ V- c: O& J. G% A& i
   wait_output_full();6 B4 M( m' h; @& c6 p8 \

! p( D2 m3 d# h* T; N+ q; n2 t0 P   return inb(0x60);& t1 [. c. u+ l5 e# |$ t- Y
}6 U. q. O/ V$ K. p$ z5 w

' v1 @  I% N( C/ m7 o( S! ^5 ]    * D1h( n) `6 t: \% Z* q: }. F! I
+ Q) C2 ^2 f' u' H. n6 H: m
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。
5 H5 ^0 h- y5 v5 x, d, q5 v" Ivoid write_output_port(unsigned char __c)
3 {# O# Y5 ?; L{
6 }0 n/ ~: O% j   wait_input_empty();. E1 _9 ]0 T, Y$ P, p( {; U1 X
   outb(0x64,0xD1);
- h% z, m5 S0 g3 i1 g  d( H; q7 I0 x0 j+ ^/ `% L0 @
   wait_input_empty();' M7 D, _* d# c7 I9 l
   outb(0x60,__c);5 ?# f' J8 y. R0 r

9 x) d/ |' u9 s/ Y! G% s}
' w/ m( G" f- O4 [
' s* J$ f/ |: l4 m1 H9 j
2 _9 l* d, M! W- ]0 s4 k, k    * D2h
: M+ f5 j4 V8 J, u0 u7 W3 f$ [8 Q: [+ V& O& v; t5 W4 @
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。, d2 e, Q9 w+ M. u# k
void put_data_to_output_register(unsigned char __data)
6 b4 |/ e9 x) h/ q7 ^{
- V/ H/ _  h- A" Y) K   wait_input_empty();
) V0 x2 W6 ]  `0 {   outb(0x64,0xD2);
, n4 Y+ t9 T" t' K$ N( k8 N& R/ j
2 Z+ @5 g7 V  q. E& l& \3 g  D( p   wait_input_empty();
5 w! Y- ]& H3 d   outb(0x60,__c);1 b# F- p0 _5 b- H6 e( U
}/ X4 N0 e' v1 @) a
( h5 b0 N+ P. H! h. _
4.2.7.2 发给8048的命令) m3 Y" u; J! j" t% |9 A
+ A: |! \1 n( b  R4 v* f  @
1 n; p% I+ U. {1 ]1 V/ [7 f5 c
    * EDh0 x/ s& G7 _$ c4 X; j

: q$ o, p/ [3 R, K设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。1 s* D) ^; k8 n3 q! ]8 J/ d4 w' ?

5 o4 A* \3 }' O3 k4 t/ p    * EEh
" T; ~$ _. _# Z
9 U+ [9 [' A/ D$ N7 o' v诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。1 c2 l( _1 n# ]! y

7 W+ D% J9 {/ |# T9 a+ U/ m7 X/ x    * F0h
( k! n2 d. e: d" `' y# p
/ M' c+ [" x6 P; q3 ~0 U选择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代码所要求的。
" W3 K5 i6 x/ c( X; t, v. D. H: }$ [" X1 q, l5 C( @
    * F2
' ~. h7 ^- U# B6 }$ ~' ]( B" O/ ]  O9 t
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。* R! e* d2 d; v

& I6 |. V$ T5 b    * F3h" o8 M/ B0 ], F% @; i5 Z
, P: g" F2 C0 z7 Z" V
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。/ H; L2 t) e0 p# b4 ^

$ ?3 m1 P7 Z7 e. o! Z" o    * F4h
4 T5 F! g9 K+ I( w6 E4 m  y* q2 q+ w0 {  a" P7 \) \: n2 G
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。, C6 h  U, F! o6 ^  v! `

" t& ]* @- s/ f0 e    * F5h
7 r# R9 b+ L5 s0 l
/ O7 g" x% O6 t$ ^6 p设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。& @) i+ l; @7 U" N  j! k8 ]( e

) j. J& u+ N0 h. K    * F6h0 K' j( P9 L7 x

* G- x/ j4 P0 h/ g$ b5 E设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
& g) q0 d: N1 W- P7 v6 @
4 `6 H1 h& Z6 i  P    * FEh
( G' u7 H1 A6 C1 y8 w
) i* q& T! L' y' ~' Y- O6 j' YResend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
) f+ W7 K, O" v$ n$ B4 f7 L
. P" d6 {3 {$ h" G+ K% T. U& W1 W    * FFh5 Z2 g, F; F) `5 t' T  V

8 j. J/ R2 E1 y/ v: C; U7 Q8 wReset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!
5 @/ h. b  |  g$ y3 t$ C! G非常详细!( h6 O( e& h8 f
谢谢!
回复

使用道具 举报

发表于 2009-2-25 17:37:28 | 显示全部楼层
2楼好帖!在helppc的Hardware Data and Specifications栏里有相应的寄存器和命令详细描述。
# l& H# Z# F+ B+ h7 n; H4 d0 {/ H6 j' w9 |: _, E
我的问题是,上述描述应该是针对老的8042的,在目前的使用EC的系统中,这些status register和command描述在哪个文档中可以找到?比如intel的santarosa,使用renessas的H8s 2104 EC,按道理上述状态寄存器,命令等的描述应该在2104 datasheet里,但是我怎么找都没有。还是有某个spec定义了这些命令格式?新手问题,高手莫笑
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-12-13 12:31 , Processed in 0.055000 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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