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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上   , h9 G% J) ?& M" Z8 {3 D. f

5 P' V. h1 a' S5 S' {! k% c4.2.7 Command& [, v5 F" ]1 C% e" Y
& c% k. E! u& H3 I3 c
通过8042芯片,可以:% c; _7 S; j7 c
向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。
  @4 _% H# J0 [读取Status Register的内容(通过64h);
1 K+ A& D, c: r2 L' R向8048发布命令(通过60h);
3 T+ ]1 |. {3 S: o, [2 T' m( ]读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。8 H( J% \0 v2 g  e, J
! O% l+ T- O' O8 m( M+ O/ {
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。1 ]& w: m, J' f! W& k* E

4 H- I1 X6 Y) `9 l' y2 q! z
" C; ~5 L, _: f5 A+ P4 l8 k" e3 Z" |# S* [5 u# ~
    * 64h端口(读操作)) d) X% Q# F  p( w* W- M& J" K! i

' f# B+ \2 }: h% ~9 L* L$ l0 j# v* V5 J+ z2 J  ?& K6 [
对64h端口进行读操作,会读取Status Register的内容。6 x% }% f4 j$ v! Q: q4 r- I

, g4 X. Z# i/ h0 g/ Z/ b8 G  linb %0x649 V5 a5 s4 y! t5 R9 g, }9 ~
执行这个指令之后,AL寄存器中存放的就是Status Register的内容。6 B7 U+ U/ A+ [) f) F) s

1 Q) Y0 |. Z! ?    * 64h端口(写操作)
! S' a' F6 j! Q' P* S% C6 y+ Q/ H  V
向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
! |. `0 j8 V1 r( @: CŸ
4 @3 r4 M! v7 @% b3 \写入的字节将会被存放在Input Register中;
  ~) J9 t9 Q% PŸ. \/ V) S6 q1 p
同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;+ s: q. ^7 t0 q0 c; D
Ÿ$ O8 f) i0 `* ^8 a$ a! T
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;+ t1 D5 Q( u% t+ n% e
Ÿ! \: J9 ]" n7 \0 T( j3 v6 x
在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
( |6 Z9 w& l+ S. ~, L/ K' l
/ F+ W  T1 z7 e( k, c& |void wait_input_empty(void)
: c3 o$ r7 n' ^% ]8 \* `{
% E0 W+ `$ n8 ?& l6 A. w+ w   char __b;
1 R/ J4 S9 @" K, }4 b
" p: g! Z# F9 H0 T& V7 i# j( Z& T; ]   do{
9 e$ N  U2 J" j$ {% `* p2 u     __b = inb(0x64);2 l0 q0 h7 m8 g+ `+ l! v; s
   }while(!(__b&0x02));, }3 ?7 c8 s/ K* f$ {0 Q
}4 ~, G3 [4 F. g9 E' I% }
1 [, s9 {* m0 |$ o5 M
void disable_keyboard(void)
  X# m, o) g) ^! Z; H1 }{
# Z+ ^5 J# P6 ]1 S8 Q% I" y0 r   wait_input_empty();
* V. J9 L: v0 F8 I7 T# i   outb(0x64, 0xAD);, D/ A, Z6 {( {* p6 }( s
}[size=+0]* v+ W& o8 X' i( V+ s( W% d

" j8 u% x3 w, ~! ?    * 60h端口(读操作)
, T3 c8 |" J- G8 v1 O
* Z; d2 B8 R2 R7 ~9 j对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:: k. k. g4 d2 ^) g# h
Ÿ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。
4 V4 f- _- @$ XŸ           通过64h端口对8042发布的命令的返回结果。
# Z. X1 ?4 A6 V. E
* q& r4 N- t" @1 \在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。' S! ~" {/ d7 L1 [  o0 h1 o9 K
void wait_output_full(void)" g4 r$ d: U: ]# s
{* b6 u& T1 ]. z
   char __b;6 H5 D5 F5 u  A' Z& i
! j7 I* K8 `0 ~$ @
   do{* {6 \* @5 \2 P' ^) E7 `
     __b = inb(0x64);2 [5 f% |  C& C! P" Z1 |
   }while(__b&0x01);
: z- x* M* ^# @6 t  u4 e, X: ^1 c}2 X8 L, [* u/ \6 R7 o, l" B" d% Y

+ H3 ?  m3 n8 P0 l6 Hunsigned char read_output(void)
6 G0 q  j) s. Q6 n  o4 R" e4 K0 ~4 H{
! n1 D: U3 f5 E1 f" ~9 U   wait_output_full();+ x% Z9 W4 ~1 J8 |& G
   return inb(0x60);- y- ?9 F3 c7 ]" U; Q4 Y& U
}
" z1 W# i3 `9 q* h2 {1 {1 M7 R# I
    * 60h端口(写操作)
9 Y+ V7 H* Z9 I) h8 q  z2 V' z, ~: p0 z
向60h端口写入的字节,有两种可能:
* p$ p. r- p3 W6 w1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
" r: Y' V- v3 }5 k/ K2.否则,此字节被认为是发送给8048的命令。
. \' t. l3 Z2 V, e+ e
: c/ d; P* I- }& l- c' L在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
0 R; _/ Z0 q9 Y6 }1 u
1 C, O6 p" \  m
  _; G" l% x5 }9 w+ ?+ b[size=+0]4.2.7.1 发给8042的命令
, ?3 J& E6 _  f3 B0 q% G- ^4 w: g& z
    * 20h * r2 ^/ v3 X0 V1 O0 i* Y- ^

) Z0 G/ H1 r% x1 N  U0 p准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。: J- Q8 ?  B& H

. [- T6 I/ m; ~3 V: S; }5 f
' c& D" ^( V: |" Y, xunsigned char read_command_byte(void): ?% k1 U! e0 `& F! Q8 V( z
{. h) a/ e# D4 i2 J
   wait_input_empty();
) `  |8 K* a9 E. x7 m5 j7 i8 d1 h   outb(0x64,0x20);
* z7 Q5 i# k! G) r5 Y   wait_output_full();; F0 y3 H4 g" D0 k! B% ?) I* Z
   return inb(0x60);   * e4 p" r' ^. l& E+ b1 ]
}
( q% a3 R% c: D8 J4 N
  O1 |) N5 N; b! l& X    * 60h) I4 U. I) L6 x. E3 @7 u

4 d" T7 C" H5 K准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。
7 @4 u5 ]/ \1 @6 p6 S8 c7 u, ^8 M# U( o
1 Y% L. R  ~1 B
void write_command_byte(unsigned char command_byte)
, k8 H. h6 E; E( |0 y% }5 @7 [7 L) c{
! ?' X0 g2 p7 z- T  V" S   wait_input_empty();
% C$ j( Q2 {& f! i2 p/ `   outb(0x64,0x60);
1 r1 m6 C4 V" J   wait_input_empty();
, @8 W: Z' V' B* c% Z   outb(0x60,command_byte);: A* T1 J' K0 \3 D1 a5 X
}
/ X+ H9 r. z  M+ ^  R( Y( j. r4 r# W* O; y3 k7 B  H
# C7 x/ n' R  O. k6 m+ a! Y; ]) [
    * A4h
8 B9 [9 @% y$ c: i  w) H5 G! N* J4 k/ x  x& z3 g+ P: k. {
测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
2 K* z9 E$ z2 T, F+ ybool is_set_password(void)  Y( q* p1 k  j2 y* J( {
{
% u" P/ A; R9 M; P   wait_input_empty();* u3 A' ?  @- n! s0 |0 }3 @7 q
   outb(0x64,0xA4);
! a6 {' l+ Y6 h0 t( n7 \4 z   wait_output_full();' X' s: F+ U1 x* V8 C0 @: i" A, B
   return inb(0x60)==0xFA?true:false;   ' z0 \1 O, m1 S0 g1 a) S5 r& V
}; C+ Z0 L! e" V/ u' A; f3 U+ `) Q
1 g8 y5 V8 j& T8 {# q
    * A5h
' `( I, C1 h- L! g6 o0 Z6 L5 `3 ?8 q
设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
3 I, s% m1 p$ I# Zvoid set_password(unsigned char* password)
/ W5 L: @$ ~; X/ z- g& }' v: L{
+ A* f5 i' u. H* }  }   char* p = password;
- ]3 [4 n( x& U2 f2 `& r- R
' K6 H/ z3 ?1 k6 ~- v2 Y4 s   if(p == NULL)
" l3 e# \( O1 \8 N      return;, u$ `1 J! X  E2 E0 p, `, U

3 Q& O" U! a' ?$ }# d0 ?& @& l   wait_input_empty();
! l1 B  n+ i# ^' U" M0 `; A   outb(0x64,0xA5);
4 @2 m( }$ T- V4 m% p
- `9 M: H- b% r# `% z: u* U   do{4 x( h" Q1 ^+ I3 v
      wait_input_empty();
4 {. I. z, A& t( ^* i      outb(0x60, *p);
- Q$ L$ G& v* A+ U  i6 U* D" n   }while(*p++ != 0);2 _0 ^; k7 \9 {* |$ W$ c
}
% ~, _0 K$ j" ?6 c$ |/ l' c9 O) r4 u6 `
    * A6h
( |. ^( `  X" f: m3 s
0 @- M2 ?, R9 b$ l- g1 L" S让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。% B* o" l" G% Q4 `
void enable_password(void)9 {$ o. [7 v) A. z2 Q4 _/ _
{
& O  f3 S% F! L+ v   if(!is_set_password())6 H* P) E! d7 [; Q( O
      return;+ I: V0 [4 p, P) }+ I

( e; c! L) X# ~7 q   wait_input_empty();
  q8 V" @% a- w8 Y4 l4 T$ f; i$ w* S   outb(0x64,0xA6);   
* n$ Y- @5 u8 ^0 N}
3 T0 R  p+ w: ~' t; t
5 e; O) u7 m6 {' a    * AAh+ c* `& C; a4 e/ ^; O

; T: s% @8 v) c4 O自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
% K( I3 z  O& p, G5 m5 l3 C; }# H& h6 d# n
% ^; I) e7 t- A' Z
bool is_test_ok(void)
, t8 I" f0 I8 P2 ~- M/ G2 A4 r  H2 N{
8 L, g! w9 C5 z7 O( J) e   wait_input_empty();) ~$ ]" v! B# y0 z2 q
   outb(0x64,0xAA);" `5 }! C; U3 |6 [7 f* c
  o  ?/ G( c$ }! Q& G5 u4 I
2 _" T& Y* r) b4 i! z, o. z
   wait_output_full();
6 x" c' a1 m9 q2 s" D   return inb(0x60)==0x55?true:false;   
9 g/ t2 y% x0 s) p4 |}
% F4 P/ ^7 M6 S# E! i5 Q) |& N& P/ F1 R& t* n. @
: ?3 g* v" f3 M3 V. j) k! I7 G
    * ADh
# d% X0 A7 J) y+ A7 C6 G7 F* j8 ^- E% q4 O+ l: I6 ~) G  I2 ^7 J
禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。
4 r! }; j4 N& s+ w5 O9 Mvoid disable_keyboard(void)
# d2 N% f8 q6 ?{- Z$ Q8 u- ^& O; Q5 n8 a7 \
   wait_input_empty();( `: @1 a2 P# a" e7 z0 x
   outb(0x64,0xAD);
) z1 f. q( D: N
, M9 P- _; h# w2 [. G& m}
) p& v& E& m0 J; g, e* @- @) D: V5 o  k+ ~+ j/ |* ?
    * AEh
* ^3 z/ c7 [, W2 I
/ v8 o4 y" K, c4 `4 H8 X打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。" m* R7 m1 ~* y0 P5 Z2 {# @7 g4 `
void enable_keyboard(void)
" R9 @8 V5 f: I{
; X5 s% C( U1 ~   wait_input_empty();
& {6 s4 Z* k8 @8 o% U1 ]   outb(0x64,0xAE);# o9 C& D( A3 D  H8 ]

1 y' ~3 x2 _, _: Z6 @6 F, j( F}1 `# M" m5 ^7 Y2 v

- Z% e2 O$ O! t+ {2 n! l4 J6 a    * C0h9 e/ Z; B2 x# J' F

* B# o2 j3 T1 T% H准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。/ z. T$ i& i, E* e" ?% B
unsigned char read_input_port(void)
8 E: z6 D+ u. d2 p. f, |{' i4 {) `. Z  O/ o; Q8 O
   wait_input_empty();9 D" `3 u  p+ I0 `' V
   outb(0x64,0xC0);
& U- H& E7 H' g+ u" R3 z( s3 ^! D7 k
( R5 |0 }# O& \+ M   wait_output_full();; F% }8 j9 {- x3 {3 ]

9 Y% l9 x$ ?- b; h' T3 H/ X$ |   return inb(0x60);5 x2 P) [6 }6 v  A1 p6 W9 ]/ A
}& A. B9 g; I0 w6 V, s2 ^! Q
$ ~2 n4 l5 f* `/ Z- v
    * D0h
0 q- n3 ?5 m3 x- D" f& B% f1 f. B
9 J: P) R+ T; z5 K" y' Q8 L2 _准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。
3 Y; u  F; H, b) @unsigned char read_output_port(void)
  j* a8 m) d7 z/ n{
' r: j& Q$ b  Q1 p1 ]0 j8 O   wait_input_empty();* w  V3 @  \& Y+ `
   outb(0x64,0xD0);
$ L; N4 ~# G7 U* X* U% q: y% R1 H
   wait_output_full();; R! ^# a4 Y) E) n

0 A! G8 `& v) K   return inb(0x60);  Q1 x  w$ ~; d# w
}: h2 K6 m" D" b/ w& }7 F, \6 V2 [
% ^* ^0 }- |: k/ O
    * D1h
. D+ S1 d+ D  m9 }% Y
$ }1 v; r' L5 \. m( ?( i准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。* M: T/ i9 x% r
void write_output_port(unsigned char __c)
. J' {( Y) c$ c1 A{- @9 z5 t0 R" g: E8 v- ?
   wait_input_empty();2 B" a. o1 ]4 N6 T7 }, E# _8 j
   outb(0x64,0xD1);
+ P+ Q6 f4 ]+ Z5 ^* V
+ ~. U( I, @2 W9 W0 ^! [$ }   wait_input_empty();# `: w; D1 @: z, d( S6 L9 [; y2 E
   outb(0x60,__c);
( Z+ `  v" B+ s6 |3 K: a5 N% e7 K4 g. g  J
}5 R+ ?# @' H; g3 g2 l) E4 ~
8 p5 Q2 K! x' P4 `  x
* b& {( C9 @# Y. m' v
    * D2h. ]& d) Y( x6 W0 W

9 }) ?* T' l+ Y1 f/ N# u8 a准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。8 L1 n+ U% d/ E; i( ~- o
void put_data_to_output_register(unsigned char __data). f8 i5 Z9 J2 H
{
9 x3 w# _7 c3 w( s$ m   wait_input_empty();& B' s3 i" f# ]3 f9 t% T; T% E& c
   outb(0x64,0xD2);
( V1 }; R% l9 I4 m7 U+ \: j7 f. ]! @6 K! ^
   wait_input_empty();% Q) W' s" L; v( p
   outb(0x60,__c);! _$ @0 j( x& Q+ V
}
9 h0 `, ~: x" t  n9 m6 b  a  ^! C. O
4.2.7.2 发给8048的命令& h; n! i" A2 L4 b4 @" M+ j& j
3 S. T3 T& B8 `4 }
' ]" S. r3 i, J% x) s; n8 p
    * EDh4 f; O9 Q6 w* i) _

$ H0 O+ f6 \. v4 D) ^" T  J设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。" c, I& z3 ~) e2 n
1 O2 q0 P3 w! N' `% ~* s' `
    * EEh
# o* W& J& e, i5 a- M/ p2 d: a$ S! x6 ]( v6 A# g1 R
诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
$ P. `1 X8 B% t/ j2 F% {" G3 J; l) r( X9 w# ~
    * F0h
+ B7 ?1 h! O2 G) ^  y4 q( x8 b
: {- j3 I4 C- t$ Y. I选择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代码所要求的。- P8 Q3 J; Y: v! _5 r
' l$ K' r; u+ N9 t- K) J
    * F27 T* j* R; ^3 k
% S6 H+ E7 H' q- T% M  N
读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。
5 i( Y( q3 Y, ~" T) f/ _; q5 D( |6 A( ]2 ?+ g9 o. d
    * F3h3 N  Y* H% E. P* V6 t
5 ]: h3 y$ i/ J3 D( G, ~, D; |0 _1 l
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。  h; n& ^# l+ y' Z+ m) R; z

+ l* N; J( V: G, x. N3 n    * F4h
/ u' |8 [% X" ]5 Q, c% u$ d# W8 G
2 F6 L. z( I+ G8 H% N清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。
9 }" _$ W9 p7 ?* t3 |! L
( x: S/ N8 ~4 F2 ~; h$ P- W+ L    * F5h
" \6 k; l/ ^. c$ v6 K& o5 g
* N/ \8 B) ^' h+ J7 I" g设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。# n* H+ T# `* j3 {! Y3 }

  n# S8 ]" c/ x; r  \    * F6h- z" Q" M; H! F

% f! Q/ p& i2 |: V) C# M7 \1 `5 F! p设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。! v3 N( r5 x' M! W

1 \" }4 u( C3 s) T3 s8 J/ [    * FEh
2 n( w2 B7 |! j$ {# [8 V2 k7 K) O6 F9 W; T  n# m& ?: y4 _
Resend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
7 T) _  \6 \0 Y2 A- H: F% Z1 I
7 v& F" S* U4 t( k3 t    * FFh
$ u5 }3 U" q8 I0 B8 t
  G5 V0 F7 X* ?1 J. i$ J' {Reset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!6 @% c- d" E' U; ~  z
非常详细!  l% L. D" \# [' J0 i, @" v
谢谢!
回复

使用道具 举报

发表于 2009-2-25 17:37:28 | 显示全部楼层
2楼好帖!在helppc的Hardware Data and Specifications栏里有相应的寄存器和命令详细描述。5 c1 P# l, E& i  B1 o

" d8 ^3 I; T9 f# e! \5 T6 ^) c/ r我的问题是,上述描述应该是针对老的8042的,在目前的使用EC的系统中,这些status register和command描述在哪个文档中可以找到?比如intel的santarosa,使用renessas的H8s 2104 EC,按道理上述状态寄存器,命令等的描述应该在2104 datasheet里,但是我怎么找都没有。还是有某个spec定义了这些命令格式?新手问题,高手莫笑
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-5-2 05:25 , Processed in 0.049288 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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