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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上  
% f3 d5 O" }2 h2 Q8 c
- f' Q1 V8 y! _  b/ k4.2.7 Command
5 E! D# W1 `4 n. Z) z3 `( d
0 ]1 h3 d! r2 M6 j; G* e8 J通过8042芯片,可以:
+ |$ S3 q2 K  X$ A向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
' ?9 x5 y* ]5 a7 P" z* e读取Status Register的内容(通过64h);0 G2 c9 [% h- Q6 o( U$ B6 j
向8048发布命令(通过60h);
' l+ k, `7 W: p读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。
& e* }, f. {! a1 H, L( i4 J3 O0 t- g5 n" }; ?! D
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。+ o8 V& n9 Y, `

: v; A' w) |: b2 \
1 P/ V  O% w; v% `2 h/ s+ P
1 ]7 x) i+ ^- U! R    * 64h端口(读操作): N2 Y7 c! j% I" P) F' h

9 I- e: X# t# @! v4 e: v$ h
6 `6 s: q7 l3 V" |" Q3 c对64h端口进行读操作,会读取Status Register的内容。. |/ v, p8 V% U& X" h) d
. Y" s2 L# ?7 ]1 _: T3 a# G
inb %0x64
7 ?3 U" \* i- k. v; l+ N- V4 L执行这个指令之后,AL寄存器中存放的就是Status Register的内容。
# n/ r5 Q$ f. ?( [/ f( s6 B: t/ W" [7 S; B& f( A
    * 64h端口(写操作)
  v' d1 N( L3 l0 p" z
0 n" X6 ~, H0 D' O4 [! H& W向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):, k# E' U8 S' f" I7 I# a/ b  S) S. a
Ÿ
3 W1 ~1 d) I2 m7 t3 P, N写入的字节将会被存放在Input Register中;
% L3 J) |* w8 R/ q0 }Ÿ9 J* ?: v( ]; g7 d" z
同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;" c+ W; y* c4 T; |7 V
Ÿ
9 h0 p4 z6 P$ [4 z; ]在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;
' N0 @2 D+ B! A# YŸ
% S3 \2 g# s$ U, D  }在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
4 m" }3 v: |  V0 E  R3 X/ z2 y) [2 f1 }% G7 S% @- X: T: m  v
void wait_input_empty(void)
) `: {! `: P1 U& \8 ~{3 ], g4 X! g1 ~/ J, V) d3 w
   char __b;# Q: E! E/ l# g1 q2 T
+ G1 G. q" W7 |7 H( W
   do{
: a0 U9 Y! s8 e6 Q+ m* ]     __b = inb(0x64);
/ o, b2 I( K7 l1 y8 P6 m  w4 d   }while(!(__b&0x02));
# Q+ Z0 c+ ]3 D( X}
4 g, E7 Z  E/ X* o# x+ |
7 R, p: ?: o; U# p* W7 v( @7 Ivoid disable_keyboard(void)$ |0 N+ z: X( S6 g, R
{
8 Z1 N" E; [* ]+ Z7 Y! p   wait_input_empty();8 F7 H! m  C. h% ]8 N
   outb(0x64, 0xAD);
# h* u1 \; F1 \6 n}[size=+0]
7 W% F) L& `7 h3 d
) G6 v  w- Y) v5 A& g/ i6 S# Q4 C    * 60h端口(读操作)
" K9 v6 e# z8 |' R( }9 f( p8 R8 a* O- B& _& \- X
对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:! N1 c8 G* Y+ |3 {
Ÿ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。2 N8 ~6 |  m( c, Q
Ÿ           通过64h端口对8042发布的命令的返回结果。
+ Y6 [* b6 M' M* a2 P: e6 v" K# t8 C9 w! |# n% K
在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。
5 g" A1 S4 k/ Mvoid wait_output_full(void)3 w- I# n3 @( N
{, @8 I% d3 i4 o" ~6 {% d
   char __b;
" J0 n; R6 G  O8 H$ n, C4 W, i4 H# O+ _$ W
   do{
$ Z& C4 ]3 @: g' [$ h# o     __b = inb(0x64);
" |7 d# g* B+ N# P7 G   }while(__b&0x01);; l, z3 D  Q, @2 k3 G. X3 o6 Z9 u
}3 |. `3 ~) ^* l8 u0 I0 ~
" s! L( M3 C; u4 C
unsigned char read_output(void)
9 t9 K5 n! k) m/ e& H7 B{
  k3 ^2 y% a4 m7 s   wait_output_full();* S- @% {1 l$ Y/ E
   return inb(0x60);( M2 _3 T, K6 ]8 H
}: L9 B% V: D8 g  `% Z3 ]! ^5 b7 m
- g* R& _: T) h' c) [- F, n5 o2 W
    * 60h端口(写操作)
5 z. ^6 y/ }- @, D. R7 K' E4 H" `) B
向60h端口写入的字节,有两种可能:: P* c, {/ x, r( ~8 V
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
9 Y9 S/ t8 O- k/ n2 e. u. Y2.否则,此字节被认为是发送给8048的命令。' {5 J7 N9 a" k5 c7 C
- C+ {% B) B, v6 W/ t: Q. F9 _$ B
在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
' h  O' ~/ ?$ f$ j7 \7 _
* r2 d. t( v: C8 j- T
; ~- |0 `! h+ V, m' V2 t/ i[size=+0]4.2.7.1 发给8042的命令
; Y  ^! l' S. N+ F, N$ Z7 T, `$ g1 n9 _4 T9 N: W2 i
    * 20h
- @) F5 W5 Y0 _% h6 S
+ }0 f. j' e9 V$ W! M$ n准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
9 P& [, J0 V) Z: v3 ]; g
! k* S, |9 @: w6 ^' v/ `5 j9 d. b% ^
unsigned char read_command_byte(void)
4 c0 |6 y. V# x& W{" C( h6 N& h% g
   wait_input_empty();
7 c0 L, _& B# o; Z   outb(0x64,0x20);
0 G0 g( K# A9 S7 l! R5 D' _   wait_output_full();
& V4 W3 |! r7 E  G; Q1 X, P   return inb(0x60);   
- T) l# T9 K* c& J- `2 n4 F}. M1 [3 z* ]+ q8 W3 q" ^  ?
. f) S- \/ ?* R7 B
    * 60h& J9 U" P' I) K, c( l
0 h  w% d6 Q! S6 E, t( |
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。/ [4 R( {  o  f; U6 |- Y' h
. v8 e* s5 C" |$ U  v% D& ]2 ]

1 E+ j2 ?2 w& R# Avoid write_command_byte(unsigned char command_byte)$ {) L7 T: a' R* ~" X; |6 `
{/ f) O0 a( ^6 K' L" v" R
   wait_input_empty();8 n+ T( |. ?  n$ }" p1 a' \
   outb(0x64,0x60);
& [9 F0 u/ y) y" k   wait_input_empty();
  C1 O$ T* R( e; Q- A% H   outb(0x60,command_byte);* \2 |. x6 |" M9 D& [
}
& Q# }4 P; {- [" K" b( }) h* f5 o% Q
/ K2 V1 v6 f& L3 T& m! n
    * A4h% V3 E0 z% R  S: D

7 t9 r6 C0 V: h. X5 q. n测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
7 r/ q/ [4 u1 ^9 r+ z6 s! W1 K+ J: cbool is_set_password(void)
, \# G' |( @* C( Q5 l3 {+ K{
0 `6 z5 B* W* ^- S  e, \   wait_input_empty();
6 v0 q/ S* o* B# r7 O   outb(0x64,0xA4);
+ I$ D1 Y4 ~; L) a/ J   wait_output_full();
# u: k) n& q/ ?% Q   return inb(0x60)==0xFA?true:false;   
6 o/ o7 D/ j5 j% R}9 k3 I( l6 k- w' M

: @; E# V: r( ~( x4 V4 p    * A5h
+ W2 @  O' Y/ `! F8 ~- G
/ Q3 i0 `4 N; ~设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。0 u/ @" y) m" E1 P' N8 T2 C$ r! \) E
void set_password(unsigned char* password)+ C0 s' n  D. S5 `  j  g
{7 \( u/ Q, ]2 U
   char* p = password;
* B& R8 ~7 f: ~3 [8 r; X
$ ]1 t2 u- k4 X( y6 n% S, e) F   if(p == NULL)
) b+ W  F& O  Y2 F! `      return;. {3 J- r  M$ @- r' M2 {

% F8 I% n" v0 x; k9 `   wait_input_empty();( X; U; I* n2 {, c
   outb(0x64,0xA5);: F/ |% s1 h1 Z# }' I( L
9 ]9 e- P8 ?0 f/ h2 s! p
   do{
* M$ Z7 |( k% I7 M7 l+ Q& }: q      wait_input_empty();  y* y4 y5 {2 A" o6 Q& J8 D" r( r
      outb(0x60, *p);: d; z' o1 _# U( y5 E1 S
   }while(*p++ != 0);
1 i" D: z& u; D/ D1 T; _7 ?( J# Y# D}
  U5 y; }$ b2 ]: w
7 K1 B) H& P! d# ^; c    * A6h) ~5 b7 W$ P- P

) Z2 W1 N. @+ Z/ A/ T% [让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。# }9 G' Y1 H% x: ?9 F( h
void enable_password(void)
2 M" ~) w) G: V. e" q{
! p7 a1 T4 H. ~8 u$ n9 X   if(!is_set_password())
" n" F4 p' S" W. x6 g0 `+ k( b      return;
) c( {) g. w2 U( i7 G) I& V$ w" k
; q, l! ]- `4 ]; N6 L4 j9 ?   wait_input_empty();
( H) A+ F1 a  l: K( X   outb(0x64,0xA6);   + ?5 O) m$ R6 P, Z& W, e
}6 y- b2 q) v: ^5 P; S$ {2 _2 _
% K+ k& G- c) }- `
    * AAh
! R/ u' p2 g5 [
6 n5 x6 l* F% S自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。. D  p" O' Q# ^" T

; E1 a+ ?2 W( e6 @% Q4 F! B2 F. j# w1 ^# P+ W/ U2 e* U
bool is_test_ok(void)
% ]$ G9 D" [8 |7 R7 E% _{" W$ p5 O% a  ~( g
   wait_input_empty();
. z% G& J' m6 A. S+ E+ q, ?   outb(0x64,0xAA);0 w0 V7 X; L) M; ^/ `" P$ E0 [( [
' g! ?1 S6 {+ b8 K+ q2 N

: n4 b1 `  T2 @   wait_output_full();2 Q) a2 r5 K% e- {5 S6 R
   return inb(0x60)==0x55?true:false;   , {: T9 t) E+ n/ U: _  v+ j5 k
}
1 Z* g4 V% J! L( W
5 Z2 r+ Q% M% S- u: H% \' L& [' ~# \# ]+ s5 x3 l# A  Q
    * ADh$ u' @7 h# b% s
0 S0 }2 X1 B" ~, Y& j  r( H- R
禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。* F8 X% ^) M* k, V
void disable_keyboard(void)
- q7 r( O/ ?/ q4 G6 N{1 o- M# E1 m' t% U0 `
   wait_input_empty();
0 ?2 Z2 `3 @6 `' p1 m! N' B   outb(0x64,0xAD);
1 `* m& T: H% M. `0 e0 O+ _" N$ s+ w9 m# Z
}9 L2 Q! U* ~: c, T

* m, F4 {: k7 u  c3 E. x    * AEh
& e$ x# w) O5 R# ~. u4 O7 E
# I5 s4 F( F. I3 g; j打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。
& y  P' D5 s3 M6 Bvoid enable_keyboard(void)
  m) r% o. ~4 i9 o9 T5 o  j{, {  y' Z* J/ \8 Y2 R! E+ F
   wait_input_empty();
  c4 Z' r- U9 M$ k( V   outb(0x64,0xAE);
4 S: e! J) J' u# W2 E; ~! ^6 a* Q5 T* Z: N  V. W5 b
}) _2 T3 d0 f8 L0 Y* ^
6 F; ?1 R% W- @& B! @
    * C0h3 d+ T8 _7 E3 u
) G! v* i/ r$ B# e
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。) `, J& X- H6 ^8 \1 u# |; A
unsigned char read_input_port(void)
0 U5 w7 [6 w# y5 Y; ^; Q7 x7 P{
- d' F3 o/ H2 A  {% h   wait_input_empty();
' s* ]4 y1 i! ^7 Y8 D   outb(0x64,0xC0);
9 P! h2 b" E3 q: H5 ^. t2 P! D! c% g0 {- D& `9 C
   wait_output_full();1 A+ O! c$ Q1 S5 i1 e: e- T% `; p

* u. d4 @6 d' Z8 S   return inb(0x60);: G( d4 ^9 T- T8 _$ q- a' P
}8 h$ i8 h& k1 T1 I6 I! J

0 Z/ ?2 h6 Y0 ^, v5 _7 [; s$ n9 U7 J! o    * D0h
3 M/ v; i% a9 G* A5 x# d" K
3 E! Q0 B+ B4 x0 N: d# Y, Z% k准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。' P, P* t3 c, G7 z1 T# `
unsigned char read_output_port(void)
% i* y) n' d$ V- Y& Y6 `( E. i7 J) ~{
. \1 B0 {1 ~( P& R   wait_input_empty();  s7 \- c/ o( }; I8 O3 s: P
   outb(0x64,0xD0);
8 h" j, ^- e8 b$ P2 \) Z: Q% U+ J9 t$ y7 z) p. b
   wait_output_full();+ L8 h+ w; m: e% Y
# a/ v* b* A( m& n/ d/ m: G& \% T
   return inb(0x60);
# e1 O2 O1 A9 A4 ^- C7 z1 |* G}5 y9 L/ y8 m. ?! ^. q/ u# e
+ G1 B" {5 G0 z% N" ~
    * D1h
7 n8 v' N% @. `" v% W2 x- R  E; Y- b2 w( J( a8 a+ c, Y
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。. G9 u* g6 R& F9 W$ A' q  U
void write_output_port(unsigned char __c)
% O" \& Y# j: @7 a5 P{
) p. u& c7 z  e, v0 \   wait_input_empty();5 F. X; u0 w) V# E; f! m5 F
   outb(0x64,0xD1);
5 f% y5 z' m/ `. [
$ d, ^7 [$ x& m- H) n   wait_input_empty();) ?3 f* u4 U7 F
   outb(0x60,__c);
- X8 @" o8 G2 h+ q  L; a: |9 n% B2 b: U  N1 ?, E. a
}
- P( i' V4 h, x# [
/ R  W1 _6 ]; N' g, z% q) S9 e, [4 L2 x% h3 n
    * D2h
" ~7 ?  s/ A4 G6 c$ d$ m( I' [# d! _8 j& C! w: {) h$ @$ U
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。' G- F3 Z: K; p3 M
void put_data_to_output_register(unsigned char __data)* `7 E  _. b9 K- ]* }4 e
{& n# P9 a: D- ~: a0 C
   wait_input_empty();6 t# [! r! m0 I3 G
   outb(0x64,0xD2);
$ G! I; V8 s, @* c  ^4 o% L% S/ f( o, {2 T
   wait_input_empty();
- p! V; V) S0 M8 _! _   outb(0x60,__c);
* l) J3 l- a. r" i) D}
7 H0 g$ k5 I3 u. h3 n- w" s/ W# j0 K! O- H! m
4.2.7.2 发给8048的命令, ^2 ]4 g0 i7 g7 x! G; j7 `

- m4 [9 M! }) l% ]8 S/ r
3 v3 F  h4 J5 r4 C    * EDh" y2 B, R9 D: ]7 L( `4 n

, ~) d( `$ ?! }& m8 ]设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。6 c, F; F4 D1 k. h; S
/ t6 H8 D5 |) J
    * EEh
1 h( z  y+ H. @1 z6 _7 G4 K) E* i2 h# ?- Y, t" G% x9 {0 R9 M
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。- s4 O/ |) R1 n8 ^
/ f; B( B# V, s3 f
    * F0h
* g& t6 c; q0 G9 `) p
6 X" M- Q' R7 Z- o* C选择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代码所要求的。+ W$ |, |/ `' M, m1 x1 ?
) Y" ~7 J) x! ~
    * F2
; |% _$ l( g) _2 T: L. a: @
% P( \* u% C' X- x读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。" S/ q. _- n3 V& y% {- Y
9 p. I' O9 C  [  q& V
    * F3h
+ F2 I' ~; a8 Q4 c4 Z2 r) d5 {8 t; N5 m8 d. W  o4 q
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。1 C9 k1 D8 a1 K3 S
1 ]9 T- K; l1 a3 G, D
    * F4h
. m( r9 V( P$ W! L
! ~- _7 g9 P* u8 i- H, @1 h清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
  b7 p2 s/ w* V( u$ U- v
6 t& E' M  [! r% F* r0 n. e0 L    * F5h
; Z0 p4 X9 @# ?% j
6 a% F" P# c9 L) ^- [; j设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。
/ N, i1 {+ Q  o" b6 C. E4 W( ^. z7 ?$ u# S, {* ^6 C
    * F6h, E4 ^5 Q" z4 A) A( g

7 d" ~  p+ D, Q设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。2 C# V! C1 a/ C$ `9 p8 e' C8 ]
, F1 u, F9 R; T9 ^7 Z9 d: B
    * FEh
/ j! G1 b1 O  v$ M% `% q9 |7 c, N& n0 z& y; `
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
: ^- s; v) P" f; I( p
0 J2 P% _" Y( }! i    * FFh
. g6 E7 l. ?) |. Z$ L( }) \, t2 i$ p: {) s, g
Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!7 P' a* {2 a3 K" f7 v1 V: i/ K: g
非常详细!' T5 G: p9 `. |# c6 ^4 {3 M- R
谢谢!
回复

使用道具 举报

发表于 2009-2-25 17:37:28 | 显示全部楼层
2楼好帖!在helppc的Hardware Data and Specifications栏里有相应的寄存器和命令详细描述。
6 x0 ^5 K  n5 H, u% f
( g2 P( _* [/ m! i% {' \  \我的问题是,上述描述应该是针对老的8042的,在目前的使用EC的系统中,这些status register和command描述在哪个文档中可以找到?比如intel的santarosa,使用renessas的H8s 2104 EC,按道理上述状态寄存器,命令等的描述应该在2104 datasheet里,但是我怎么找都没有。还是有某个spec定义了这些命令格式?新手问题,高手莫笑
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-14 14:40 , Processed in 0.027748 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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