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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上  
4 k& s% h0 y; x; [8 n7 G/ n) o: h! j4 k+ s# w' [, e% `
4.2.7 Command, e) u3 q) h+ }# O0 D' }/ z

, K& b3 c$ o; P; x  m通过8042芯片,可以:
+ L8 V' E; j# b6 c2 f" T+ M: u向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。' k7 @: F0 E( n! H% S7 ^9 a
读取Status Register的内容(通过64h);0 E: v5 L; D" R5 i; A# ~
向8048发布命令(通过60h);9 k9 K& a0 T" m/ Y) q" p
读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。
/ ?* f" H  c4 i. q; u) F" Q5 X+ F" y) m) P/ {% y& i
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。0 @/ e/ q' `$ G3 y* F) f4 c  m

# o- @/ X. y! r
3 i" N9 F, A8 A; i7 d: S6 ]
8 a( D" q) G8 M# g& l  [    * 64h端口(读操作)
2 P6 N9 @3 S/ w7 E" \4 o- E% J
: g% i2 N( _& [8 T0 R3 j( M
3 h' [( ]' G& q/ z" Y; W对64h端口进行读操作,会读取Status Register的内容。
3 c' ~3 R2 ^2 D5 V# {2 S: ^/ A8 d0 L0 N+ d1 b1 |
inb %0x64: M" l' u/ W' y2 z5 c6 B3 l
执行这个指令之后,AL寄存器中存放的就是Status Register的内容。
0 Z' Z/ H. x* ]: ~; R
3 H' E: B) _- z! z' K* w6 M" i" I    * 64h端口(写操作)
+ {1 v* O' g) d$ R* M! j5 O
' g% U1 r2 q3 `0 ^8 x. T% A向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
+ J( [' ]: k+ o& uŸ* Q4 Y  Z& z3 |/ L0 D& W3 |  b
写入的字节将会被存放在Input Register中;) ?, [% u/ v) q1 ]- h* O/ l) ?
Ÿ
" t1 q5 r& K# w& C  t/ Y同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;/ l) [" M" l4 m2 x$ t; M7 b/ s
Ÿ5 t- F* L; f' u  p  x" u. }
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;
3 V8 o4 ?2 D2 N3 h0 yŸ4 P6 m4 A! p8 h5 L5 P& {2 I
在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
0 S# k9 }5 i. q( q3 T1 {* W' ?
9 t# R1 u: R0 h" F: Uvoid wait_input_empty(void)' T$ i: z% Q/ N1 _
{; j( ^0 Z% c, e) }, E4 I
   char __b;
  d" K% _2 M) \1 m( o/ s( n
9 O+ J) S0 G' x) E$ X/ K! z   do{
, l( F% H" H# P2 p     __b = inb(0x64);4 O0 V" q: y! V
   }while(!(__b&0x02));9 l+ m; t, l! X% [0 B: ~# h
}
5 r! e3 o& d6 t* o1 `  \  S
3 [. r  I+ j9 V% b4 vvoid disable_keyboard(void)8 `* B$ z9 M- f, L/ V
{
  g# W& x6 M* d4 ^   wait_input_empty();% B* M( w- u+ r; Y
   outb(0x64, 0xAD);0 M2 V6 l: G5 N' G, e# i) g4 x3 B" ~
}[size=+0]" ]! I" F2 p" d
/ t) c7 u- _! M8 `4 b' G! L  w
    * 60h端口(读操作)" b+ W+ [$ p2 a% z
  e( ]" D! k, D9 F5 t
对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:; r$ A9 F# P% {0 Z& F* a
Ÿ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。4 F3 F3 `0 R' ~0 y# M
Ÿ           通过64h端口对8042发布的命令的返回结果。) z* D7 s4 a- d: \
2 r" j& g! T" q, S3 u
在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。0 b. X  d+ X! F" z7 ]
void wait_output_full(void)- z  k5 d% U5 t
{
9 O5 A1 ~. v, |. o& ?   char __b;+ v- |3 ?: h: ~2 Q1 V- m& Y( F

  Z5 D! i$ D# Q! R9 k   do{, @/ V* E/ z  p* u
     __b = inb(0x64);- c# n# w! z: h( [& R
   }while(__b&0x01);
" b: Q5 z0 I% o}
  _  p% H8 L+ z9 W8 H# S: A; J  i  E9 ?8 R: z% a
unsigned char read_output(void)+ h4 f( |7 X5 K' L( N6 T# J
{
6 Y: ?& F; f# j2 u   wait_output_full();' \/ @# |1 R$ O4 b3 x
   return inb(0x60);
7 w6 q! T- R% E& Y3 a  m& B6 q}
1 n5 |& |* j  ], A
1 H- a# T2 T# |/ _* A    * 60h端口(写操作)
2 U- I% M" ?6 T" F& Y
: ~( a& e  {; H( E4 U6 J" J向60h端口写入的字节,有两种可能:) f5 b% m/ B  j% _) [- }. G% ~
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
- C  q, m2 P* Z8 X9 f" S- V2.否则,此字节被认为是发送给8048的命令。
" A/ o' P) k& R) I2 S1 n) D
8 T2 Q2 W1 V3 f0 L, K2 v! F在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。% k7 [4 I. R: U; k- o' F8 |- {; C
7 Y$ E8 r$ r5 {$ Y% y& W. O  |

$ y4 a. r2 h8 T% i( S0 P[size=+0]4.2.7.1 发给8042的命令
2 `) H0 y$ e) _. }
5 O- `+ n5 v& ~    * 20h
# ]% n: J' @4 Q
' o6 t- C% `* k9 U9 L准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。) ]4 E3 u8 w5 z0 ~2 f0 T
1 _9 a9 W# h3 O$ U- }% r: A

, u+ R4 G9 O* k9 g5 wunsigned char read_command_byte(void)
- \( w6 a$ z) q( K' g{  k9 R4 w! R% ^- l: ?
   wait_input_empty();9 ^" P8 E9 T9 a) t/ x. f
   outb(0x64,0x20);
* `, V; l+ ?2 \2 B2 a+ J+ l   wait_output_full();
- `4 f4 j' _2 o; l/ M   return inb(0x60);   . q+ B2 ~/ }( T
}$ `6 |2 v+ U  c/ N
3 m8 e# I/ J+ H" W$ ~5 Z
    * 60h, O" \0 ]8 d! K6 c2 r
7 E% b' b4 B4 s' U
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
4 N! L, n6 a, l( V. l7 f! y' r: p7 K, P2 \  N6 \( H( S, D+ A

, f1 z0 V$ D& i8 Y0 Vvoid write_command_byte(unsigned char command_byte)" {# }  T: z' i) Q- u& W5 `& J
{
! F' a1 |% N2 v  c. f3 G   wait_input_empty();% a% `) L5 q/ U+ c
   outb(0x64,0x60);
& c7 \% w. [; [+ _   wait_input_empty();
9 w& H: i- Z  ]  j/ ~& g   outb(0x60,command_byte);9 b: j" g! I6 I2 j% Z1 U
}
9 p5 @7 w4 y- q1 Y% C8 m, b1 O
+ a+ ]# d0 S/ t8 @, r( k0 e: e+ W) O) v7 \5 p4 q. `) z0 B
    * A4h
3 f' F* `4 D3 F) I% ]' ]. R
, @. x* r' Z) z9 p: a测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。- K4 a  Y. X/ X. C, m2 O5 _
bool is_set_password(void)
3 Z$ \/ S  [* i2 j1 w* _{
6 W: Z. ^* W  }2 Y6 ~; i   wait_input_empty();0 `+ V* K$ k0 p, l* J; w) ^
   outb(0x64,0xA4);, F" {# f% \6 |  |% Z" ]
   wait_output_full();5 x. M6 [; V! V. `* n
   return inb(0x60)==0xFA?true:false;   ) A; T( t; E/ I! F! ^
}- {6 G6 ~. T8 @' b
+ u6 C  O' g# Y( {$ p1 k, U
    * A5h
6 p! ~# [! a6 N& [& V
; Y. G+ w  e( T# J设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
7 Y& a. q7 Q# j& z" A& d! ?void set_password(unsigned char* password)
8 t4 f/ B" G: q{* K! W  z1 O3 W+ G( `/ |1 P! e
   char* p = password;: Y2 d- b# o  d: R2 t

% Q7 B, j% t1 @5 A+ X3 T  V! ]   if(p == NULL)
& ]9 \# D7 Y* \      return;9 n! J6 V$ I6 N4 U4 J3 a3 A8 a; S& v

, _) h+ l$ y& a   wait_input_empty();
/ u/ h  N: `. d3 h+ T$ n   outb(0x64,0xA5);# k% n9 p- v4 g4 W
5 ?1 K( P* h- K7 u8 a" S
   do{) R" j% Q5 ]' u7 F. E
      wait_input_empty();$ E# w: w5 s" i+ v
      outb(0x60, *p);1 V+ l* m2 }  _2 @) o4 W% ^$ N% ~
   }while(*p++ != 0);$ L- b+ x% T# J( o/ W
}) e& X# {$ n0 W2 K% z

! B8 H$ `% i3 P/ v3 E2 [    * A6h3 X, l; M& S& }

6 F  q/ ?$ H+ e$ e/ l. c6 X让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。' w! d) C! C9 g) O# w: x
void enable_password(void)* f4 j! T3 ^& z" n1 c/ v
{
- g& C3 Q4 z6 B. n% H) k   if(!is_set_password())9 C3 i4 @+ f8 F9 S
      return;, W9 y8 }+ a5 c# C  f# G8 d- x
3 m8 h$ C/ L$ t& e; [' ]; C/ a
   wait_input_empty();# i# Z, W$ u" \. h
   outb(0x64,0xA6);   " U, J" K: Z# t6 W! b
}
2 j4 D  V/ K: V9 ]+ M
( u: B. |( r! |" c9 e$ D  A    * AAh
2 y6 ?% U$ n1 J% }9 V
; [' \; Z+ O5 A8 p自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。% z- e0 ?5 U9 }% c, c3 e# b7 X

1 v8 W4 m  d4 |( T; G+ r) l. J: r# J' o8 u4 ^! E0 L5 n1 ~2 h
bool is_test_ok(void)- D8 z. O' s0 j0 C) |. u
{
4 [& X3 H1 \$ j+ p* P   wait_input_empty();* x% b& ]  F, a0 G2 x
   outb(0x64,0xAA);
$ v' r9 g, Z3 E0 N! J
5 z0 o% p$ ?' M) C( t1 l  ?, x' Q8 u* N: I! P* m0 H
   wait_output_full();3 s- L, r8 E$ S* P
   return inb(0x60)==0x55?true:false;   3 F& Z0 ~; j' U2 V1 S
}
$ u, e1 |! i( S) a5 A! y1 d  P* d% ^: }5 ~: U

0 `/ j& U. H& U6 ]% z6 n+ C    * ADh
/ K# w$ m" [$ Q5 l! y. Y  A0 L& G# L* }# b, m( E( U. M- ^( l
禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。* Z" p% f! }( D
void disable_keyboard(void)# E8 g* s1 J) [
{
* t( J1 j+ \- D: `% o0 c   wait_input_empty();0 V9 S1 Z0 `2 {9 z
   outb(0x64,0xAD);9 @- {+ M( e+ l! Z) E. Q6 o

$ I0 t* I0 u! K2 J8 S}
& i6 u0 S$ c% {# a: z. E
- c: W9 Z' \5 ^( d' x/ Q    * AEh. [, X* L) r; J2 R

7 |2 p* `) @& W4 {$ H7 b打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。8 \% ?. u0 v4 v: ~- L2 q4 {
void enable_keyboard(void)$ z. `+ e5 d. I8 j# b3 f
{6 R! L. M* K. p" |. y) V9 [  l
   wait_input_empty();: g* Y# K+ {# {6 E- F0 e
   outb(0x64,0xAE);( B* R8 c' @. @3 T7 b4 ]/ e: j

* i* |& L0 P- s! L. }" K) i}
' Z! n( {& r$ z- l8 R
1 T  @, d. w+ B( ?7 c1 p    * C0h! ?3 p! O7 u# ^: A
( e# P1 R) V0 i8 l
准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。$ a, W3 K+ A# p; {# b
unsigned char read_input_port(void)! L# U( M5 R1 H) g' I( t
{1 ~7 l; O  Q2 G5 Q$ q
   wait_input_empty();- j6 e7 A  m; o( s% ~) m
   outb(0x64,0xC0);
* a7 M9 n0 `- i$ ^
! o% K. E' |% n1 Q# [  n% y   wait_output_full();
5 \& O5 w$ r* e: f4 |! b# |5 S$ i
/ G: M- M9 j& {5 w- |/ z   return inb(0x60);
* V+ H. E$ o4 ^  p! I  @3 j& d}* e* D5 R" o) P% _) }& |9 U1 F) ?% X8 f
4 A) {- U" W9 A/ i3 ^( v
    * D0h: _7 y" y6 V- y. k% O. W( m
$ w9 t6 E. Q8 L. N6 v, a$ _8 Q% U
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。; G2 y# r& U1 [
unsigned char read_output_port(void)
7 c$ ~, [/ m' H/ Y# e) M{3 l: n3 i) T4 U* v8 H1 C
   wait_input_empty();
' L& S$ j% Z$ ~0 w! c   outb(0x64,0xD0);" X& {  U. Y5 g6 _  |

$ T9 K0 g. U3 e6 C5 t, Y, `   wait_output_full();
( N% n' ~8 D8 ~# n5 V, `# ~1 I" q' y
; h. m+ h% r: ?# Y, ^8 `   return inb(0x60);
+ A! }) ?' X( A) h) H}6 O( K7 O5 x4 M" M2 A0 I$ e

% Q( Z& ]! @2 V% Q( c    * D1h
. x: v: [7 `% n2 g% u8 i7 h1 O' Q/ p
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。8 s! Y6 V, ]6 b- E5 ~, M+ v/ _& Z
void write_output_port(unsigned char __c)
# A1 g# O. P( L; Y{
) G$ ~8 L9 w% W: |8 u7 ^- X% E3 Z   wait_input_empty();
4 p; w: h2 s  K# ]$ O/ |% ^: G   outb(0x64,0xD1);! L1 n4 U$ x$ Y5 o9 h

8 ]. V: \9 }. m' B   wait_input_empty();( f/ H) w* `; h; Q0 b1 e4 _
   outb(0x60,__c);; g$ F9 ~4 m: }* P

" t- W/ q( q/ z9 p: N}
* N$ n5 ?' P. C# d  u' V7 h3 z1 F3 M2 {; j

9 s/ j; d, V& s5 |9 i    * D2h
2 E% K/ ^0 D8 y* V% H6 @6 K1 h9 m7 D$ K9 R% H
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。
8 j0 ?. |9 M# v- Gvoid put_data_to_output_register(unsigned char __data)# ^1 d2 k& \) D+ @
{% N5 _: a7 b( q! _1 L0 x
   wait_input_empty();
  m1 B$ i* g. J1 W( N7 |   outb(0x64,0xD2);+ v/ k6 O! N1 ^9 D( B! _
# z) `6 a& o1 A+ u0 n
   wait_input_empty();2 k" [" W: Q- F$ }4 p5 @7 ~7 J8 B% t3 y
   outb(0x60,__c);
- p; J; v) k: l1 G  X}, |1 r- Z: G/ r  ]) }
: d/ j! I& s* m( `' I* U: U( F
4.2.7.2 发给8048的命令
/ z3 c% F* n0 P$ k, I! _4 y9 }  `
. E6 f8 S% r# b% F
7 U( M( t$ U5 k3 X1 M% ]    * EDh
  W# p1 f8 V- C
. m8 F2 d7 f# j; T$ i) m2 i设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。( L5 E+ \) q, F# k9 X" j9 X
8 w* [# {- c1 F6 X8 ~  S
    * EEh* Q' L" j3 h+ Y: W# [9 c# C

9 Z7 t" W2 T( |( B& b诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。4 w' t; U( E0 [. J; V, H4 R6 A6 c
! z: {  Y% m$ e5 S
    * F0h
- n/ I# f) d* _- w1 A4 `  C, l- V; E+ ?9 f, j: b- V
选择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代码所要求的。
0 \# V, Y& s* ^4 I) x, b- r# t9 {( f
    * F2
8 f' H5 S: s9 J8 e' G/ Y; k% s9 Q$ L* N1 G- }( t  H4 e
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。
- P: p# `( T! i  s! k. {' T; n+ O# p- W6 Z1 F6 N$ V
    * F3h6 o% @7 S! X7 M0 |, R

1 y! F% g( \7 W设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。0 L5 A, ^0 B8 k& i
; G- S3 q1 y3 [
    * F4h  r5 r; N3 T3 f8 r! r, M) s+ q
& N+ Z" ~' E5 C* m# I8 I0 Q
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
! n: p% q1 c& {6 e1 [$ i) H+ |) A0 ?; Y
    * F5h+ O& N5 I/ {7 ~

- |7 @' y% {7 l& R' m+ j- y/ \设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。
) j1 Y  P( i- L$ }( @! K- e! }
8 i* N6 {4 u9 y8 E- {    * F6h
5 q6 R# Q2 }+ R0 X7 A; [) p% o+ Y" R3 ~2 y% I( z: f
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
! N1 d0 G, A  ?# s& f
4 X3 M+ \8 _# Z7 a    * FEh
; e9 b7 }5 l5 {0 c
" x1 c( H* R: ^: ]! Q8 V( ~Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。1 e% k& G# t  K, _

; Y# H( q) l9 K/ O1 c2 _4 g! m8 Q- \    * FFh
$ J% j: L6 K, J4 c1 [( ~: w% P' O( V" }7 q( V7 B0 a9 o
Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!" o) H5 c0 }2 Y* E! b4 i- l
非常详细!  x$ J- J1 f5 Y
谢谢!
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-20 08:34 , Processed in 0.050953 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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