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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上  
8 k2 Y" D4 g* D' `/ B2 V
4 v& Q% G8 R' l  L- N+ O: @4.2.7 Command
3 b2 a/ K6 r+ _3 ?3 p" p  Y! l0 Q$ `& m" C
通过8042芯片,可以:# u; D8 V! W5 s0 @  _
向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
- E7 _% j% C- S2 k* t读取Status Register的内容(通过64h);
& |0 {# N1 m* {7 O向8048发布命令(通过60h);9 u8 a. v, b" ^
读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。
" L, E5 t# _# R. ?5 M  Z" W. G, y. B6 F0 G
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。6 z, ^' n- o+ I. g* `4 ?- g

3 b& O7 Z5 Q3 R
' u1 `. J0 K  f+ |  s( R0 V! W2 \1 q7 w( x/ h) U/ F9 P
    * 64h端口(读操作). N1 [' ~6 h: n' F
% d# Z! k4 v( e# @; {! M8 E

" {  A8 c- P, @对64h端口进行读操作,会读取Status Register的内容。" Z' L- A7 }9 h
/ Q4 p( q. p" s% E5 s/ z
inb %0x64
) f* M0 d4 N0 y8 o* A) A5 Z& K执行这个指令之后,AL寄存器中存放的就是Status Register的内容。
+ [/ N( y1 A/ c  x6 C& g) p( c& V% J9 a: Y3 A
    * 64h端口(写操作)# q: }, w' y, t: C- a

' Y% H% b$ S7 b1 t3 A7 Q  c- k向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):3 R( ]8 ~: n7 O$ Z% r
Ÿ) c0 i6 d) X  A1 U* N' _
写入的字节将会被存放在Input Register中;! P) i% A2 S  e% z: \
Ÿ
4 `( `! {6 ^4 Y# |同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;
! K. h4 P( X3 o: p% K+ y; vŸ
- d4 V' K# V% T4 C+ \$ ?( n3 m0 h在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;  A4 _3 w7 z+ S2 t- a0 l
Ÿ
. m% s# I. W1 c- K2 h& k在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
* r; H, x9 m" a0 ]$ s% p; X
  n+ Z1 F; i" p* i# h* s3 fvoid wait_input_empty(void)
4 J! |  q2 r9 N6 h: `{  n1 @$ B' N& v" D0 L
   char __b;
9 D4 H2 z6 X/ Y
. w3 e1 L$ R: B# q! m  K   do{
: o4 v7 S7 p9 |9 r5 a8 @     __b = inb(0x64);
0 B2 k# X1 ^8 Q4 A" Z% Z   }while(!(__b&0x02));9 ^  ~5 l! e, H2 j, x0 {
}
% q6 C  x$ q! ?. y- o: @- Y* u' r& L: f- U
void disable_keyboard(void)
- y, `0 ]# r  ?! Y8 }8 x# H{- [1 k& }) y7 p' @. G( l
   wait_input_empty();
3 G* z9 w' v) p9 j3 [! ?   outb(0x64, 0xAD);  i+ ^5 f  y; U7 G$ Y; [
}[size=+0]6 |: W/ ?5 F- \; P7 m& k* f

2 O) p7 U4 u1 d    * 60h端口(读操作)( Q5 v4 [6 Z' b+ i: x* k: Y) V

& k* F+ g6 f) ?; I1 e, ?1 i7 z对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:7 X/ e* b' W" C1 q+ f
Ÿ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。# f6 z- A% i$ T! `
Ÿ           通过64h端口对8042发布的命令的返回结果。
1 D& v% f+ z5 q+ g7 ^: L; z8 _6 @2 f/ `% ~* E  A
在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。( J0 h. I/ O7 h) b+ B8 z. }
void wait_output_full(void). l- K& B7 u; j$ Z9 Y
{0 J7 ~3 ^% S* j$ ?: Q
   char __b;
. B, W2 L4 `+ {3 O$ l2 J8 p" C+ k( f* M3 d! E4 h5 s
   do{
; y7 J7 A+ S* H5 j( `# U' H     __b = inb(0x64);
3 T4 W6 j- x& h2 n+ B   }while(__b&0x01);5 |4 I( O' E% S0 c) D, l, d
}
; O& S+ \3 e' k- I0 ^1 y) ]" x: e/ H
unsigned char read_output(void)
5 J' ?! b# a" N$ j{: G1 W0 H$ v! A* Z2 O& M# _
   wait_output_full();
# B6 D: p% z. M, y3 q0 w   return inb(0x60);7 Q; z6 G& i3 O" J  S  P
}
4 q4 h4 o" R( {9 s) K0 m* |: G# \; ?
    * 60h端口(写操作)
/ j& u$ j) V( Z: _5 X% x, J' B" q, x9 n, A1 I2 ]
向60h端口写入的字节,有两种可能:5 G! [4 H- c$ w7 |- m# W- h
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
/ y7 y8 ]/ a8 n# B8 g2.否则,此字节被认为是发送给8048的命令。  d- p+ K9 N" P
9 ]  L7 g1 ^; Z' H& @
在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。) i" s7 W& y$ }* n3 O
* B$ b/ b" m. }$ R

" z; [0 S0 }5 ?1 O5 r[size=+0]4.2.7.1 发给8042的命令6 [8 M, y; `. o$ F9 \! K2 y

2 W4 Y+ o3 D3 \- O2 I  U  U: R5 ^8 z    * 20h 7 g! `. r# T* m0 V) J

0 A4 n  u$ E, _+ t& S- u2 f准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
6 \3 d1 R3 y: ^0 C5 J* }% b6 w% e
2 O: I7 l( O/ H+ i6 i7 U6 O0 S
- g( M# X& v$ j9 hunsigned char read_command_byte(void)7 P8 C4 v5 T$ l. [1 [8 H2 G3 g
{. A4 ?/ T# o! N
   wait_input_empty();
7 w  \+ i- }" T1 i/ w& d6 K+ [0 \   outb(0x64,0x20);) j, [5 o. G2 \" M- W! ^* B0 F
   wait_output_full();
9 ^* ^2 }4 X5 i$ x" u, ]- Y* J4 v   return inb(0x60);   
1 ]9 Z6 d5 g7 S3 G; x5 i3 {/ n}
" p% r2 {. K+ N. i, j# j4 n
, z: {; v0 J4 C: K    * 60h% O" L$ q9 Q" o6 @) ^% p/ o8 v
) q$ q0 b1 X- R9 l: e8 z0 }5 v% h9 P
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。% V2 O: f4 c4 R1 z0 P4 y9 C

5 W( U, K" H, k( a7 B
& o" X. X  t; ~1 g( Gvoid write_command_byte(unsigned char command_byte)
  c, K* R- }5 a* C{
1 K8 {4 d1 S, `0 p( s7 d' U   wait_input_empty();
0 @: o6 v5 H' h( Q& A1 k* Q7 v2 g   outb(0x64,0x60);
# ?6 n/ s& _" x   wait_input_empty();
+ x% |) k9 C1 T   outb(0x60,command_byte);
) J5 K4 a( g+ H0 h7 [8 Z3 x3 {0 J}
7 o8 V9 G% l5 x' q# R7 f5 X# f$ H. H( r, X
: i7 B1 V1 ?0 i: }$ Y( x% W
    * A4h
5 w, t5 A# i# ~8 O$ B  b& T( n& S, I7 P+ f' y
测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。, ~7 |1 e0 L8 h0 Y
bool is_set_password(void)
( @  u$ Z$ s9 N2 f{
, X# N% T$ @$ c7 r' L/ V( [, g   wait_input_empty();* H7 s, R6 z. ^. c6 j$ K
   outb(0x64,0xA4);
% M4 E) Q2 B1 h3 {; {( D   wait_output_full();
1 ~6 E3 z  x8 C* u; p   return inb(0x60)==0xFA?true:false;   
, ^% _) K# C6 o1 d5 i. V5 F/ O$ q}! b$ [# ^3 k; [+ u8 P/ t
$ [) M1 ^3 L, T7 Q& J% G. z
    * A5h9 ~) g+ ?2 I( K

8 K) l2 Y" N/ e$ x, A- X. r设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。1 k, ?' o! E) Z5 ]! f6 ^* Z) o  Q
void set_password(unsigned char* password)% M" l6 P6 a, M! j! S
{
0 R. D" z- t  c1 d3 ^8 J/ J, Q   char* p = password;
$ G, ^/ i  q. |: Y  F% D! O* y. Z. ^  m' N" S3 v& G6 ]
   if(p == NULL)
0 _) e- m& T( q      return;
/ R( E+ m; v0 g0 f4 l& }: N' |- S6 d7 ^, \7 f3 i3 X$ U! J
   wait_input_empty();" \* c9 {% D5 U3 l% f. n; c* C
   outb(0x64,0xA5);
2 v6 _+ X0 s5 X! O+ O8 ^( A: n3 E  n0 L, X+ D
   do{( j, {3 A8 R5 o" r9 |' `5 l* S
      wait_input_empty();
1 T' v# y, v8 v2 f      outb(0x60, *p);# k( h& p  Y: V5 Y
   }while(*p++ != 0);, z( D$ B) i% b* }( `3 e$ h
}* A2 c! t/ I' s7 _1 L

  a  h% U! r% u9 ^    * A6h/ `& E0 L0 V8 I* g3 a; ^  [
2 a" g0 U) }: J5 ]/ M+ U5 V
让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。2 E& o- @; G, C" W5 K
void enable_password(void)* B9 J3 Q/ n& f& X% e' s
{
8 H2 C* g3 k# e0 a/ x! _# k2 C# P   if(!is_set_password())
7 r& m! X" b8 Q/ B7 P      return;, e# n6 Q! g% d7 n3 Y, O, b7 |, ?

  D9 G. |; z7 E$ C- d& s8 U   wait_input_empty();+ r9 A/ i- M; E" s3 [7 g: h
   outb(0x64,0xA6);   
/ l: P, ?; l$ t4 c}
) h- n1 O7 p4 [0 w3 l
/ h, \2 j- a7 `# s1 I9 o+ y    * AAh
' N/ E0 D7 J7 ~. M! {, ]3 u3 _. O- L$ e
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
. [% ^& B3 \1 Q  |& V  t# `. e( @% ~+ l

, a! b. ~1 C# Mbool is_test_ok(void), G+ M% L9 o, ]. \, m7 A+ B. f
{
; x$ A& k  J; B   wait_input_empty();
& M: k' W7 U- M3 E$ {. p   outb(0x64,0xAA);% d8 q7 [: |9 N$ G/ o: q' z3 [
$ n& C) I0 G" I% C
% s. [5 N. x' X. k! q4 j
   wait_output_full();) {/ R7 _. l! Z3 m. U- @4 O
   return inb(0x60)==0x55?true:false;   
8 N$ q, n( e1 g3 N. o}
0 o( A# g0 w5 o5 m/ v( Y. ^1 C% {5 p. \- p5 y1 G& C) L: B
6 O5 O' b1 h* z& V2 \! _
    * ADh' x3 w2 }# D5 v3 j% A: H4 l

+ H: L7 g  O' Q0 l4 b) Q: C禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。- K) u& V, l/ }% Y3 v; Y
void disable_keyboard(void). Q2 ~( J' n( T6 o# _. }" m% G& ]
{
6 \6 j# x: r8 d7 u2 ?+ j5 A6 n* c, A" B   wait_input_empty();9 U9 b3 D; N: f1 T
   outb(0x64,0xAD);
& A% x3 `# l6 f# b) R+ O; u& _6 Z! _8 V  D
}
% y. Z# Y0 y8 ]0 G! J! a! p: z. @5 l0 q% X. b8 m+ O& ^9 A; h
    * AEh. u4 ^9 H) q; c, Z! N

. s  K: J3 b. @! x2 T7 a" u打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。5 F+ s; a: B& u, {, l% V  I3 x' }: Y
void enable_keyboard(void)7 N) H  {4 r& T
{" C. e" @! ^! L( K
   wait_input_empty();
# c' [5 e4 t7 v7 M/ V5 \1 R6 q. {   outb(0x64,0xAE);
0 O2 a; b0 k$ w: q/ r9 i& A3 f6 G& U- J) w7 f# m
}
2 m/ _4 w' Q- A" O& r* O$ N' ]
' N: X# }' l  s3 S; w8 B    * C0h+ Y2 o$ A; a( v9 r: s0 {* C% P

9 Y$ }- X1 O: b4 z; Q9 A9 R0 U1 k# J准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。7 v% D& e" X( O. C
unsigned char read_input_port(void)
% }( L9 k. r; R% ]2 l{
2 C  r& C$ r& P; d& p   wait_input_empty();7 Y, Z7 j, r  Z6 ~3 V) e
   outb(0x64,0xC0);
- }, M* t) n4 |' ~8 _& z7 g* S- E
5 w/ `6 O' s/ }$ T( M+ \  `: ^) W, ]   wait_output_full();
1 z. u5 R+ f6 h# M) ~2 ]8 Q8 [' C. p' Z; t2 q* p; {; e
   return inb(0x60);+ _  u2 N3 q# k
}/ S2 n6 A0 e8 E0 s

% i$ E( N/ I. A0 ?    * D0h
5 P: f4 u' {( h
9 R3 K: C* [$ j: ^1 {* J! r$ S准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。6 |/ d! Q; l' ?! s8 O
unsigned char read_output_port(void)0 P  R$ L" L, D/ G* S
{" x9 p. q9 R# _# {1 f
   wait_input_empty();
# [7 [# K: H* S  F% V& k   outb(0x64,0xD0);1 A' S* }: Q  n% C7 O

- T0 m% R9 U9 R  E   wait_output_full();# s( m$ O. J9 S* j5 E: Z

7 I* c- k: @/ d   return inb(0x60);: }9 ^* p+ P$ t0 h$ Y
}
. E' R- K9 S1 b& X$ E
& Q2 a* U. H$ P& L: J( E    * D1h- g5 h( k+ `$ X6 G  W

' Y" v- O. V+ p7 b准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。
/ t( j. G0 k# |* R7 m+ E5 B6 J& n5 @void write_output_port(unsigned char __c)
! B+ i2 O: \, a7 `, k- T& }{) K  v; f$ E: X$ J
   wait_input_empty();
8 o: e& A0 @9 l1 a  E, B( N   outb(0x64,0xD1);* ~/ U8 u/ o2 f% |% g1 p! B
& X  v2 @' _% s9 C* [2 f2 m
   wait_input_empty();( J/ J3 [, a: S/ [9 s8 H8 u  R
   outb(0x60,__c);
  d3 X" b8 u# u& b6 K
2 G( G7 Y' c: @- N8 ?}9 Y0 `' t$ s" W+ q5 l

! t3 L$ i: W* d# C& `# B- e. t  E% f% M9 I. ^0 Q
    * D2h
$ Y  m8 Q/ ~3 P$ G: a; W9 Q8 e2 K9 y
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。
, O1 {9 ^$ T3 L/ c# N- K8 dvoid put_data_to_output_register(unsigned char __data)
0 s9 u6 f4 I+ D5 m! V8 ?{
, K; j( j) l+ N   wait_input_empty();, [+ o" i% \+ w2 `
   outb(0x64,0xD2);+ _; c: _5 {( ?, z. m

2 e6 U9 [# {) C& A! v/ u9 H/ l   wait_input_empty();8 s/ @2 ^0 d/ t- W; |% Z0 m
   outb(0x60,__c);  C/ m$ H- o& c6 `
}% h& i( [7 B) e; P; A  Y

5 F  d0 [: q+ B; H4.2.7.2 发给8048的命令
  P  H! ?" D# N' b. v8 B4 N0 A: W' ]; T9 y# W

5 }/ B3 W: b! ~$ ^9 N0 Q& c( B    * EDh
' y& ?" ]6 @, x
1 l7 h1 ^! u1 C! T& h" L- K设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。2 A8 I) o7 Y1 {

- L0 z# _* i/ i; o    * EEh
9 O/ H2 d: ^) t6 i" h) g3 m1 I3 a1 |% i5 M. n' Y0 C& Q8 q1 O! u
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
" c  @) ?' p; M$ A% e8 }, d8 P4 T/ e: G
    * F0h6 {) e/ r+ h! X' N5 @
: J* {6 S; M* |1 r
选择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代码所要求的。1 w. U- m! y; T, O
2 j; H: n- H9 A; W$ z
    * F2
- f7 E4 V8 G7 Z3 E, i
, z- y' S0 x2 S$ D0 p: R读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。  V0 P' t! ]! ]$ v) f, M2 G; Z) \; D
+ o/ n) D4 I/ |( |2 n
    * F3h
, j3 D; V# B+ p# Q& h& R  M- V/ T( ~+ R* ~. g
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。' X! ?" h7 t' I: i
9 f$ o" M2 |2 V0 e; r
    * F4h
. u1 d$ j. X  J* q( G& a5 r5 ?% @  O( D. Y
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
5 Y" q- s* V- ?. Q4 W% o7 j
; C, w' Y" I9 g+ I- [: y% K# a    * F5h
7 k% Q9 a6 S( F( f) l
/ N- W1 h4 ^$ S, U4 T设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。  {/ ], J" B+ A- R& K( C' w# y
% q- L; B8 v7 O) R9 I& Y
    * F6h
0 @7 ~+ g: B& T. n6 t6 i. B- M2 \9 t& U, N
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。2 T* A, _7 I7 k5 X4 U# k# _3 }% Q: x

1 d0 y7 q3 M% t6 x* t; b% M# N    * FEh6 O& U& f- {/ M0 \. Z" z" M8 M5 L
9 b1 Q& J& J3 N  h3 J- X# _
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。4 v% @& z- W- @  G& B9 X
+ V2 F" B% I$ O: T0 h5 G& m9 w
    * FFh
! c% I3 W+ V. P' p  i+ }
4 q4 Q3 u7 j* X" G- T4 \8 l7 t  gReset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!
% Q, ?' D" p! K! h$ S, U非常详细!
( N2 T/ c* P' |$ [7 R$ F) G谢谢!
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

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

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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