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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上   9 Y, i; S3 @0 R" u6 L" v
1 D* \/ ^  T0 h
4.2.7 Command" i) G$ [4 Q( e5 X; l2 x0 M) h

+ P8 a0 [  ^6 e; m: q, L通过8042芯片,可以:' m+ r$ f3 A$ v7 E, F
向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
* o0 g! y% |/ Q4 x  b* H2 w& o读取Status Register的内容(通过64h);; q0 U& [) q( q3 U6 g
向8048发布命令(通过60h);
; l( i& N; V3 B读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。
) E- x; [0 I) Z" z! x; C; C9 N5 m2 R' u$ z9 P
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
# g, T8 N# ~2 c0 |
7 c0 U- O9 v1 c1 a7 u
2 C5 w& H( K, g+ Y# I  f) g0 s" m" J
    * 64h端口(读操作)
! N: u% c$ o: ^5 C8 O5 o
: K3 T) E. |  }; D6 i  B( y+ @' }9 }( P* g# ^: R$ b' S
对64h端口进行读操作,会读取Status Register的内容。$ b- g; z8 B! Y( l! H, K0 c
' }5 ^- g/ H6 y
inb %0x64
& i: L9 A# d! B4 t8 j执行这个指令之后,AL寄存器中存放的就是Status Register的内容。* V/ y5 e7 g- |% @8 C4 T5 E
- x( a6 }. |' H/ F0 e9 r5 t
    * 64h端口(写操作)
1 j1 x. C; |6 S7 v9 _
: L+ O! U/ R$ c8 ^1 U; ^. |' G$ E向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
2 k  w, D% K) x4 g, ?) V+ CŸ" ]& d0 B( U6 W* m. s. N2 s
写入的字节将会被存放在Input Register中;# h- c3 x* W1 M
Ÿ
5 |, n3 u( c$ g% P' o  C同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;
& D# H' G2 n5 KŸ3 k9 c: O+ F) Z7 a- |) v  |
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;
3 N$ P. I- B: w1 r5 ^" ]* K- EŸ
+ h/ J, Y! x7 U# H在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。/ @- m9 D( \# X  Y2 A7 e- n

  B# b6 h1 q6 v% Tvoid wait_input_empty(void)) _! Q. h$ B+ G2 b
{5 D4 a+ W: e* ~. k6 d6 a
   char __b;; t) l2 N+ t9 J. R. x8 L

5 _1 ~6 `( j8 _3 C$ b7 z   do{! B  \/ c5 m8 i* \: V
     __b = inb(0x64);$ h! Z( T8 x4 B/ S& F( ]& \- u; W% t
   }while(!(__b&0x02));6 }$ Q; H3 X  f7 G) e0 @
}% J5 v1 ?4 R# B9 D
0 ]4 q- D' q5 a& e4 ?  N# x* e% I
void disable_keyboard(void)$ q- _; m" a% U& j9 O; v. ~
{$ W4 w: Q5 a, y# z! N0 y' s% A. N
   wait_input_empty();
" c/ r  z) J3 _! r: x" A  Y% u   outb(0x64, 0xAD);: `6 P' _' q/ {9 n
}[size=+0]; s. b$ R' z! p' h: c8 E
8 x! X6 I, H1 h5 T- t% p$ P
    * 60h端口(读操作)
  i% O; G9 j7 b5 g# S. y7 {
" l: U# B6 x1 y2 c对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:: L, C* F& T7 N3 w
Ÿ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。" ]1 J8 o/ d, U
Ÿ           通过64h端口对8042发布的命令的返回结果。
2 e& r8 [4 D! d' w
, }! S0 ^: ]* ?: |在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。1 x: ]& M' q" @/ e8 j
void wait_output_full(void)
3 J) p- E/ p2 E) I0 f' J, E- `{& M1 c& ?8 i; T  @% j: R! [
   char __b;
4 {8 @& Y# T* G. Q9 a) a1 O. @/ O5 R. |* {, l
   do{
3 G! [- k/ p! h     __b = inb(0x64);, C6 q6 F) [6 C
   }while(__b&0x01);  y  n5 C' q1 [1 f8 G
}( h; ^  X/ q" d5 x& r5 Q# R1 g7 b
& C% u4 k% D7 w
unsigned char read_output(void)
$ @0 g3 V% P' t) E{
" d2 W+ J# V1 Z: P( {* i   wait_output_full();2 Q) o6 ?4 d  M& q& W6 L9 b$ A
   return inb(0x60);, g$ t5 U. }2 w% ]( a, E1 S
}
# o7 i+ R, l2 u0 s. J1 M3 `+ [- y& w1 P( |7 }! P; @
    * 60h端口(写操作)
$ [1 o' N5 Y# R! ?5 c( L* b$ y+ Y. w- P) z, m7 s0 Y: [
向60h端口写入的字节,有两种可能:" ~5 Z! ]0 u7 k3 @2 A/ a" K
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;* N1 d- L- e" m2 c' {4 P, w5 ~
2.否则,此字节被认为是发送给8048的命令。
  ]: t1 e+ a  z2 s: J* L7 W* @
) C( C4 t9 h  D) h8 i$ c8 i% E5 l$ n在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
' k9 d0 p$ O& [# f  F# X: B
  k/ A6 q7 q8 ^6 `5 x# }, x) I: w; i2 ]* e
[size=+0]4.2.7.1 发给8042的命令
/ L6 E. e$ @  B; _, C
6 W% L: s# v( d    * 20h & b& R3 m( d; @* B8 ~
. j4 e* G. H$ d
准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
" k. x  [9 Y6 U' X2 |4 b& b8 I% A! y) N. |

) K2 p8 W3 |: o" M' Dunsigned char read_command_byte(void)3 V8 A3 }- D8 b: ?  R7 o. ?
{
) z) J0 H# s1 w/ b( O   wait_input_empty();) I/ M( u2 V. ~5 g4 g4 y
   outb(0x64,0x20);- L$ ^. A* k# w$ K3 v
   wait_output_full();" G1 j  G; B* m  [
   return inb(0x60);   
8 D) n' }! S, ~: o# k; k3 \}
5 r6 V: R% X! m( Z
1 Z5 B& H: P& K    * 60h. ]1 |- C9 v1 g/ u
+ C& x: I1 z3 I% n* u# E, ~
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
1 C5 U7 f' ^, {3 c
% e$ D, U3 ?2 s& H% ~
) ], O: L; i" p- |- wvoid write_command_byte(unsigned char command_byte)! W6 m0 Z% V( G; r
{6 d/ }3 p" }0 G  y4 z4 j
   wait_input_empty();
5 s5 j8 J& ]" I" W4 N' {" h% X   outb(0x64,0x60);* f8 Z3 Z: X" S
   wait_input_empty();$ B7 v* d. G1 \% g
   outb(0x60,command_byte);
. p4 D8 b, p8 J- @2 i) _9 f: l5 |4 X  C+ I}) H3 G+ u( L' A' S! i
- K& O8 `( a* B: F8 ~5 A. A5 V
5 W8 D8 p6 C+ ]& e4 a- P4 x
    * A4h& w+ W% u4 c; g6 }6 h

# @% v; X; }5 m9 F$ z4 F+ e* L/ c. h测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
! D& c) ^9 l7 }' \3 kbool is_set_password(void)
, X9 V, d6 B+ @2 f{+ C& ?" h! r$ L8 \. {. k$ P5 p
   wait_input_empty();
& T6 |) }* o8 O+ K) `" X! Y" |   outb(0x64,0xA4);' _' T4 x& X; ]- `' _6 _/ D) U6 f6 P
   wait_output_full();
% c5 u$ h2 r* x( y) @   return inb(0x60)==0xFA?true:false;   1 Z+ z( x3 l* X
}- e* C8 _  n) }* O# ]
8 h; \* i/ v5 B) w: ?
    * A5h
  u; \2 b, [8 q* a4 k. ~" k4 `" F+ T8 I  \  e/ P) }/ @, ^
设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
8 e: i4 `1 a* U# Cvoid set_password(unsigned char* password)
7 r2 V1 F% ?* y, M( ~{# D, J$ r  c1 ?5 O+ w7 ~) K
   char* p = password;
* C& R- _- e" e6 }. d0 `& l6 j1 Y# P2 `) `& C9 k8 y
   if(p == NULL)4 P2 X  j  h/ g* j5 v5 V2 K. n& i: v
      return;
) }2 Y  l6 n9 ?% q1 N- S( K  U# D) @" M+ {( O
   wait_input_empty();" F  e8 o8 }3 j; B) B$ S
   outb(0x64,0xA5);
9 \1 A6 I+ C& \7 b. r2 Z
# Y! `4 f4 u2 n$ f! u7 Q3 |   do{
# v6 y+ Q+ y* f0 j6 g" s      wait_input_empty();
5 M  J& J* l4 l4 j% E9 y" k1 Z      outb(0x60, *p);
+ u1 i9 y2 R  `   }while(*p++ != 0);/ U! p9 T! v" w7 ~# S( N
}' z% ]: \7 ~( }0 T7 U
9 [, q" n  D; r# P0 m, S$ ?
    * A6h
' I( Z8 C! Q+ d" l% `. ?* q( J+ }) }7 y9 F
让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。7 [9 y- P, n* K9 h" {/ @
void enable_password(void)
; k/ J* |7 Q$ b6 x. S3 \{3 s6 o! X. Z/ W3 S" q1 P
   if(!is_set_password()). I- z8 ^* R# r6 D9 ?% m
      return;/ V6 E3 O: Z$ l2 N% U, d/ P
: y8 i  [# y* l" @! l
   wait_input_empty();. t% h$ A& _1 \5 D2 k9 M$ e6 }$ a
   outb(0x64,0xA6);   ' y1 X- y2 C5 C* p' z# i
}, |9 e1 s% {9 }' P5 d" F
" O- R- x% L6 r- [2 W# ?
    * AAh$ n- e0 H0 a# `: L8 t( j

) v/ v9 s9 [4 l& ?6 U自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
% R: [# t0 m* `' u
% W6 ~! G# H, K. f: q
# x/ G5 d) k8 N7 Jbool is_test_ok(void)
' R) ]( j9 O6 F8 c/ O8 i$ Z{" r1 z2 s# W! O
   wait_input_empty();9 Q. M# ?" E: m& r; k1 x# g
   outb(0x64,0xAA);
* H1 ^8 r5 ~5 O1 d6 ~. m# A+ Y. H
5 b" ~, C& e( ~; z/ u: ]4 J* L' |
* J& i, v1 \5 ?& _6 O   wait_output_full();6 m7 c! g' V- e. Q% N' M1 g
   return inb(0x60)==0x55?true:false;   4 x; V* B8 W: Y8 k' S3 q6 K" ?' ]$ f$ G
}
1 r* M& b! m- i: n  x1 y' ?9 H( A8 Z

0 K3 m4 i3 x0 Q- ^    * ADh. O, U+ \! q+ v" q4 a' T
0 F8 i9 [# L( C, ^
禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
, Y( Q5 u4 r; E; ?, B# Nvoid disable_keyboard(void)
% X$ e3 Z8 l( ]0 r" H, M{
/ k" u' [% l8 q9 e7 [- I0 F- Q, F   wait_input_empty();
" z" r' x) m, g3 G$ z. K   outb(0x64,0xAD);$ C+ z& S/ Y0 j  u. |5 d
/ V+ W5 ~  K) [
}
8 K0 ?; k7 B( R0 m+ b/ K# e9 I  G2 }& [: M  ^3 }5 B
    * AEh
$ w+ @: f, _5 r& x/ K' e) ^. I0 @* y, X4 n5 H- Y9 N" k; |0 I
打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。
* D( X3 w  A) z' `! {) x4 l3 [- rvoid enable_keyboard(void)
# W0 z8 w# t( p$ T% V$ A{, w- i# i9 b( f
   wait_input_empty();5 I% ~9 T/ B, W2 f
   outb(0x64,0xAE);
- N  M- x7 l, l* E6 Z7 e2 e* q  t; @' x* L6 V4 w* p: p$ I
}
6 j  L7 `& M( s) C, ]  z8 b" P: o$ Y1 t8 L
    * C0h
, i: D+ s1 [1 P3 `. R( t9 f$ W8 y+ ]# c
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。- H. x7 o- h( X  {9 A
unsigned char read_input_port(void)2 K8 O9 ?7 a3 M/ i
{
* y! t8 \9 w6 T5 A   wait_input_empty();
) B+ Z1 N& O0 v0 }% U( w6 g. r   outb(0x64,0xC0);
" }6 e& d$ J) u5 O- u, y6 s+ M6 c: f* }
   wait_output_full();
( L* p& s! C( l3 S# h. z9 ~1 D' m( Z! t0 [: a: D
   return inb(0x60);
5 i( |  x; K4 d3 [0 F- m! ^' c. t}
3 A3 k4 h3 d; m) X& \1 y; A% W- H: @3 q* @& U  J$ L% i
    * D0h
; U" z( {! d7 e* P) d3 P& R1 G  ?7 h: M" C) @, z, a
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。! G4 e7 z; [$ ~  e
unsigned char read_output_port(void)
. Y0 \& }; X+ e- g{4 E, l1 ~7 v7 k3 ~: e. C7 g* ^
   wait_input_empty();: ?; T0 Z. B4 N5 r& O2 z9 G
   outb(0x64,0xD0);
' a4 V9 ]* ~8 r9 \2 C; V5 v: o" ~; e
% E1 t- L$ q. ?" T   wait_output_full();
/ F8 ]' X/ T! p+ N1 t! S# V8 @7 }4 s
   return inb(0x60);
( r$ R# o2 h6 k}
" [' s- s6 k7 g& M5 t( v& Q/ w
( s9 N) A8 M2 C% q    * D1h
) c3 f# k( v/ V/ X7 y; l' P  C# ]$ G6 j8 b; L& u
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。
) F2 W0 z" m+ ~2 O) }void write_output_port(unsigned char __c): \  K! l! K; ~- l) o0 t
{
& M7 m) b- U; @2 N$ c, o$ z   wait_input_empty();
. m& Z6 S% s. J2 g# O4 y   outb(0x64,0xD1);) D6 X' j1 |9 {$ q! F2 U

! j3 E% @: C( a1 G5 Q$ W( ~5 t6 q$ b# J   wait_input_empty();. r6 U; N/ q# A3 n5 o8 P: y* w
   outb(0x60,__c);7 H+ C! `! R( E6 L1 F
: w' ?# |$ f. W4 @% A/ v
}! l: R! L3 W3 _0 F: h- G% c

1 X3 w- U2 g0 B# s9 B" z9 k$ q8 n# [: k* \) x& d% i7 e
    * D2h
8 N8 E) E+ k  D( z% v7 z2 h
4 I" b( W& R; B0 K5 ~. q! u准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。/ {) r: J# i7 ^& ]
void put_data_to_output_register(unsigned char __data)
' N. a; ]! B8 w" N$ o{
+ L7 L9 ?7 M  C" G6 ~   wait_input_empty();. C% T! c. H& [  o/ C
   outb(0x64,0xD2);
1 c9 I! ]; ~4 M" Q7 G
$ q( f. ?: v8 B) }( v% P   wait_input_empty();! H  X4 l- C4 U: L! S
   outb(0x60,__c);
0 i! Q" ~. l& U4 u* Y; e9 o$ C4 b}
" J; P0 k  c9 i  Z; j' G7 O# @6 o+ Q' \5 x4 M
4.2.7.2 发给8048的命令+ D6 I; c& c  L1 V8 w6 \6 N! e4 R

) D- W; n" V4 j3 [1 Q* o  m( o& ]# O8 r8 O2 D" G7 _/ x
    * EDh$ W5 x8 D" U! J, l+ b

) Q3 h6 x6 V" ?7 q4 \" v' v$ Q设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。7 b6 h' L% P/ [/ w

3 S  V; A( A  ?% S% K    * EEh9 G, m, n7 b# x6 W, R6 S& ^* H
4 q$ b0 F( Z* V2 P% _8 W. Z
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。& n4 ^: s3 {% L" y: B

- [9 x  W5 L1 @$ x% P$ h    * F0h- l& H, H7 L+ c' ?
9 |* N  p5 B1 X7 k% T8 [2 p- Q
选择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代码所要求的。
; E% U1 ?* [  N* G4 C3 t  p% F% n2 I: l
    * F2$ |5 Y- }: P- L/ A8 u0 T5 ^

' {1 E% t. U+ E: J" `读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。
: D' _; }- I# Z# o. G- A& P4 l6 d6 Y. G1 U: W8 \7 z
    * F3h0 x; q+ P3 K0 R* N# |2 h  Y) z
3 W  \& ]/ ?6 J$ \+ \9 E) h& I: a
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。6 L) a' K" @- u+ ?5 P. D7 z
9 j* q2 Q! t: z& p# Z
    * F4h' r) ^4 j4 o" l4 Y2 r- U3 S! |

8 _7 z* M2 m+ @! {5 b8 R清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
( L7 d/ D' v9 L" b, [3 m/ q
) o% q6 y. y! G$ D    * F5h5 x6 X) @& u& e5 Q4 f
* U. m2 v5 F: ^# }2 `) O) T
设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。# \8 x8 x$ s& [5 q; `
- Z8 i. j4 u  |( Y
    * F6h
. K8 {% }5 e, K  h& W
: O" s2 K9 E3 c9 f0 D% G设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
2 ?/ a# U) I0 S1 x* |: F2 h! F5 ?
( q6 T' W6 H0 H6 J    * FEh
9 R. @! z3 G7 f6 a
4 n; a. G# h" b( ?7 B8 F5 n# c. uResend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。  k- Z! h+ o  N: U0 n

- ]; S2 L$ Z0 x4 S    * FFh
+ D" Z6 b& J  X- `& Y' K! |4 ?6 X1 A: {2 l) D
Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!
8 h8 ]1 M- a( E* Y/ h' t- @2 U, t非常详细!' |# `9 J6 a! u2 {" N0 w
谢谢!
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-7-19 20:42 , Processed in 0.524360 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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