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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上     u: |/ m- G) `$ J' g7 D0 x3 Y
* E/ w  \9 G2 C# X& z
4.2.7 Command
6 }- W- E& C* d0 a
6 @& o; q% Z6 I# D8 v通过8042芯片,可以:! ~) ~3 b! l6 l4 d
向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。" d+ A& [& G! K. ^/ q
读取Status Register的内容(通过64h);% T- M$ D$ |  Z/ {0 p: }8 j4 k
向8048发布命令(通过60h);6 z$ b9 ^+ Q4 e8 m
读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。' Y4 E! F+ T! i) o) k2 k
* t+ z6 X9 m% I8 D( V6 v
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
0 J1 t" x' n! m; w0 x8 Z  S8 r7 T  b. u* v: \( J1 ?5 z
1 H' _$ @* a9 L# j2 f
1 I5 N( H( P% \6 l$ r0 A$ u+ V! d
    * 64h端口(读操作)
: T1 h) y& H- ]) @0 w
) e8 ]$ `0 z7 w' e9 n9 f& y3 h$ U6 H5 r' }2 {/ m0 l' {  V* I
对64h端口进行读操作,会读取Status Register的内容。
- o2 `. x$ ?& D' z/ o7 G& A0 D9 c% I, A
inb %0x64
8 u  t- s' ~  S. W' F执行这个指令之后,AL寄存器中存放的就是Status Register的内容。
0 V0 T/ n2 ^. Z
1 y$ @$ W4 L+ f- z  k    * 64h端口(写操作)0 Z2 n. Z6 x5 o; I, A/ u$ Z
; E' x9 Q; X" g) H
向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
0 ]  _- j/ i* c+ sŸ
" p3 R! r$ e; F* T5 a写入的字节将会被存放在Input Register中;/ a+ H! |+ V0 @1 {* y# _" c
Ÿ
, I2 x" L' h% g" y' N; X& p# [同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;  ]& O/ `) b" l4 n* U
Ÿ
' T+ A# K9 i2 k, E" T# s在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;' G( o- @  n3 u; e# W
Ÿ
4 M5 S& H) L3 z+ M3 @( K  O在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
6 _1 O+ v; l: z& p( \
' ^( Q1 U  B4 y$ U3 \void wait_input_empty(void)( z& h/ e4 P# L& s
{3 X1 f- v1 `% w) P7 ]
   char __b;
# E7 q1 l) x* l& P3 R# |: Z1 j6 y! C4 @3 p, T/ P/ h0 G
   do{
0 s9 d% c& C; f  z- k     __b = inb(0x64);
  I( {' r, z' O. W, u8 Y" I   }while(!(__b&0x02));
5 ]* d* z' v7 |4 Z}4 r8 l, l4 H; }& w
% q( [2 g# P- k
void disable_keyboard(void)
) f* w0 p$ P' e) n1 g# ?& f{1 J$ z6 C: L8 n% f$ e4 B/ R1 ?1 [
   wait_input_empty();
) g  T# i- P# U: `# a7 K   outb(0x64, 0xAD);2 W! q( M6 S) ?, j0 _6 J; f; l
}[size=+0]/ Y9 t; b/ G" ]- R: @
1 Q" H7 C1 E: Y
    * 60h端口(读操作)7 v! K, ~! o" H# Y- E' [

4 D3 T5 U) `0 _4 w' S' h. Q; @0 p对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:
( p8 |0 M- D& `* Q! _Ÿ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。
- e" V- Q6 A5 {* CŸ           通过64h端口对8042发布的命令的返回结果。
2 r+ k& w$ O. L0 K! Y
  B/ T, H3 R& ^# w0 L, M在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。
, O; _) X* W1 k$ U; P& g* Ovoid wait_output_full(void)2 E" L" m, [0 t: G, e
{
1 D$ ~( M* B6 x& @! o   char __b;
5 ]  o4 J3 ?3 |  f; E7 B: U+ A# @  R. z
   do{
+ Z& G4 ], ^1 a2 M& a  V5 S     __b = inb(0x64);' y* P8 G1 W6 E. W
   }while(__b&0x01);( J$ {4 N5 `* D- B" S4 `4 ?. C" X
}
, p" }- ]2 f+ l7 f, Z% J5 z, J; q
2 g0 b' d$ m, g! hunsigned char read_output(void)9 r% @0 z, @6 x0 k! e
{
' y# G* ]1 _. W/ u4 z' M/ Z   wait_output_full();
, r) S; l# `% {. U: D   return inb(0x60);
% R4 ?' g  B. {  N# R4 N8 [& y  ^}
; i# [7 u. c7 [' |# `( }( ]6 U2 w( t: }6 A3 R" ^
    * 60h端口(写操作)
/ o; N/ L4 D7 A) |2 J9 X" T; l: N4 L2 O
向60h端口写入的字节,有两种可能:+ Y; F" d( d( i/ m
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
# j/ ]5 R. c8 I1 I7 \) j/ W2.否则,此字节被认为是发送给8048的命令。
- Z& v* d$ h$ e3 S" q
2 q' s- {* v& w7 o$ s3 E在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
3 m: y1 L* r# y- M- B; L5 U. I1 K! s- P3 f7 A% [5 T
6 V1 P4 i5 a0 ~. o! T4 i) d) @
[size=+0]4.2.7.1 发给8042的命令
5 W& _( U8 }5 \' W+ N, X& {0 W; F
    * 20h
0 \& E7 o4 |) ^3 D; Z* C1 n7 Z4 [# \
% y& `1 ?: d+ ?6 R5 N& k. I, Y& f准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
, z/ t. S) V% q& v6 g! _$ F, s* @6 d4 l+ ?" x6 H4 ?

3 h6 w. V* z: Xunsigned char read_command_byte(void)
" g" t6 Z9 e' ^' s% {{
- M6 M1 H0 z4 N8 e( f0 K   wait_input_empty();1 J+ Z6 d; p! N5 o, b. J
   outb(0x64,0x20);$ h$ M0 w- \) {% Y3 M
   wait_output_full();& {. t8 v* }$ T. f+ \2 x' j
   return inb(0x60);   
( E8 N1 D2 v5 R; |- E3 @5 V) ]% S}
1 U3 H+ D$ B7 q7 v
$ l8 u& u. n" X* f7 T! m; k    * 60h
. z# V& D* D7 L6 B" H: q
% k" _- o- V9 Q7 I, @* Q9 A准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
+ N" g- @8 ]* r5 ?
) Z$ |/ z' y9 }
' L8 U: O% }7 B* }: g* {9 {  |void write_command_byte(unsigned char command_byte)* L; g- m; m9 L9 c
{+ n5 c$ N$ j' G! Y0 F" S/ X
   wait_input_empty();1 J4 Z2 Z- ~; ]2 t- u: c
   outb(0x64,0x60);
2 C. F5 {+ j( T   wait_input_empty();# |, ^& x* |+ L# x. B+ _+ L
   outb(0x60,command_byte);
1 i7 S  @2 e+ p$ a}
+ `& V( C2 }4 L6 s4 S! R4 v7 F
8 O: e7 N. s$ z6 S$ S4 T$ n
3 q0 Q. V% [  b; E0 L/ @1 |    * A4h5 U7 p9 z5 K+ l8 B+ M

1 i# A7 E9 P- a) S测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
" \& `! \: G0 _; ebool is_set_password(void)$ X5 ^6 d1 N/ n7 a6 d  _( p4 k
{1 D6 E! a8 O  f+ f
   wait_input_empty();9 @. W& R, \( k
   outb(0x64,0xA4);2 o  a* Z8 s; E( t# e
   wait_output_full();
' V( X. c" N+ ?7 ]8 y' {   return inb(0x60)==0xFA?true:false;   
1 `) H: O! Y/ a. Q$ C2 m, k}. W) u0 B' F! }5 t" h6 S+ I. w% U
/ {9 \, _: b: m- q
    * A5h2 |9 [8 F5 b8 t
  W$ R* B6 B! y3 W& y- d& Y
设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
% p2 N" r( t2 T! D0 F; ^7 Xvoid set_password(unsigned char* password); o( s0 e4 x5 f( K2 U; G5 e) p: Q% q
{
( f2 L. w& x" f# d# _) i   char* p = password;
6 M9 a' c: C9 y* T; P$ R
1 [" ?/ ~( M0 Q1 A   if(p == NULL)
2 f% T0 i9 M% j. x3 F1 V- e3 `  ]      return;
, U. e! E  y) \" N! W
$ n1 n: b; J+ T0 n5 v, Y" H   wait_input_empty();9 b2 m, }/ o/ P$ F( p
   outb(0x64,0xA5);$ O4 q" c) ~. Q4 G3 l( Q- p

* |: ]# a4 e4 c# }9 B# V   do{
# m  n2 y! L% B) L1 s      wait_input_empty();
# [/ A$ X% F2 x$ z  K      outb(0x60, *p);: |' i) k9 f4 k) i6 ~" Y4 W/ X" i) D' s
   }while(*p++ != 0);2 P7 \; m0 c3 k! X6 F
}. S, B5 T9 u# F5 |2 v
5 F+ A5 r+ v3 Q" n5 a" r2 b. S9 m( i
    * A6h
/ E% B/ Z' b$ n! A8 ]5 r8 E& W5 A  q3 E6 Q" c
让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。- e3 k/ j  E( P, }
void enable_password(void)0 o4 q1 J/ @# ]# G6 q
{8 q2 H  c6 W, ~
   if(!is_set_password())" J' C- j% J# k! R/ G3 ]
      return;
' n9 n2 o2 V8 F! t; j
/ r/ j* ]) A) z9 l* U( I; T! J   wait_input_empty();& e0 o0 {! t' A! T9 t
   outb(0x64,0xA6);   2 M) y6 _' z. X
}/ \+ v8 T( [4 C2 O% a1 T

8 e4 Y! d- |8 l1 o, D    * AAh
- L8 z: ]5 [/ ~3 x# A- S* f+ ?% d9 g  W2 I, I5 d/ o/ f
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。6 [3 [$ p; ]. A. u; M8 X

3 e+ [" B2 [0 S3 M: b5 g: w5 N- K
bool is_test_ok(void)! u! I6 m+ \% N% l2 \7 d/ Q0 i7 |
{
. M9 ~2 w" j7 L5 F% Q) ~   wait_input_empty();
. ~3 @( ^8 \! f& g+ w7 f8 m$ f   outb(0x64,0xAA);1 H" D' v6 n2 ^+ s- n# T" Z3 b' e

  Q3 B1 O  p. A0 k; w, Y# V( `
, H" `0 O1 ^; l   wait_output_full();
1 i/ U' x' N$ D/ \: F! i" S) X- g   return inb(0x60)==0x55?true:false;   , i. [* X/ b! h) d- h
}* ^) C, _0 R( x! ~9 J0 G1 M
$ H" G9 v& J& q* L( b" R
3 k5 w' X0 C  ~
    * ADh  I/ a% `( @7 c: P

  H2 n9 o( X0 d- F- M$ M' ?禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
( K1 R* M( y* B. [void disable_keyboard(void)
: h5 q9 a/ p1 u8 y4 u{
& F' E+ Y$ m0 V* U   wait_input_empty();# @4 V, K- `; G! a$ g
   outb(0x64,0xAD);
, C: z% b: b( k  j$ u+ T$ O* x! D
& A* C8 ?( x8 L7 t- z}8 f! V. f& Z! D: S

5 R% I) ]1 B' D3 r. ]" i6 r% U    * AEh
: p- k. k4 z6 m+ M) c/ ]( p
& R9 K  R' D# u; q5 T5 X打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。. l' I! Y! A0 g
void enable_keyboard(void)
2 S+ y3 |/ K0 g' z# g/ I{
6 H9 R% X, l! q2 ?8 ]( K$ E   wait_input_empty();) n/ ]+ K7 g' X* s4 X9 @' s
   outb(0x64,0xAE);
1 n9 v, Z' `3 Y6 E1 S4 G( [& R6 B( C' o# D
}1 \/ O! F+ w( e0 k" i

6 Y$ |' x6 n, x2 N; b( s7 s( @    * C0h9 v: F1 f; D4 v6 n/ Z- e

" J5 M  R$ ?: N/ t2 U准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。3 Y& E2 P1 ~# u) L
unsigned char read_input_port(void)+ \& z" ^' M4 [! ]) E
{
: D3 F. G' C; e1 K( r- L  Z1 A  K, Q   wait_input_empty();
9 G" L+ N7 i1 i0 @, s3 O+ ?   outb(0x64,0xC0);
9 T/ Z" L: W+ c" d$ z* d( K2 ~9 h  b4 X0 T( L
   wait_output_full();2 u& C; x- x. m* L5 Q# q- X8 r6 I

/ W7 o' K4 n* S' D% _! y* H+ G% g   return inb(0x60);) w: F* i" h& E; w+ @. a! M2 C8 t8 R1 L
}9 T- e6 g5 e8 K

$ H' q/ K$ m% I- |6 v! Z    * D0h% L$ }# c( I. K
9 D4 V" U$ \! h4 x8 C
准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。
5 N6 Q6 Z% G# T$ N8 q2 _0 bunsigned char read_output_port(void)& |1 I- @8 k! e$ l( `( n& _
{
; x" v2 e+ P% w   wait_input_empty();% U9 R% K( g; ]3 y. q8 I3 S- w
   outb(0x64,0xD0);0 h% f) P) {% ~3 n$ P& u
) x( s& }; f6 D; W& X5 F
   wait_output_full();
* {" @0 Z" T5 Q# a9 I. U) c2 @3 |, X; |7 q4 P1 U: E
   return inb(0x60);
& q' T, L+ L/ U! o( S* I  g1 D6 d}
# ]# i% ?- b: D( |& s( x
" c7 O  A: A1 V' H% v! \1 }    * D1h8 `0 G) H0 p/ _) r4 O- g
! U) i, L1 R* Y6 J' k
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。5 q' m  F  g5 l6 D3 Q2 R
void write_output_port(unsigned char __c)
' G- m8 G& r/ A{
: e" e5 z. Z/ F" |% E   wait_input_empty();7 d. I8 a# U. |+ T) f- `. j
   outb(0x64,0xD1);
! o1 O1 L# v: E: ~
! ^3 a4 a$ b5 |0 \2 T   wait_input_empty();5 l# P8 c% s" I4 @+ Y
   outb(0x60,__c);
+ o0 ^) S; N/ _- N# i+ I
- h& S! _. N/ n& V. s2 c9 E! D# b}
0 n. }# e4 ]' K! M6 t8 [" g
9 L; V. G) ?/ W3 t) _& q0 Q& K) o* n( ~# t, Y
    * D2h
: H1 ]. t& V+ G4 z% ]6 O3 O# D, w
准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。
% \6 t6 x/ t5 ovoid put_data_to_output_register(unsigned char __data)
: S% {; O8 ^0 r+ c{% T0 P/ b; W7 X4 j) c9 _
   wait_input_empty();3 ~6 [. V* S; s3 ^1 A# \6 f, }
   outb(0x64,0xD2);
0 }# Z+ j) y- g+ }# ?/ b7 c5 ^0 e6 e' v1 K  |
   wait_input_empty();
$ W, X* p8 O- A" ]( J/ W- E   outb(0x60,__c);
! X' d; U. J" y* t2 @$ G* r/ M}
( u& \- N; w& R  _% \+ j- j% i& r5 U# l2 t( m( y; j
4.2.7.2 发给8048的命令
) W5 r% q! w% s8 \
- R% J% t, F9 A1 e
( P$ E- g- W& X. T    * EDh
. O  n+ ]" X0 W! [9 [2 N3 y2 n
, \, P6 y- q0 p5 u% p9 _8 w9 L) C设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。
5 A  r3 X9 j+ x, x# C
! H# _6 z$ X1 ?! c" ]    * EEh# F! H5 p. r, Z3 k( S: \% T

8 `' L. Y  X& {5 j1 F诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
2 h! c( W! G! `8 h4 ]% q$ L+ n( l: b; `
    * F0h) `" N. e$ a  \
: n4 d6 N4 H. n) F$ J
选择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代码所要求的。
: r; o  _8 f' l0 \& o; h3 m3 n$ K7 ]; Y; l# R
    * F2% J: K( M# d) Y! @: T/ o
5 Z6 m3 \. E3 g4 F+ P/ j6 b7 G
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。
, e' ]# R* s2 P1 o
. j; }2 q7 t, H5 d1 A+ o    * F3h& T" `4 O3 J& x3 L4 a

7 O( h% M& T% M/ n! t* F设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。
2 M2 a- K1 t1 X& ]$ C9 H6 e( W* R3 v4 B# f/ \1 [- F5 j
    * F4h) K1 H2 p2 j2 x' D* n9 Z6 t

. F! m5 ]# t# x0 k! X清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
: i( k7 H/ p$ i$ |# d) @* ^6 v4 f6 j4 g, o. z6 |3 ^
    * F5h
; I. X% w; O. _7 g1 F
4 i: s: Q, E" S% }! K" D2 G设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。
$ R. I1 u+ q: Z. s
# d  [) Q) C$ A; C    * F6h
0 @% q( p) l+ R% Z% C  s3 {: Q
设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。) V% t/ R) W7 k) G
3 y! S7 |% X" x$ }4 Z
    * FEh6 l% n, V2 `2 i( B$ F
! D# ~! w0 p# m: U
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。! T. A3 u/ `+ h9 S( a6 z
# j3 E; H! D1 k1 L/ x$ }/ N2 V
    * FFh
( W' t  x% ~$ {* `8 y! f- @- R7 i! L. U( E' Y- ?
Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!
) j# D6 n  d; B9 W3 z+ U非常详细!
3 S5 v. v) S; E$ u! p谢谢!
回复

使用道具 举报

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-3-5 14:40 , Processed in 0.084153 second(s), 16 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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