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

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

[复制链接]
发表于 2008-7-14 00:04:00 | 显示全部楼层 |阅读模式
bini殇,能帮详细解释一下bios post过程中的所有发给ec的60/64命令号码和意义吗?数据量比较大,截不住。
发表于 2008-7-14 12:09:38 | 显示全部楼层
转个别人发的,不知道LZ能不能用上   7 U1 ]! c/ ?+ d  }" e( u

" ]; c1 e% }5 F8 L  w6 \4.2.7 Command9 N$ w( @& W( U2 p1 Z

$ s( w5 S. S. X6 I: {4 K通过8042芯片,可以:# t3 S0 x  f  t7 f! ?  s7 H
向8042芯片发布命令(通过64h),并通过60h读取命令的返回结果(如果有的话),或通过60h端口写入命令所需的数据(如果需要的话)。! \, k: V. _) E
读取Status Register的内容(通过64h);8 Y. P$ W/ X. P9 z, c; F: U
向8048发布命令(通过60h);8 V1 a2 D% M! W9 x$ G5 l! p+ Q
读取来自于Keyboard的数据(通过60h)。这些数据包括Scan Code(由按键和释放键引起的),对8048发送的命令的确认字节(ACK)及回复数据。
% R6 F" L4 b$ Z4 H, l7 Q7 |" Y& E, ?2 O+ t
再次强调一遍,Command(命令)分为发送给8042芯片的命令和发送给8048的命令。它们是不相同的,并且使用的端口也是不相同的(分别为64h和60h)。
3 G' A2 O6 [: n8 H# r+ m; Q1 t. ^8 k3 R/ Z. L  W3 w9 W
) J1 |& `  Z" O' I6 N

# c1 d, ~, b; _* j* Z$ f  o8 t    * 64h端口(读操作)1 M, W! e5 H- j/ f

9 C" ~" k+ Q& s. h4 h
* Y: e( M. u, _/ \. k8 @对64h端口进行读操作,会读取Status Register的内容。8 O1 z2 X- W+ ?

$ D9 T0 T, @9 k+ E7 n  @9 Kinb %0x64
% h0 I( A2 Q3 ~' S- D1 y执行这个指令之后,AL寄存器中存放的就是Status Register的内容。! k, U% G$ w. F! k% @4 X) m% M

, d1 z0 g0 F5 b" S2 l2 E+ X    * 64h端口(写操作)( o; S9 F$ c( d* x

" _  [2 l+ B! E1 M$ N4 k向64h端口写入的字节,被认为是对8042芯片发布的命令(Command):
4 q" D5 z6 ?% P: }+ Q, i- T. @6 yŸ) p  j: X' q+ `/ V- v2 O- X6 P* \
写入的字节将会被存放在Input Register中;
7 o/ s1 I% k/ ]$ W! BŸ
9 Z; E6 P9 _7 {8 F% T3 j同时会引起Status Register的Bit-3自动被设置为1,表示现在放在Input Register中的数据是一个Command,而不是一个Data;: D6 \" T* W: |! U* \; J* }/ G
Ÿ) \; E7 d$ K  V3 L8 e
在向64h端口写某些命令之前必须确保键盘是被禁止的,因为这些被写入的命令的返回结果将会放到Output Register中,而键盘如果不被禁止,则也会将数据放入到Output Register中,会引起相互之间的数据覆盖;
/ d0 w2 w' G" f( F; @6 i) V6 SŸ
0 \( |- p3 _6 z7 P" ~4 G# R/ ]在向64h端口写数据之前必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。8 E' u& m$ D$ ^; }% m
8 w  ^( Z/ P; ?8 k# s" F4 i
void wait_input_empty(void)/ s9 R7 @% p. ~/ I8 @2 j( l: O
{, n- I$ H! q5 S2 F+ Z8 ~. r
   char __b;
$ N: I' \- i" u/ P: |; m8 U  w8 W
   do{; C7 C3 o: n: ]8 ~  B, f8 ~
     __b = inb(0x64);
$ Y4 o8 V/ @% j& w- x% B7 M   }while(!(__b&0x02));4 u* F6 I# b' ^
}2 Q  d$ M- q+ n- P6 I' \& J* I, A5 X

6 y3 m: u5 K6 t  ^# W" i# Z+ Vvoid disable_keyboard(void)3 d/ D- |; i& @: F+ i* V$ _" ~- F
{
5 T) y: S- {8 n+ l8 U& m   wait_input_empty();( q' X) K# t1 |/ i' t
   outb(0x64, 0xAD);
: N( X  w9 K% e1 Q, e% V4 Z}[size=+0]$ o+ j7 ~7 ]9 C
/ A( u/ f, W9 P8 p, O
    * 60h端口(读操作)
1 D& o' K& }1 D/ S* d9 Z$ q) B% T8 l- ]$ V
对60h端口进行读操作,将会读取Output Register的内容。Output Register的内容可能是:
' c5 k2 z, [4 M: ^. r; h( IŸ           来自于8048的数据。这些数据包括Scan Code,对8048发送的命令的确认字节(ACK)及回复数据。& S$ E3 r# ?- Q# r4 g: O- i& P
Ÿ           通过64h端口对8042发布的命令的返回结果。
8 D' D  h# C' C& V
5 M- z* d6 A# ]1 t0 A在向60h端口读取数据之前必须确保Output Register中有数据(通过判断Status Register的Bit-0是否为1)。
! L0 a$ o& `: Y  q. `( o: tvoid wait_output_full(void)
% M8 V9 h4 \& I{" W" r! z. i* ^6 o; O  k% W
   char __b;- a4 t3 z1 C$ s0 v

" [0 D& L, M! u  ^& ?   do{% W7 @& {: g, w# M. M
     __b = inb(0x64);4 L# T# b. f' E* H2 D
   }while(__b&0x01);
% ?' C  x) m/ ]) a9 U}
: s: Y' a% ~$ r4 `) @% {: X9 V- Y- h) z- w
unsigned char read_output(void)' n: X3 v) g  ^* r1 K# |
{
$ E' a# }/ E' y, F' |. P$ t& l9 Z   wait_output_full();1 a' z! K+ l! M" n& r* o: h
   return inb(0x60);! S/ @' ]1 ~& ]0 o; E* M. g
}. ^9 T- g5 l, b) J) f0 h: Z& ^2 R

/ D- ]& `1 a, u7 _# q2 H    * 60h端口(写操作)* [- l, U! f1 B  P" N
# p5 A# u5 J, ?1 Z" O
向60h端口写入的字节,有两种可能:: w; U+ g6 ^) P' ^: o- R6 o/ _
1.如果之前通过64h端口向8042芯片发布的命令需要进一步的数据,则此时写入的字节就被认为是数据;
( c7 A4 ^/ C1 o( |! |3 R2.否则,此字节被认为是发送给8048的命令。
$ X1 k6 ]3 I2 ^1 i5 ?0 k8 x, I) w  j
7 q$ U- E7 P. J( b" D, O8 D5 i在向60h端口写数据之前,必须确保Input Register是空的(通过判断Status Register的Bit-1是否为0)。
+ q( a) u; K4 I0 A( X
! a9 f4 N; a# g* v$ t( j2 N5 x/ {4 O$ g0 X' R' I7 a$ N9 a# z" `
[size=+0]4.2.7.1 发给8042的命令
4 d. ~3 F: `2 Z" A7 k6 i' ?; k6 a/ v$ l# L
    * 20h ( x& u. L5 A1 f- A5 @3 `9 l  d. ^
+ Q3 m6 S0 c' T, ?: l
准备读取8042芯片的Command Byte;其行为是将当前8042 Command Byte的内容放置于Output Register中,下一个从60H端口的读操作将会将其读取出来。
, s4 x; B; H) b$ a3 y) s- L) u1 C$ f! A5 w- _" G) B

, d* E5 |; z0 q* p) K7 t% Sunsigned char read_command_byte(void)* M; r5 @; B  Y9 i7 f7 r7 U9 O, U, T
{/ ~( ?  N2 \; j! {) w/ V
   wait_input_empty();( \$ c+ r+ a& W' `# ]/ z; W& i0 g
   outb(0x64,0x20);( G! N( K  m( Z* T' Y9 F% J
   wait_output_full();- w* Y! f+ d/ X
   return inb(0x60);   
* T' G1 a0 d) B3 W" H3 ?( N}
' ?9 h: z7 I0 m8 J
3 ~& z  Q, l! Q. L! Q: i+ t8 d! |3 l    * 60h
: E* y8 k2 l8 A; J% X5 b8 n" j; S# Y; R2 m/ j6 X$ \0 Y; h' g
准备写入8042芯片的Command Byte;下一个通过60h写入的字节将会被放入Command Byte。# B- Q" ~. q4 @) S6 f

. m" S2 N  C' Y7 ^! E7 t
! }1 h" D# G, v+ v) N$ ]void write_command_byte(unsigned char command_byte)
7 _0 e6 A% Y, b" J4 m$ t{
- I/ k5 O, t5 g   wait_input_empty();
  G: Q9 T# y9 Q( c   outb(0x64,0x60);8 p; D) `" L% b& m. O3 C% l7 v
   wait_input_empty();
  m7 O" k% t8 |. {   outb(0x60,command_byte);
4 i. j( h9 f2 X; b  j' [}
4 ?# D1 b5 r7 i7 \+ E* k0 b" q
% l4 T8 `/ ~. a: N  k
; c% E. t( e7 \1 e; X, Y, U8 A    * A4h
. I2 E5 c! t0 M6 @& D* A% q% O
" {% {' _4 a- ^. l; X7 ]* N测试一下键盘密码是否被设置;测试结果放置在Output Register,然后可以通过60h读取出来。测试结果可以有两种值:FAh=密码被设置;F1h=没有密码。
6 e& E5 ^0 ]! V% mbool is_set_password(void)# D4 g+ O  [: }" l
{* _* N5 M  F1 t. Y$ n
   wait_input_empty();
/ _" L8 B4 n) J7 n' p0 {   outb(0x64,0xA4);8 k" ^! g9 p  _) P! ?" T+ D
   wait_output_full();
- Z' q+ }3 p" e% Q+ d  s! i( n   return inb(0x60)==0xFA?true:false;   8 h! }& x; u: I% T4 c3 d9 G8 B
}
* K, X2 r% q0 ]" z4 C
2 X+ H0 e" ^' Q0 d9 ]) ^    * A5h
7 `* o. m0 `. @$ p" c, w0 G4 [0 d: Z+ N0 w( w! k8 h
设置键盘密码。其结果被按照顺序通过60h端口一个一个被放置在Input Register中。密码的最后是一个空字节(内容为0)。
/ q9 j( e- n. Kvoid set_password(unsigned char* password)% z3 l0 p; R8 d5 O8 [5 F
{* ?: x2 U  S0 H  [7 ]3 S& r2 E' L
   char* p = password;8 ^; K4 @' k! g7 i5 Z% p0 q

9 w  u' b% L. Y2 j8 ]( E+ A   if(p == NULL)( w8 n' t  i% y1 k0 |5 N
      return;4 h& R0 a) ?& X* R. R# x+ R

9 ]4 D; u4 w, I$ _" q   wait_input_empty();
% A/ v; \3 x. M9 _; O0 i* b   outb(0x64,0xA5);
/ M: B9 m2 ^% f  Y# _
9 w$ G! Z$ `5 v9 n7 N5 H, j0 @0 r   do{
6 `: @6 B- t) X% I' e0 p8 N* b      wait_input_empty();# k- K* R: L* m+ u+ H
      outb(0x60, *p);
+ x& R! x6 E6 V2 m/ T! q+ _   }while(*p++ != 0);6 F, @& L, K+ U0 T+ `
}
. f! X( D1 q! K1 y/ ~
1 U6 @9 }. L8 a! q2 Y    * A6h
9 E1 q6 C# @8 O- c. ~% u& F8 {5 c2 v3 n# S
让密码生效。在发布这个命令之前,必须首先使用A5h命令设置密码。
8 n& k1 s/ |- m7 w% evoid enable_password(void)& ~# {! N0 f: u
{  C& T! X- y% q2 n
   if(!is_set_password())
' p8 F  j- l7 p3 ?- _' r# q0 s: D) n      return;# V. i: o7 G5 i# H

3 Y2 T9 \7 s4 q; |! g+ ?% A   wait_input_empty();
, D7 V) ^) p1 x  O& G9 v   outb(0x64,0xA6);   
4 Q$ }9 I) y$ I+ y0 u9 L}' T1 P. j7 y' E
# r7 r+ c) W  |  Q  v7 z6 K  z
    * AAh
1 ?8 D6 W- O4 Y5 W0 ]2 K( Y2 U4 K
自检。诊断结果放置在Output Register中,可以通过60h读取。55h=OK。
; |3 f0 w! E9 T6 f
7 C, ~+ Y7 e$ `8 X+ q  d8 K2 E
5 c; n1 j' m+ [' k1 p) Q& zbool is_test_ok(void), C0 }- \" q, e& Z/ k3 \
{2 ~  }& a. @+ m$ O" H
   wait_input_empty();
! e/ Q- X4 b1 X! ?4 Z   outb(0x64,0xAA);5 A/ l* S6 Q3 W4 x0 a0 d4 d1 a$ i

  k1 w4 l+ C9 @- c
4 K& {0 n! \. b7 ~' a' D   wait_output_full();
: n# f8 X9 M2 Q   return inb(0x60)==0x55?true:false;   
. E0 e5 _" m0 _1 E2 _; z}
) s2 F# v. F1 \5 Z/ G8 \9 g9 g9 o* E; S! k3 |( s

* h& S* K! R. d( O' V$ F; y    * ADh
" o5 t! B' E% q2 w1 R
* T  s* F' [/ B, m, v4 K6 a禁止键盘接口。Command Byte的bit-4被设置。当此命令被发布后,Keyboard将被禁止发送数据到Output Register。( w2 U, w0 f  w# j# Y# J
void disable_keyboard(void)
) M6 v: i9 V* o6 S9 W6 _; h* }{7 B$ X. R, L% P
   wait_input_empty();
3 }9 c) L5 n! r   outb(0x64,0xAD);% m: j- R& u2 n7 |- z/ Q& e. }/ }3 o
, L6 O5 o: _1 r! C& j1 W9 q
}
8 u! E  l4 ]" d2 v5 O( S! l' v+ Y* o  M
    * AEh
) ^' r! L9 v# g, f' |0 X" ?) T9 b4 J4 D3 }
打开键盘接口。Command Byte的bit-4被清除。当此命令被发布后,Keyboard将被允许发送数据到Output Register。% h+ [, V7 P: q5 T0 b0 |. C5 L
void enable_keyboard(void)
& M4 |4 y" j0 @$ y( P{
3 C/ W. b/ R  _   wait_input_empty();& c7 I9 |- r* a( F. y
   outb(0x64,0xAE);
9 B, J0 F- u+ R+ G) I/ S' q& C6 K
6 s+ X. G) c  l9 l% u! J) y}3 g& L0 L# F: a
2 U0 v5 |, @0 |2 \  i/ n
    * C0h- N  l$ ^3 b! i6 @2 @! E( m

  Q0 r: d; w; \$ {! a7 K  @, e9 v准备读取Input Port。Input Port的内容被放置于Output Register中,随后可以通过60h端口读取。/ n* H1 W" a/ B, N
unsigned char read_input_port(void)  Q: G4 C' ^, v
{
, Q+ j( z/ ~! {  R   wait_input_empty();
- @+ |9 V" e+ _) U  H* K& }   outb(0x64,0xC0);6 w$ Y6 R; }; ?  O

9 F6 [5 l. `% a* p. i   wait_output_full();! o' C+ _2 e3 H- Z

$ v& c$ ?- g. t5 B   return inb(0x60);
0 V- F1 I6 j: m: D}  b, z. x9 n. y! a3 c5 c
3 M; L5 s7 ^/ H
    * D0h
6 r7 ?4 k/ t. F$ s1 I7 }. A* |
) [3 \" _4 c9 G* x准备读取Outport端口。结果被放在Output Register中,随后通过60h端口读取出来。" M; \& ~, X6 j+ e: a  L
unsigned char read_output_port(void): c/ S4 N2 T% c% h* t; _
{
% _7 Q3 [( R; G/ j   wait_input_empty();. W. S9 g2 r6 @
   outb(0x64,0xD0);+ Q5 P1 V) r- e/ q7 b  Z

0 H/ g' _- Y( ]3 K   wait_output_full();
7 {" p7 t2 q- e9 ^$ C# K/ ]* d4 [. M" e3 l  P" D- G0 J
   return inb(0x60);
( y! j  O+ H7 \1 }}3 M6 F2 |6 f+ k7 B3 D2 S" S% ?
6 n! p% F3 \1 W  ]
    * D1h
; x' i" S" j1 ^6 j" Z8 S  T( A4 m! p2 L. m. H: z/ m
准备写Output端口。随后通过60h端口写入的字节,会被放置在Output Port中。
! O& ~/ \4 x/ h& X* a7 d# l9 uvoid write_output_port(unsigned char __c)# D8 l3 `: z2 Q5 I! `0 N2 ~
{/ H- p; w8 ]1 A
   wait_input_empty();' ~3 Q+ |$ }) o0 X6 }  y% j. R% g: \
   outb(0x64,0xD1);& L: [: F0 E0 o' ?7 N

) e$ K. O- _7 p# u" p8 f   wait_input_empty();- y, ~7 ^: S: P0 o) m
   outb(0x60,__c);& `+ @; @0 Z$ V& `) Z. R6 k% q
! ]4 Q0 Q6 {3 Z  h, i
}
- l3 \9 M- [4 U5 v% u; m
. G, P% @9 z. r+ X- W% G
) x! p( ]" ~' ?# i3 z    * D2h
3 f& }! y4 r& W
, O5 ?. f$ k6 f1 A2 ?( a准备写数据到Output Register中。随后通过60h写入到Input Register的字节会被放入到Output Register中,此功能被用来模拟来自于Keyboard发送的数据。如果中断被允许,则会触发一个中断。5 E( s( v" [+ b8 g# b
void put_data_to_output_register(unsigned char __data)
% ]5 @6 J7 d' |6 @3 G+ k5 J* j{
7 ~0 u6 H" L! w9 p0 F- [: I: K1 e   wait_input_empty();8 y: P' T  O% h( m! W/ J  {
   outb(0x64,0xD2);
3 `& E0 b0 o! m5 C" u, Y; p1 K$ a0 v  S) k' H. ^% @4 h1 h8 |- [
   wait_input_empty();# V* q, R% M0 ?1 |0 R
   outb(0x60,__c);  o5 V9 g- S8 c" \! A5 ]6 p+ k
}9 e) Q. \7 v' q! }$ i; c$ ?
  n/ f$ F6 s! X/ \5 u' @$ h' |
4.2.7.2 发给8048的命令. z7 U1 n8 F8 D( B% b
+ z5 _2 j/ F; W- I  i
+ T1 y8 V; x0 o
    * EDh
5 V5 L* ?. l" {  d& g% T' `
$ a% K4 ^& H0 F设置LED。Keyboard收到此命令后,一个LED设置会话开始。Keyboard首先回复一个ACK(FAh),然后等待从60h端口写入的LED设置字节,如果等到一个,则再次回复一个ACK,然后根据此字节设置LED。然后接着等待。。。直到等到一个非LED设置字节(高位被设置),此时LED设置会话结束。
5 {/ i1 e  o1 }2 p# f7 S$ X4 `( \* a- F' E6 L' M
    * EEh
( B) z; x. q/ ~, k1 n
. |" U9 V% v) _$ q1 h4 y' {诊断Echo。此命令纯粹为了检测Keyboard是否正常,如果正常,当Keyboard收到此命令后,将会回复一个EEh字节。
. _* t6 M7 Q- m
1 e4 }! I$ y. x+ ?8 R    * F0h$ a4 O+ M. ]9 p# ?

- C: ^5 X3 p6 Z选择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代码所要求的。+ _! o3 {  h( R5 F0 [# @1 p
9 C" @# d: D4 a1 r
    * F2
" \3 u1 a- ^! C  e6 @4 b9 A( f
( U4 f5 ]2 o- H- B6 w$ v3 ^读取Keyboard ID。由于8042芯片后不仅仅能够接Keyboard。此命令是为了读取8042后所接的设备ID。设备ID为2个字节,Keyboard ID为83ABh。当键盘收到此命令后,会首先回复一个ACK,然后,将2字节的Keyboard ID一个一个回复回去。1 u, G2 t* d' |+ Z, D
8 O$ m7 R% `/ U7 I- i" Q
    * F3h' \7 ?* W9 O1 u" K# h8 d
* b7 T  U4 c" X1 S* A7 m8 L
设置Typematic Rate/Delay。当Keyboard收到此命令后,将回复一个ACK。然后等待来自于60h的设置字节。一旦收到,将回复一个ACK,然后将Keyboard Rate/Delay设置为相应的值。# Z% C! W( @: w; G: Y4 h% ]5 n5 w

& W0 D2 ], }# }  h* \    * F4h# l( J, \# o3 [
2 I3 \4 [" G# \
清理键盘的Output Buffer。一旦Keyboard收到此命令,将会将Output buffer清空,然后回复一个ACK。然后继续接受Keyboard的击键。6 O7 k9 r; O/ F8 r+ t
% Y, S/ Y$ y2 m' H" ]8 M
    * F5h
  Q) ^% Y5 d+ T# Y9 @- n/ v6 O4 v7 A2 s
设置默认状态(w/Disable)。一旦Keyboard收到此命令,将会将Keyboard完全初始化成默认状态。之前所有对它的设置都将失效——Output buffer被清空,Typematic Rate/Delay被设置成默认值。然后回复一个ACK,接着等待下一个命令。需要注意的是,这个命令被执行后,键盘的击键接受是禁止的。如果想让键盘接受击键输入,必须Enable Keyboard。
  S& o5 f8 I2 G
3 Z6 N- g+ K# d: S- T; P' X    * F6h
2 V6 K6 f% G- u2 b: j- X. d
1 f# }: K+ m7 w8 a7 s设置默认状态。和F5命令唯一不同的是,当此命令被执行之后,键盘的击键接收是允许的。
* q* j, f; E# m: h- b8 y# ~2 i3 U) Z7 ^6 p0 Q5 F3 r2 H5 H
    * FEh; X/ e$ R" B* O: U

! o3 ^0 M( H: ], B9 ]6 HResend。如果Keyboard收到此命令,则必须将刚才发送到8042 Output Register中的数据重新发送一遍。当系统检测到一个来自于Keyboard的错误之后,可以使用自命令让Keyboard重新发送刚才发送的字节。
; U9 F0 e$ A0 ]
" v. E7 h4 O1 t" f    * FFh* y- f  Q8 c% [4 v" n& l

4 P. K3 n; q" S& r- X# g3 G! s- CReset Keyboard。如果Keyboard收到此命令,则首先回复一个ACK,然后启动自身的Reset程序,并进行自身基本正确性检测(BAT-Basic Assurance Test)。等这一切结束之后,将返回给系统一个单字节的结束码(AAh=Success, FCh=Failed),并将键盘的Scan code set设置为2。
回复

使用道具 举报

发表于 2009-1-14 13:49:16 | 显示全部楼层
好贴!3 I! T6 E  j. D! @  S
非常详细!
. A" N# H' f3 o/ e7 ^$ y" Q  I谢谢!
回复

使用道具 举报

发表于 2009-2-25 17:37:28 | 显示全部楼层
2楼好帖!在helppc的Hardware Data and Specifications栏里有相应的寄存器和命令详细描述。
! N9 l. W/ s- w3 L0 ~5 T' g8 B4 I) J# I( a5 `: E6 F! T& @6 I, ?
我的问题是,上述描述应该是针对老的8042的,在目前的使用EC的系统中,这些status register和command描述在哪个文档中可以找到?比如intel的santarosa,使用renessas的H8s 2104 EC,按道理上述状态寄存器,命令等的描述应该在2104 datasheet里,但是我怎么找都没有。还是有某个spec定义了这些命令格式?新手问题,高手莫笑
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-23 23:16 , Processed in 0.030006 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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