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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上  
, y7 B* H" Q' U7 O/ \' p& I6 T5 }
$ |0 ]( K( ~" ^; _  F1 [4.2.7 Command
  n% F+ v$ y0 G% b! J4 v: A) f/ m5 M# V6 [6 z3 q8 D
通过8042芯片,可以:
/ ~3 {9 D" l8 ~" P0 C向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。6 n" s2 d% B/ ~$ r/ z5 U1 l' |
读取Status Register的内容(通过64h);
1 y1 T1 h" \( j3 K向8048发布命令(通过60h);
# H; k- j3 I( K读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。/ p1 a% M+ b' f/ F$ `

+ T$ v4 C  C; W; o- V; y& O再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
1 n  E/ m* J( N' V7 i6 V4 a# a2 C/ a
' J1 l" V3 y, `% n
6 h  M9 l: V  k7 ?3 v
    * 64h端口(读操作)
% {; A+ C! a3 f" G+ P3 F) m$ j# Y* [6 m9 B

$ V  h# C( M3 a对64h端口进行读操作,会读取Status Register的内容。
0 y; v8 Y; R/ P1 u3 M2 Q1 G- H8 I5 ?" e0 S  t+ Z: P8 o( F
inb %0x64
5 J( l$ Y0 ?. t3 K/ S6 e执行这个指令之后,AL寄存器中存放的就是Status Register的内容。* e8 Q" x+ o! }5 j3 S" S

% \" k# {4 U& `4 d$ @$ {    * 64h端口(写操作)8 B! G9 |) N3 S7 l4 `  O* I8 \9 V6 ^

4 y9 U2 R: B/ [% [! q: }向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
, |; n+ m4 r3 }+ V6 LŸ) w3 P# [4 t9 O0 k* y  e' ]) u! R
写入的字节将会被存放在Input Register中;
) t6 C' U! a* h& p9 m# x& s7 rŸ' O6 P- g9 k7 e) a' l) h1 T+ Q8 y& l, t) ?
同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;
7 y! m, t. ?9 q1 U% [! [Ÿ6 z2 ?  g  |/ r0 g) p
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;
  o: d. ]" U4 x3 fŸ
, B6 A8 ^% T9 q1 g& l1 ?在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。5 a$ O/ ~# e/ R5 X+ j

* i  D; b/ X; s- J" `void wait_input_empty(void)
: C$ c/ K; t+ n3 G{2 M+ ~6 H. j( P3 d
   char __b;
1 O  \) t3 C2 G' l. R2 U$ l
; n5 R- I$ E0 L5 c   do{3 r4 @/ E1 C# Y& q7 n" E
     __b = inb(0x64);' k* h  N6 \5 W6 w5 b' a) n
   }while(!(__b&0x02));
& v. O. A5 q4 d( w2 U2 N0 A}
, [6 W6 Q( Q: W. t0 \3 k  W6 v1 F  s7 ~) V
void disable_keyboard(void)
7 D, ^* ]) e4 K{
  `& l& b. c9 u! }: L6 l  j3 m6 H   wait_input_empty();, V9 \( C5 I8 l$ b; S9 e
   outb(0x64, 0xAD);
" O8 u  D  {$ [3 d( @}[size=+0]
& Z9 ?# I% R) D3 V2 U/ e$ E* i
- ~# B2 @' _& p1 q7 E    * 60h端口(读操作)9 x# y5 I' E! |) ^' ~  B1 `/ v

! z2 [+ e+ l) j/ R5 d8 ^8 X对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:; g4 _0 x- p) r! \$ Z0 c' P
Ÿ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。7 W% k) [; K2 E  ?3 q3 T. a
Ÿ           通过64h端口对8042发布的命令的返回结果。3 U2 k& K$ p  y& v, ^

5 `# f; C5 [' \) q在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。
/ o0 ~, k& }; uvoid wait_output_full(void)
" m# ]' q0 [. f: ]+ Z+ L1 Y( W{
; u! v$ N4 g  T/ y6 I   char __b;2 p, v5 h3 v; f- p$ e$ x
' s7 N) b) u0 Z; R
   do{- E; B0 f: k" s8 o3 K
     __b = inb(0x64);
: y1 C1 [( H- D3 P( Q7 i   }while(__b&0x01);
! k% o, s0 l# P: ?% y}
, q8 U( T9 t: O  z4 N
) c5 ^: S" ?8 P; p9 l* g3 ]unsigned char read_output(void)& Z+ Q( A- }' h' ]: S* v
{
4 O0 h( A2 C4 P9 ?, |   wait_output_full();7 c$ v) s, p* E8 N- d0 S
   return inb(0x60);: J8 g- C8 r1 \; M5 s  e
}* T8 |4 W! w. _5 Q

% F- o" Z+ l( a% F    * 60h端口(写操作)8 L6 \5 Z3 M8 t2 j; }$ _
& i6 O7 s# Z& i0 y; @: }
向60h端口写入的字节,有两种可能:
8 T5 V& ^3 i4 b, i' D1 x% b- G1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;( A' a8 d7 y7 _6 h2 e- S
2.否则,此字节被认为是发送给8048的命令。4 v3 S% y6 A3 j5 ~

0 g" Q8 l# S2 K( g& \* K在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
7 U- R5 K4 x% l  b, t, Q* l+ I  |) C6 Z& T* {

  m2 Q" l& }) f- B[size=+0]4.2.7.1 发给8042的命令
: D) p# P9 h3 G
$ ~, q% j& x! B' H( w; l+ }    * 20h
1 X* f5 ~9 Q: w! t7 W  t2 q2 P; z) o0 ~$ z& H- q9 `% K
准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
6 ?( e' ?7 n" a. w, {' x$ a1 {6 B
- l9 u2 S. [) |' h' B
9 J; w2 [$ w% P$ }3 Vunsigned char read_command_byte(void)) l2 K( L! z' B
{/ R. ~" y1 w: I; g* U) @9 l* ~
   wait_input_empty();
  e# i+ J& i! |+ I* u4 L   outb(0x64,0x20);* m1 Q0 b/ x' g: m" S5 o
   wait_output_full();+ K; j) H3 l6 Z. _4 Q
   return inb(0x60);   
  ]3 A' [& M2 Q6 O, w" @. j6 A& {}
/ \5 E/ Z1 Z0 p& u! x! y4 O: U( @; I9 g2 O8 ^: R4 q. h9 w
    * 60h
8 F1 K! i& M% a9 o) w' \6 M: `2 O4 G1 ?% b! w( w
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
. j& k- K! ^6 B# n
" W8 E1 v/ Q* o( a" `% n8 g( J, Q) e. y. ?" C+ X1 t* l2 a
void write_command_byte(unsigned char command_byte)# x- _" W: n: Q% R, x/ J
{
( H8 }. R- w3 Q2 a   wait_input_empty();* h' h% E- c% A
   outb(0x64,0x60);2 G* p+ q1 T7 J2 ^3 i
   wait_input_empty();
9 e4 X- R8 o6 f  e' v7 Y4 V$ V# A   outb(0x60,command_byte);
8 v% v3 C6 S+ y6 B2 H}
% D; Y6 q' }8 }' M5 M8 Z
- O2 x2 ^& g# t- @. O5 z3 F( |0 _, a1 V& E
    * A4h3 t9 T, x4 B1 L* Z. Q6 V

- d% W* E' ?  U& v& Z! J测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。6 S2 ^) G8 e' @, W/ q
bool is_set_password(void)
, f/ R) z9 I0 |$ B# ^{: I% Z, W9 v0 R9 D8 y
   wait_input_empty();
! L9 Q! t7 f: j5 Q   outb(0x64,0xA4);
: Q1 K. L+ z; h' w. d   wait_output_full();
' _5 C9 f, H. T: Z! s: J   return inb(0x60)==0xFA?true:false;   . ?, s7 v6 [# A* B' j7 i
}- b1 T' x" G* `7 k, R: U* o1 J

! x5 Q4 f+ C4 V' v1 J    * A5h
+ W- x6 y  q/ W; a" [/ p
% \$ c# k9 e2 }; c$ l$ r设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。! E! M/ R3 r9 I9 C6 J
void set_password(unsigned char* password)
7 l; e0 {1 a' S. [( u{" P( k: T7 d# w# d4 T+ O5 i, n( E' C
   char* p = password;8 _, h* K# ^1 q* A( I* L* Q

, a3 P& d6 S6 D" t6 K   if(p == NULL), c( a6 ~( u" [0 R0 [6 @
      return;/ X6 ^0 n0 x# t. J# I) g* ^
( \4 s( G  d1 P) E
   wait_input_empty();
. l! ^# n' N& M) a1 Y7 N5 ^! `   outb(0x64,0xA5);* |4 X5 }3 j8 u
0 m6 p5 F3 |( @2 \
   do{- I4 F6 l$ }0 v
      wait_input_empty();
7 s6 }7 P) o1 i$ |      outb(0x60, *p);% ~- b& i3 a. f# H
   }while(*p++ != 0);
# B- [( Z( o- ]6 U( p. a}4 `- N+ J; ?  ^$ b5 m* f

- g5 \4 P  J7 W1 E. @  ~; X    * A6h/ V( F* H7 a9 |. H( x% R. a7 L% S* G6 _

: b% }$ J6 Z/ R: I" Q* V, i0 C0 q8 J让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。7 T& J: i1 I. m' G  p1 [5 h9 K! O7 V
void enable_password(void)8 R, X+ |" @4 j: x
{
/ o9 x! L. p0 X) t0 o   if(!is_set_password())
6 G$ ]  ^' H8 A+ h5 R  y      return;
, I4 z# y! Q' H6 M7 _1 v
7 x/ |5 O5 {/ F4 s9 c) D   wait_input_empty();1 ^/ [# P) R( Z& [3 C- |! e% X
   outb(0x64,0xA6);   0 s' z& Z! n' p6 r6 G0 H# |! K
}+ F9 ~8 y+ q- s2 A  J7 g4 Q

$ f6 R8 {1 r9 J/ f  h3 e% e    * AAh. z! \/ K0 P+ ?9 |. T- p3 k, [

' H+ F  F, e. {0 b2 Z  C9 T$ X自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
/ H( @0 t( C$ F; i" `1 t( V4 Y' x, {. {
. o7 n; T( g7 V* V, f5 C0 L
bool is_test_ok(void)
+ J" `( P' V7 g4 b{
4 L2 B- Z7 w, Z  @1 q2 |   wait_input_empty();  h* G$ H$ Y7 y9 C" v" `" c
   outb(0x64,0xAA);8 l. J# ]7 ~2 l1 k/ J, q1 ]

- L. o& |; A6 V; z
0 H4 i$ W, H1 W5 `" C9 B( s# A   wait_output_full();
8 u; u- ?9 {/ Q% I   return inb(0x60)==0x55?true:false;   
+ Z. M" ?; m* v* ]  v}
+ U; U3 z, k, K7 y2 l& j) a
: C/ F% r5 i5 g2 }, P7 B( E, Y
$ d1 t# P4 ?1 i  c" G    * ADh0 Q( z8 ^6 d9 @

3 o; l+ s: a( @0 B5 u禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
* Q. B- F7 G7 d$ v. ^. E: h1 O% Jvoid disable_keyboard(void)% D' ]. y9 }' g; v  @0 Z
{- {8 q2 h6 Z% s; ]1 z2 C
   wait_input_empty();' ]# {7 a( ]' G, Z/ A
   outb(0x64,0xAD);) l9 i" r' M; S' H: w9 v
) S! s: x8 P+ Q" v2 l; W! Q
}. U: `. s4 T6 [

8 ]" K3 ?& |' P4 H1 ]% K+ p% g1 f    * AEh7 K/ `! [- x) @2 p- y7 ^1 g& ]
, x1 y: L0 `, s' S4 z& n
打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。! b5 G! U9 ]6 {( Z  G: t
void enable_keyboard(void)1 _7 m" O; b; ?3 j
{
7 Z: Q; `; ?' w7 p- _* f   wait_input_empty();9 P. x: p9 U* b# b4 c3 S
   outb(0x64,0xAE);: Z; _6 Z! H! y% l. K
- n+ N; M+ ]; G* w
}  t5 r  _" n; d

+ M  h) j1 m; q    * C0h  B3 [9 {( |0 G6 q) |* k4 r

$ ?) q& A' n0 P( j0 h5 w准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。) _6 D+ o2 x6 e0 J( G4 i% B
unsigned char read_input_port(void): |9 l; v0 T; J% ]8 Y2 z7 R: \) I
{
! `# S# m3 P, \, C7 N5 |8 t   wait_input_empty();' E7 u2 L8 l4 Q8 p! g
   outb(0x64,0xC0);
6 e. P- o: g' J6 `2 p5 M
7 O" B* s. I  t$ U! x" `, ^3 N   wait_output_full();* Q$ b4 e. }( \( \1 [

( M8 R/ I) O. w6 ^7 a6 ]   return inb(0x60);
! z$ Q5 t0 U' L9 k}* z7 s7 d* ~$ l

1 G8 Z( }7 a  E5 r$ g3 y    * D0h
  j% a4 C/ k9 s7 ~
; \, @9 L( h! a) Y1 O准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。
) P6 }6 x5 I5 |  g) ~unsigned char read_output_port(void)
' x! J+ L" h& N{* c4 y# _2 ?* C/ N% {3 v6 v* U
   wait_input_empty();
+ A# V- d9 c8 k/ h% B8 P' @# A   outb(0x64,0xD0);
1 k) o* Y' P# r3 q
3 {3 r+ @/ }" A6 o4 r   wait_output_full();! {+ _/ H0 o2 G& |6 R
: p6 O3 X2 Q& c+ A5 }
   return inb(0x60);* W9 q. V+ P3 n, E3 T
}5 e- M7 a$ N0 p6 b6 i
8 F/ ^, ^1 L7 i) ]4 ~/ Q9 R3 A
    * D1h
; z3 K2 P6 f  a+ J2 F: ~* C* F* w: H. f& j; ~/ V
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。$ }5 F9 f" `! W3 u2 D$ i  u& N
void write_output_port(unsigned char __c)
+ N+ Q3 Y5 |! l6 }( h2 n- j; Z* ]{& U8 N1 `" Y4 R5 ]5 Z# R
   wait_input_empty();6 x2 I7 }/ w! Y1 W5 J
   outb(0x64,0xD1);
4 c. E' S) d, ?) ?, h- w- V% p) g! f' }6 n, m
   wait_input_empty();
5 P% H% y. ^+ u# `) I   outb(0x60,__c);
8 D% {! d7 [1 t) {: P' e; }& o: Y) _, {
}
2 r* Z' k  D! d$ E$ v, N. @' G! }' m) q7 R- |9 B. C2 K5 h' D! n

: X7 C% `/ ~# z$ n    * D2h" b: ^0 J9 b& P% S6 X! f# c  Y9 S
3 u0 O1 S8 M' V; N* V1 I. \
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。
* `* o& e  Q7 cvoid put_data_to_output_register(unsigned char __data)& K. `0 t/ k  k+ \; x/ @
{, E2 l0 ]9 A8 [8 m5 f" w; v
   wait_input_empty();5 Z! _; ~' b8 K
   outb(0x64,0xD2);& D% r; j0 {  G0 p" d1 @
0 Z' e. o! _% J  z4 Y
   wait_input_empty();
( N& s/ n& G; d* U9 S/ c4 a* ~   outb(0x60,__c);
5 v* q% v1 ]  l7 g; H7 }( ]}
6 o2 q( E1 O! [( s, r7 g7 Z+ X' T$ [: |, W* C' D5 @
4.2.7.2 发给8048的命令
" S- p% v( E6 U. h7 G) A: H* X5 r, k3 w% ?' m$ ^' R
% i8 \* s2 B, l& P& R* E5 `1 R1 V% j8 i' W
    * EDh
( g0 X: q! L# L; E  A- y0 V! d: \
设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。
: \6 H  V/ v2 @9 D8 q
# j8 b8 n( \' J    * EEh
9 D! V" W0 ^) I& B- b: f# F3 {" B. i( V: E% h9 g9 j0 Z
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
- c/ i+ ?+ J$ ^" w: d
1 s8 w6 T6 P# z# e0 S3 J    * F0h. R/ t; |. H" S" v
/ T7 K! i- G" x1 t
选择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代码所要求的。9 M! M2 I+ r9 \) d0 I+ c

5 n3 _' e7 Z( }1 O9 p& `    * F2  m3 W2 ]5 i. o; w% _/ ?& A$ G; ^
( u* i1 G" j8 O% C% F; u' c! C
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。
% {' `7 T( c9 D& `: O% g0 x
. S2 c! g1 |8 g  @  z  N    * F3h0 N' H  A; E6 _

1 D6 ?$ y# _( t' q4 |. S0 ]- }0 O设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。2 [7 m* c. }5 ]
1 @. _: H8 ]8 G/ H4 y7 ]8 Y" m
    * F4h% B8 i, P! [& Z+ z) C& b+ r
$ e8 |8 A. c! T: X
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。3 X( R- ^3 N2 D. g' {# z1 {

% L+ G$ r. E' l2 o4 Z    * F5h+ x1 j4 `' v$ H# {$ h
- b9 S" @0 |+ N, f6 D6 T9 y/ C0 e
设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。8 A" {- L+ L$ o: h3 p
$ k- L. d# c! g
    * F6h
/ q9 ?) O0 x9 i1 j0 z: l/ R' \7 i+ D1 l1 \+ e* _8 K
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
9 M& e# k, V9 X6 X4 C2 V3 L5 z; O8 h; u, M5 ^+ j
    * FEh7 c; ~9 C* n5 H3 e

; I$ ~! t8 Q) _2 _& c, @+ w9 U5 XResend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。1 W2 @0 a+ {, w8 N

4 J6 x; n: r9 e5 V, I! D    * FFh
) I& d$ P  u2 G  h  O7 N/ n
! o; g2 ]7 P9 y3 \Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!0 A* `0 x- |' I' B& P$ |+ N
非常详细!. g# {" V4 F' z: \0 O9 E% `
谢谢!
回复

使用道具 举报

发表于 2009-2-25 17:37:28 | 显示全部楼层
2楼好帖!在helppc的Hardware Data and Specifications栏里有相应的寄存器和命令详细描述。
9 R. F0 l) @" {( l# {8 a3 F8 C+ G- }2 [" @
我的问题是,上述描述应该是针对老的8042的,在目前的使用EC的系统中,这些status register和command描述在哪个文档中可以找到?比如intel的santarosa,使用renessas的H8s 2104 EC,按道理上述状态寄存器,命令等的描述应该在2104 datasheet里,但是我怎么找都没有。还是有某个spec定义了这些命令格式?新手问题,高手莫笑
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-12-1 07:16 , Processed in 0.119398 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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