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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上   3 x! s) C1 G1 R( M9 b$ i" k

+ R6 ?6 V5 ~' J5 s2 ^; ^. B. Q9 _" Z4.2.7 Command
3 P4 _. y9 T) o* D/ ~7 t
$ n% y# j% {3 H6 [% a+ h通过8042芯片,可以:+ G/ k2 f7 ~* R. c* j" D
向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。# C+ K8 f: y1 H9 h  Y
读取Status Register的内容(通过64h);1 [( W/ @; z0 N0 n7 q; @  n, z
向8048发布命令(通过60h);
9 L5 [0 @4 [0 |# A1 M! t: E6 v读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。2 t& S! w" Y* E- Y- W

. ]# X" K4 v: l0 G8 j1 ~再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
! R5 V! q& |/ W! b1 S% i- K9 m, z( [8 N7 g: Q# w
- a3 W. Q  g: I5 I% K
! b9 }1 }2 C* b+ |  `2 y& X! q
    * 64h端口(读操作)# ^: V. @( l: t' Z- K
5 f9 \. D1 `$ m; R' J
  H; ?! j) L0 {8 ~
对64h端口进行读操作,会读取Status Register的内容。
) h+ r( m- \! T1 B4 X- g4 Q; ~. R1 V5 F0 r. _( }7 d
inb %0x64
9 Y3 C7 }( c* r7 ^  T. G8 @6 R7 F执行这个指令之后,AL寄存器中存放的就是Status Register的内容。
5 {" c8 z# Z6 c1 p0 A1 n! P+ P# B7 p! [4 p9 J
    * 64h端口(写操作). O& ?' B+ l" {" z( z' Z: r

1 [. ~6 F* s7 Z* N* M向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
0 H/ [# }; X9 [, D  PŸ
* N  N6 e: M7 V+ a* T写入的字节将会被存放在Input Register中;
4 I. R: [4 C" h/ H3 I  n8 c1 Z2 GŸ* u' g( c  n5 V) V+ J! t
同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;
+ p9 s; g$ A$ M5 u9 l/ t3 NŸ2 T4 P/ G4 N3 U( p' p
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;  E4 s; f1 e# I, B" I5 k( r% A; i
Ÿ7 M+ v7 F3 E8 y4 h; d4 _
在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。% I& y9 S0 ]0 K8 V1 Q9 s" s  J' {
8 Q' P- f- l% W" P3 d, f5 Z% \
void wait_input_empty(void)) y( f4 ^. S' ~: A1 _) l( u
{$ \& q- e$ r: U+ a- _9 p4 B/ w
   char __b;8 T7 Q' }* O% L* N9 y/ k
: c) x- V2 e' s& ~
   do{9 N" v) ]+ B0 B( U5 I% w" _
     __b = inb(0x64);( o8 m# e8 i" e+ u
   }while(!(__b&0x02));
) U; Q( Q) M8 h3 k}+ `/ M) @2 O2 D( k) Z5 P- d0 @2 Y
7 }0 x  r$ |3 \7 N
void disable_keyboard(void)
$ h7 o  l9 o9 G) e* C$ ]{6 r8 q; }5 V# l2 ^
   wait_input_empty();
2 D% G" k9 N; s. q, n+ L   outb(0x64, 0xAD);
  B( `  T' E# o" I}[size=+0]$ S" J% l  a$ K7 P

6 d2 u( u( Q6 C* U    * 60h端口(读操作)7 Z" s, a3 F7 c( x

/ B) T! G! t4 ^, F对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:
9 p2 Q! w4 P+ o+ k0 F) mŸ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。# a: f1 G( c+ a7 R" L
Ÿ           通过64h端口对8042发布的命令的返回结果。
5 x. B! {- K6 I, y8 }! _$ R. p5 O' j9 V, B. h/ O
在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。# g1 g( p2 z/ W" `
void wait_output_full(void)
* Z# `- X( }# v{( K/ I, D) m' z4 X5 s+ L! V3 j
   char __b;
/ w7 }$ ^: d/ n, D/ {$ Z3 G2 I6 H+ C5 o! L; s1 B3 U* a
   do{+ v. o. J, e3 I3 ^9 e& G6 W. z
     __b = inb(0x64);, A% x' R6 u. d! _! ]
   }while(__b&0x01);
& q& S" |% T# ]6 s3 C  v1 p}+ _. y0 b/ ^  T, {0 W- |8 h0 C

+ _# I. z; ~% h6 }: ^# r: Gunsigned char read_output(void)* S; `: Q8 J: S% ^3 f1 N& y0 J
{
" j) X: ^. V6 h+ ^5 A9 G   wait_output_full();1 n% E/ b* E* K) p- A
   return inb(0x60);
6 Y# ]& {  p# C}/ a8 k0 w" W# i# p9 X
6 m) h$ g* X% q1 `0 r6 w
    * 60h端口(写操作)
$ t0 {, v- H! p' f
# G, E. O- W) C# X7 N0 B" N0 s7 e, h4 N向60h端口写入的字节,有两种可能:8 [4 L4 Y& O' [  v
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;$ f* v. @* j1 W) P3 S7 i  G. y
2.否则,此字节被认为是发送给8048的命令。
1 y: v. m& Q9 r6 h3 U
+ ~/ \" i5 }) x& l# ]' S4 c在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。9 s' L2 d2 @  F" B, ~/ P8 V0 ?7 T
* C7 X9 i. P$ I# `8 Z

  p9 m1 V' C5 z[size=+0]4.2.7.1 发给8042的命令
3 P% x$ R# V& e, u' C8 v+ I
" \% ~' z9 M4 k6 v7 S4 @; o! M    * 20h % |2 N9 t" }2 [, q) g6 }, s& g' [

4 F0 z  `( I5 o: C" W准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
7 D) {/ X' {6 k0 r
9 T0 @( T+ O& o  o0 C, }3 o: d
) p) l6 h1 Q/ z2 Kunsigned char read_command_byte(void)
% u5 ]  Q0 d. [/ e* f4 ~1 I! A: @2 \{
+ ~7 G. d" b# E# ~   wait_input_empty();% k1 |/ V3 s! s/ I
   outb(0x64,0x20);
0 K8 w, R* @& j: Q8 `0 X0 k& p   wait_output_full();* p9 ~* h2 M6 R- }2 Y/ y3 C6 R
   return inb(0x60);   * {! @/ `, z# [$ ]! f
}
5 L! `8 ^% ^' F* n  p+ l0 f8 i5 _  Q4 l0 Y- j* e0 D
    * 60h
8 c) F3 h& i9 l5 c5 E; v6 M( M; P5 Y% g7 \6 U# M" G" U
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
4 E5 ?( U8 x0 A2 [: _
  S* Q* Q5 ?* ~* h/ _5 @( K/ W. _' O) h  M. O+ y3 a! [. ~
void write_command_byte(unsigned char command_byte)
" _  y$ ]  |5 T; |8 s% `{4 @8 \, n( v* ~7 d/ p6 h, x! w
   wait_input_empty();
7 H) i8 r) P3 z+ w& s/ O( z8 q   outb(0x64,0x60);
& ^: b3 J( Q1 w; j   wait_input_empty();+ Y2 T& y' d& Q7 E" u
   outb(0x60,command_byte);: |' k& e; q+ O1 U5 ~
}
, S6 f" z6 h( a) u# H) g7 L) L0 ~9 h' h2 k7 l% \
* L# \$ Z  h, A
    * A4h
7 v% _# X6 K9 w- R0 {1 Q* y/ L. Q4 E# d, T4 O5 M
测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
$ |4 ~* ?+ l7 i3 _) i, `bool is_set_password(void)- W9 h/ h" n; p* g& @
{0 G( ?/ v+ g) r' Y
   wait_input_empty();7 i! E! l8 \& ^* |
   outb(0x64,0xA4);
7 C' K4 S/ N6 ?# |5 e, k% U: q   wait_output_full();
8 a$ P: Q) d+ Y' t, b# E& P) b   return inb(0x60)==0xFA?true:false;   
2 H1 ], }1 h* V}
, R, C- w- O# S7 C1 n) R, s  s5 M7 h; T# u# K
    * A5h
6 g! P: n- d( Y5 W2 r' S8 Z  s. I
设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。# l0 p. [# l0 C
void set_password(unsigned char* password)+ o& I9 ^5 }) q$ D5 |
{' @' Y# X* J: @2 t3 ?& r7 L
   char* p = password;
1 Q3 n  x7 \! b0 y7 a
* W/ ^8 U, v3 F/ {: Z   if(p == NULL)1 k( H2 |+ Z: D* m( h
      return;0 m! C( n( Z" a# J( B2 s
- g3 O; A4 T. }5 o* k& }
   wait_input_empty();
! [3 G: G8 c% n* s/ n/ j. |! Q. G. g4 W, b   outb(0x64,0xA5);$ X  ?+ l8 C2 n. L' R+ \/ {
$ g/ ?3 z/ |/ u- K! h; R
   do{$ \5 B# A+ t' l2 d7 n' e! C+ w
      wait_input_empty();, }& w) \! p& A0 n. Z: z4 [
      outb(0x60, *p);
) H, Y6 R, n$ A! N' H/ {4 y   }while(*p++ != 0);
% a1 g  _3 G, Q  q8 p" u: N8 ~6 W}0 e' c# j% @, Y/ Q" Q. N/ N6 E
+ ~( j% j( m. i% G$ ], A
    * A6h
* |3 \# h6 @  X2 S' b
4 ~5 e' m' ]/ s) v让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。. v1 I# b" T' t
void enable_password(void)
2 _1 ]3 n$ \2 P1 S{# N: m. ~7 n! J$ t. V
   if(!is_set_password())9 L6 B, u4 J% C% g2 y  u( b( _% C
      return;5 K$ q1 a( r/ u1 _

. @5 g7 U0 q; h8 S   wait_input_empty();
# J9 H- T: v2 O1 x; ^" h! b   outb(0x64,0xA6);   ! c$ Y8 @+ ]% Z
}
1 h. I1 y/ `' h- n* K$ U/ m# `7 r! B
    * AAh6 T1 \! [) k" I2 i  x# {- V! S$ g
5 }. Y: x! e( N! u5 }
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
" L0 \4 L1 j8 a% f6 w& D* r! x. R- o3 g) V! D" d9 O$ s5 A

# l; y. P( i2 y3 p# U5 V1 y2 O* @, Nbool is_test_ok(void)
, B: ]$ S' G+ P{6 E2 z9 j- A1 y: {3 R
   wait_input_empty();( e- P" Q2 G( a% J
   outb(0x64,0xAA);1 @' B. b# [, Z/ u7 y  b9 W5 T
3 A* G1 B& Q6 }0 g- E- S
( H( P8 ]& Y" n8 ]
   wait_output_full();
: Z- V% `  F& ^& ^   return inb(0x60)==0x55?true:false;   9 u) X' ]- K3 y
}! q8 \! t- ?! n7 q

) O4 O( @6 U( a, {
' h2 R3 |  Q( e3 _* v    * ADh, K( O+ a9 r9 V) u8 V& f

. K* J" Z5 [( Y3 s$ Q禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。3 B/ F3 [7 h; W5 M7 w
void disable_keyboard(void). ]: U, S+ l6 x0 J! x1 {- n5 M' r
{
: Q" V; @2 _- o, T   wait_input_empty();
+ z9 |- ^, o( Y0 ?: z& F   outb(0x64,0xAD);
2 U  k7 u5 g! U6 T3 u& z$ C  j) E1 R3 m; U. B& Y
}
; ]# L' v0 Z4 K+ A. ?8 p
1 `5 A) h) a6 |2 @# K4 t0 |. R$ [! ]    * AEh+ }7 q1 W) I0 i

, \  j/ r! [2 A, `& T) i" T打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。
# F6 M2 k! ?  W' hvoid enable_keyboard(void)
+ ?5 ^/ G- I3 O1 ^, b- U{0 M2 D) P8 I* y. @
   wait_input_empty();9 f4 P# r6 P. {% Q+ F; E. X& W
   outb(0x64,0xAE);
5 x! w, D* V  U1 X* |3 X, c+ o# c9 C  F  y3 Z! x5 }
}" `; j: ]4 Z& z9 {: P9 K

5 W6 X8 n0 m, [    * C0h
  b, S3 o; D9 [+ O- W+ p% [+ \, T. t7 a5 a$ E, r, T
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。! ~% W0 j) J0 y. T2 r; Q
unsigned char read_input_port(void)
2 s$ `* Y& k" ]* @- `( b: U{
( i% B6 S2 _$ A' m$ W9 m+ J% u   wait_input_empty();
6 w8 l" ]2 c. L. g" V, _   outb(0x64,0xC0);
5 N3 o: I; ~6 _! d! P' x9 z
, g& Z" S  q- z( A; }! M0 F* ]- I   wait_output_full();
8 W" Y3 {' }$ E4 ~  y9 @
- w8 A8 L% x$ q$ ]. M   return inb(0x60);
4 D  P8 ]* v- ]  ?}. x8 Z# @* o# o3 S
- {6 D$ E# f1 a+ d. G( V
    * D0h
! W; f9 O& Q6 Q/ h2 C7 e0 F+ ?3 I. m9 h; f
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。4 k1 J- w! ]/ p: A
unsigned char read_output_port(void)
* _6 x& `  p% [% V) ?8 y{2 ^4 m" z9 ^* t7 P' k
   wait_input_empty();& r- V: l9 B3 ?2 }( {
   outb(0x64,0xD0);
3 V* F& R. d  r( g3 Q, z# W' C: k" E3 U
   wait_output_full();! u' B2 {6 u( h. w5 \" I+ e
1 r0 k* u4 p9 K+ k( C0 ~" R+ H% M
   return inb(0x60);) |9 F/ W& j" L
}* W- M& v  A  s7 d! h9 N+ J
2 B/ B7 Q' n4 Q3 c
    * D1h
! ~: S' t7 d$ C" b; V& `9 k+ F' L0 p/ q% h2 T) t9 A$ K
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。, S' A$ L/ M$ {: c# E5 c
void write_output_port(unsigned char __c)
% G* f* u: u9 m$ b$ b{
; q% d% w1 q% T" j# f9 u- }9 x   wait_input_empty();1 J0 T6 h+ ~5 b# X0 F# g5 a" y
   outb(0x64,0xD1);, o- h! J7 n8 ]; C% y+ X9 _6 D  Q
" C9 \& }' H( F
   wait_input_empty();
$ `' b# o# `- ]& n1 y# j   outb(0x60,__c);
. H" r3 g$ s6 [
( D* n, F1 Q- e- I( q# q$ E, I}
) Z5 Q! n9 o& c8 G5 t7 k" q  |! }% @5 `" p
  |; X7 `' z; R; K  g
    * D2h
4 U& W  w4 r* e& z; q$ ~  o, F) i  l3 s# ?# q  `
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。
0 `$ Z7 N4 N. A* `* k, `# \void put_data_to_output_register(unsigned char __data)/ g. _; \0 Z! |& j+ P
{! ^) k% g4 Q6 `! e9 f
   wait_input_empty();1 o7 n0 \. \9 D2 _- o, J9 j
   outb(0x64,0xD2);
7 |& j+ v" g5 F3 H4 ?/ ?
+ Z! y8 O/ ]7 Y6 R3 Y   wait_input_empty();
6 \+ W$ I3 d1 s1 X0 j/ |3 Q   outb(0x60,__c);1 H' _7 g: \: A& t9 I, [6 q
}: ]3 G8 r' G' @( \

0 c6 k3 ~. G, U! P* q4.2.7.2 发给8048的命令
( P% Q. y0 i4 A! U
; z! T- Z' i2 ?; s* F+ c. {+ {5 L9 l
9 T. F3 P  k9 i6 ?/ `4 A    * EDh6 W5 n# k3 L  ]
, J0 p* c* @+ R: ^
设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。& u2 u$ P" a, H  D6 Z8 m
" w; T! T# D$ ]
    * EEh
! }, u1 x" i$ e8 N7 N; M
1 p0 r$ z0 v, w' s" F诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
1 T& B* o* E/ m3 M- M3 {$ C: y/ F1 \4 E/ s1 P$ |
    * F0h* ^, k- [- d0 O, A' C
1 W2 P, I% N1 }9 \
选择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代码所要求的。
& G6 r$ N2 g" I9 b% u8 X: s) y$ q: T
    * F21 U" ]4 y$ M6 Q5 M7 @) @% Z) ]2 y
4 C+ c3 N1 o- @8 B9 `
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。2 X3 k, o( o# A5 I/ _7 L& P' Q
7 R- T7 i, Q% j) x) `# X; Y/ Y
    * F3h2 }3 {" X) w( e

% l; N6 c& _; F0 |( N7 X/ O9 W设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。0 O. J; @  d& W$ H( R3 Q2 f
2 S5 `  I% g9 u/ f6 R" _9 G
    * F4h
* @* N; U, g/ F3 P+ N& a
* g( u+ K4 k. K$ Y0 [3 W$ ^清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
, t& T& q- w  d$ G
5 D# R+ N' ]! v6 O9 ~6 W    * F5h3 }; r( t) R" F# d3 C4 o
, F: u" z2 Z- H. H0 j/ L
设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。
) G+ v3 |- x5 P3 G- z* x1 y" W6 C9 q
+ Z! @# ~. j' B# T    * F6h
$ t7 G1 Q" z; C3 z/ Z1 L
' Q+ c9 y6 y6 F' {) h: _设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。" Z8 E- Q- ]5 i1 M5 s
. W  s( d  r$ ^+ v. c2 Z. y
    * FEh, a) y8 d  k4 J* _+ M2 g; Y& Q

  N+ d! b2 ^: c. d5 W: j2 \# Y6 [Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。: V* k: o7 b8 ^2 x+ P+ y# R
& F+ Q# ?( i( d" M5 ~$ Z  E: t( I
    * FFh4 Q; `$ l3 [8 r

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

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!. P8 V8 m9 G+ b+ B
非常详细!
* N! C5 B+ x* R2 M: ~1 U谢谢!
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-5-25 14:35 , Processed in 0.209078 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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