⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 (ldd) ch14-网络驱动程序(上)(转载).htm

📁 LINUX驱动编程
💻 HTM
📖 第 1 页 / 共 4 页
字号:
      color=#ffffff size=3>
      <P>但主要目的是提供一个参考而不是要被记住。本章的其余部分在一个域被示例代码用到<BR>的时候会简单地描述一下,所以你不必不停地回头来参考本节。<BR>&nbsp;<BR>结构device在结构上可以分为两个部分:“可见的”和“不可见的”。可见部分由那些<BR>在静态device结构中显式赋值的域组成,象前面给出的在snull中出现的两项。其余的域<BR>内部使用。有些被驱动程序访问(例如在初始化时被赋值的那些),而有些不能动。本<BR>章在版本2.0.30前都是完全的。<BR>&nbsp;<BR>可见的头<BR>&nbsp;<BR>结构device的第一部分由下列域组成,按序为:<BR>&nbsp;<BR>char&nbsp;*name;<BR>&nbsp;<BR>设备名。如果第一个字符是0(NULL字符)或空格,register_netdev给它分配名字ethn<BR>,n取合适的值。<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;rmem_end;<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;rmem_start;<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;mem_end;<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>unsigned&nbsp;long&nbsp;mem_start;<BR>&nbsp;<BR>这些域存有设备使用的共享内存的开始和结束地址。如果设备有不同的发送和接收内存<BR>,那么mem域就用做发送内存,而rmem用做接收内存。mem_end和mem_start可以在系统引<BR>导时在核心命令行指定,它们的值由ifconfig获取。Rmem域在驱动程序以外不会被引用<BR>。一般地,end域被设置成使得end-start为板上可用内存量。<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;base_addr;<BR>&nbsp;<BR>I/O基地址。这个域,和前面的一样,在设备检测时被赋值。ifconfig可以用来显示和修<BR>改当前值。base_addr可以在系统引导或加载时在核心命令行显式赋值。<BR>&nbsp;<BR>unsigned&nbsp;char&nbsp;irq;<BR>&nbsp;<BR>被赋予的中断号。当接口被列出时dev-&gt;irq由ifconfig打印出来。这个值通常在引导或<BR>加载时被设置,以后可以用ifconfig修改。<BR>&nbsp;<BR>unsigned&nbsp;char&nbsp;start;<BR>&nbsp;<BR>unsigned&nbsp;char&nbsp;interrupt;<BR>&nbsp;<BR>这些域是二进制标志。start通常在设备打开时设置,在关闭时清楚。在接口准备号运行<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>这些域是二进制标志。start通常在设备打开时设置,在关闭时清楚。在接口准备号运行<BR>时它是非零。interrupt是用来告诉代码的高层一个中断到达接口,并正在处理中。<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;tbusy;<BR>&nbsp;<BR>这个域表明“传送忙”。当驱动程序不能再接收新的包发送时(既所有的输出缓冲区都<BR>满了),它应该为非零。使用long类型而不是char是因为有时要使用原子的位操作以避<BR>免竞争条件。注意在核心1.2,tbusy的确是个八位的域,向后可移植的驱动程序应该注<BR>意这一点。原子的位操作在第九章的“使用锁变量”一节中介绍过。<BR>&nbsp;<BR>struct&nbsp;device&nbsp;*next;<BR>&nbsp;<BR>用来维护链表;任何驱动程序都不能动这个域。<BR>&nbsp;<BR>int&nbsp;(*init)(struct&nbsp;device&nbsp;*dev);<BR>&nbsp;<BR>初始化函数。这个域通常是device结构中显式列出的最后一个域。<BR>&nbsp;<BR>隐藏的域<BR>&nbsp;<BR>device结构包含几个额外的域,通常在设备初始化时被赋值。这些域中的一些携带了接<BR>口的信息,一些存在只是为了方便驱动程序(也就是说,核心并不使用它们);还有一<BR>些域,最引人注意的是一些设备方法,它们是核心和驱动程序的接口。<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>些域,最引人注意的是一些设备方法,它们是核心和驱动程序的接口。<BR>&nbsp;<BR>我想分别列为三组,与域的实际顺序无关,那并不重要。<BR>&nbsp;<BR>接口信息<BR>&nbsp;<BR>多数接口信息都由函数ether_setup来正确设置。以太网卡在大部分域都可以依赖这个通<BR>用目的的函数,但flags和dev_addr域是设备特定的,必须在初始化时显式地赋值。<BR>&nbsp;<BR>一些非以太网的接口可以使用类似于ether_setup的助手函数。driver/net/net_init.c<BR>引出tr_setup(令牌环)和fddi_setup。如果你的设备不属于这些类中的一种,你需要自<BR>己为所有的域赋值。<BR>&nbsp;<BR>unsigned&nbsp;short&nbsp;hard_header_len;<BR>&nbsp;<BR>“硬件包头长”。发送包头中IP头(或其它协议信息)之前那部分的八元组个数。对以<BR>太网接口来说,这个值是14。<BR>&nbsp;<BR>unsigned&nbsp;short&nbsp;mtu;<BR>&nbsp;<BR>“最大传送单元”。在包传输时,这个域由网络层使用。以太网的MTU为1500个八元组。<BR>&nbsp;<BR>__u32&nbsp;tx_queue_len;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>__u32&nbsp;tx_queue_len;<BR>&nbsp;<BR>在设备传送队列中可以排队的最大祯数。ether_setup将这个值设为100,不过你可以改<BR>变它。例如,plip使用10以避免浪费系统内存(plip比实际的以太网接口吞吐率要低)<BR>。<BR>&nbsp;<BR>unsigned&nbsp;short&nbsp;type;<BR>&nbsp;<BR>接口的硬件类型。这个域被ARP使用以判断接口支持的硬件地址类型。以太网接口把它设<BR>为ARPHRD_ETHER----ether_setup为你做这件事。<BR>&nbsp;<BR>unsigned&nbsp;char&nbsp;addr_len;<BR>&nbsp;<BR>unsigned&nbsp;char&nbsp;broadcast[MAX_ADDR_LEN];<BR>&nbsp;<BR>unsigned&nbsp;char&nbsp;dev_addr[MAX_ADDR_LEN];<BR>&nbsp;<BR>以太网地址长为六个八元组(我们是指接口板的硬件标志),播送地址由六个0xff八元<BR>组组成;ether_setup负责这些值的正确设置。另一方面,设备地址必须以设备特定的方<BR>式从接口板中读出,驱动程序应把它复制到dev_addr。这个硬件地址用来在把包交给驱<BR>动程序传送前产生正确的以太网包头。snull并不使用物理接口,它生成一个它自己的物<BR>理地址。<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>unsigned&nbsp;short&nbsp;family;<BR>&nbsp;<BR>接口的地址族,通常为AF_INET。接口并不常查看这个域或者向其赋值。<BR>&nbsp;<BR>unsigned&nbsp;short&nbsp;pa_alen;<BR>&nbsp;<BR>协议地址长。对AF_INET来说为四个八元组。接口不需要修改这个数。<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;pa_addr;<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;pa_brdaddr;<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;pa_mask;<BR>&nbsp;<BR>刻划接口的三个地址:接口地址,播送地址,及网络掩码。这些值是协议特定的(既它<BR>们是“协议地址”);如果dev-&gt;family是INET,则它们为IP地址。这些域由ifconfig赋<BR>值,对驱动程序是只读的。<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;pa_dstaddr;<BR>&nbsp;<BR>plip和ppp一类点到点协议使用这个域记录连接另一侧的IP号码。和前面的域一样,它也<BR>是只读的。<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>是只读的。<BR>&nbsp;<BR>unsigned&nbsp;short&nbsp;flags;<BR>&nbsp;<BR>接口标志。这个域含有下列位值。前缀IFF意为接口标志(InterFace&nbsp;Flags)。有些标<BR>志由核心管理,有些则是在初始化时由接口设置,以确认接口的能力。有效的标志是:<BR>&nbsp;<BR>IFF_UP<BR>&nbsp;<BR>当接口是活跃的时,核心置上该标志。这个标志对驱动程序是只读的。<BR>&nbsp;<BR>IFF_BROADCAST<BR>&nbsp;<BR>这个标志表明接口的播送地址是有效的。以太网卡支持播送。<BR>&nbsp;<BR>IFF_DEBUG<BR>&nbsp;<BR>查错模式。这标志控制printk调用的唠叨,还用在其它一些查错目的。尽管目前没有官<BR>方驱动程序使用它,用户程序可以通过ioctl来对其置位或者清除,你的驱动程序可以使<BR>用它。misc-progs/netifdebug程序可以用来将这个标志打开或关闭。<BR>&nbsp;<BR>IFF_LOOPBACK<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>这个标志在环回接口中要被置位。核心检测这个标志而不是将名字lo作为特殊接口硬写<BR>入程序。<BR>&nbsp;<BR>IFF_POINTOPOINT<BR>&nbsp;<BR>点到点的初始化函数应置位这个标志。例如,plip对它置位。ifconfig工具也可以对其<BR>置位和清除。当它被置位时,dev-&gt;pa_dstaddr应该指向连接的另一端。<BR>&nbsp;<BR>IFF_NOARP<BR>&nbsp;<BR>常规网络接口可以传送ARP包。如果接口不能进行ARP,它必须置这个标志。例如,点到<BR>点接口并不需要运行ARP,它只能增加额外的通信,却不能获取任何有用的信息。snull<BR>不具有ARP能力,因此它要对其置位。<BR>&nbsp;<BR>IFF_PROMISC<BR>&nbsp;<BR>这个标志被置位以获得杂类操作。在缺省情况下,以太网接口使用硬件过滤器以保证它<BR>只收到播送包和指向其硬件地址的包。而象tcpdump一类包监视器则在接口上设置杂类模<BR>式,以获取经过接口传输介质的所有包。<BR>&nbsp;<BR>IFF_MULTICAST<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>能进行选播传送的接口要置这个标志。ether_setup在缺省情况下对其置位。所以如果你<BR>的驱动程序不支持选播,它必须在初始化时清除这个标志。<BR>&nbsp;<BR>IFF_ALLMULTI<BR>&nbsp;<BR>这个标志告诉接口接收所有的选播包。只有当IFF_MULTICAST被置位,而主机由进行选播<BR>路由时,核心对其置位。它对接口时只读的。IFF_MULTICAST和IFF_ALLMULTI早在1.2版<BR>就已经定义了,但那时并未使用。在后面“选播”一节我们将看到它是如何使用的。<BR>&nbsp;<BR>IFF_MASTER<BR>&nbsp;<BR>IFF_SLAVE<BR>&nbsp;<BR>这些标志被加载均衡代码使用。接口驱动程序不需要知道它们。<BR>&nbsp;<BR>IFF_NOTRAILERS<BR>&nbsp;<BR>IFF_RUNNING<BR>&nbsp;<BR>这些标志在Linux中不使用,只是为了和BSD兼容而存在。<BR>&nbsp;<BR>当一个程序改变IFF_UP,open和close方法会被调用。当IFF_UP或其它标志被修改时,se<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>当一个程序改变IFF_UP,open和close方法会被调用。当IFF_UP或其它标志被修改时,se<BR>t_multicast_list方法被调用。如果驱动程序因为标志的修改而要执行一些动作,那么<BR>必须在set_multicast_list中进行。例如,当IFF_PROMIS被置位或清除时,板上硬件过<BR>滤器必须被通知。这个设备方法的责任将在后面的“选播”一节简单介绍。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>设备方法<BR>&nbsp;<BR>与字符设备和块设备的情况一样,每个网络设备要声明在其上操作的函数。可以在网络<BR>接口上进行的操作列在下面。一些操作可以留为NULL,还有一些通常不去动它们,因为e<BR>ther_setup给它们分配合适的方法。<BR>&nbsp;<BR>一个网络接口的设备方法可以分为两类:基本的和可选的。基本的包括那些为访问接口<BR>所需要的;可选的方法实现一些并不严格要求的高级功能。下面是基本方法:<BR>&nbsp;<BR>int&nbsp;(*open)(struct&nbsp;device&nbsp;*dev);<BR>&nbsp;<BR>打开接口。只要ifconfig激活一个接口,它就被打开了。open方法要注册它需要的所有<BR>资源(I/O端口,IRQ,DMA,等),打开硬件,增加模块的使用计数。<BR>&nbsp;<BR>int&nbsp;(*stop)(struct&nbsp;device&nbsp;*dev);<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>终止接口。接口在关闭时就终止了;在打开时进行的操作应被保留。<BR>&nbsp;<BR>int&nbsp;(*hard_start_xmit)(struct&nbsp;sk_buff&nbsp;*skb,&nbsp;struct&nbsp;device&nbsp;*dev);<BR>&nbsp;<BR>硬件开始传送。这个方法请求一个包的传送。这个包含在一个套接字缓冲区结构(sk_bu<BR>ff)中。套接字缓冲区在下面介绍。<BR>&nbsp;<BR>int&nbsp;(*rebuild_header)(void&nbsp;*buf,&nbsp;struct&nbsp;device&nbsp;*dev,&nbsp;unsigned&nbsp;long&nbsp;raddr,<BR>struct&nbsp;sk_buffer&nbsp;*skb);<BR>&nbsp;<BR>这个函数用来在一个包传送之前重构硬件包头。这个以太网设备使用的缺省包头用ARP向<BR>包中填入缺少的信息。snull驱动程序实现了它自己的这个方法,因为ARP并不在sn接口<BR>上运行。(在本章的后面会介绍ARP。)这个方法的参数是一些指针,分别指向硬件包头<BR>,设备,“路由器地址”(包的初始目的地),以及被传送的缓冲区。<BR>&nbsp;<BR>int&nbsp;(*hard_header)(struct&nbsp;sk_buffer&nbsp;*skb,&nbsp;struct&nbsp;device&nbsp;*dev,&nbsp;unsigned<BR>short&nbsp;type,<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;*daddr,&nbsp;void&nbsp;*saddr,&nbsp;unsigned&nbsp;len);<BR>&nbsp;<BR>硬件包头。这个函数用以前获取的源和目的地址构造包头;它的任务是组织那些以参数<BR>的形式传给它的信息。eth_header是以太网类接口的缺省函数,&nbsp;ether_setup相应地对<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>的形式传给它的信息。eth_header是以太网类接口的缺省函数,&nbsp;ether_setup相应地对<BR>这个域赋值。给出的参数顺序适用于核心2.0或更高版本,但与1.2有所不同。这个改变<BR>对以太网驱动程序是透明的,因为它继承了&nbsp;eth_header的实现;其它驱动程序可能要处<BR>理一下这个不同,如果它们想保持向后兼容的话。<BR>&nbsp;<BR>struct&nbsp;enet_statistics&nbsp;*&nbsp;(*get_stats)(struct&nbsp;device&nbsp;*dev);<BR>&nbsp;<BR>当应用希望获得接口的统计信息时需要调用这个方法,例如,当运行ifconfig或netstat<BR>&nbsp;–i时。在snull中的一个示例实现将在后面“统计信息”中介绍。<BR>&nbsp;<BR>int&nbsp;(*set_config)(struct&nbsp;device&nbsp;*dev,&nbsp;struct&nbsp;ifmap&nbsp;*map);<BR>&nbsp;<BR>改变接口的配置。这个方法是配置驱动程序的入口点。设备的I/O地址和中断号可以在运<BR>行时用set_config改变。在接口不能探测到时,系统管理员可以适用这个能力。这个方<BR>法在后面的“运行时配置”中介绍。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>其余的设备方法是被我称为可选的那些。传递给其中一些的参数在Linux1.2到Linux2.0<BR>的转变中改了好几次。如果你想写一个可以在两个版本核心都工作的驱动程序,你可以<BR>只为从2.0开始的版本实现这些操作。<BR>&nbsp;<BR>int&nbsp;(*do_ioctl)(struct&nbsp;devices&nbsp;*dev,&nbsp;struct&nbsp;ifreg&nbsp;*ifr,&nbsp;int&nbsp;cmd);<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>int&nbsp;(*do_ioctl)(struct&nbsp;devices&nbsp;*dev,&nbsp;struct&nbsp;ifreg&nbsp;*ifr,&nbsp;int&nbsp;cmd);<BR>&nbsp;<BR>执行接口特定的ioctl命令。这些命令的实现在后面的“自定义ioctl命令”中描述。这<BR>里给出的原形在1.2以上的核心都能工作。如果接口不需要任何接口特定的命令,那么结<BR>构device中相应的域可以留为NULL。<BR>&nbsp;<BR>void&nbsp;(*set_multicast_list)(struct&nbsp;device&nbsp;*dev);<BR>&nbsp;<BR>当设备的选播列表改变和标志改变时,将调用这个方法。这里的参数传递与1.2版本不同<BR>。更多的细节和一个示例实现见“选播”一节。<BR>&nbsp;<BR>int&nbsp;(*set_mac_address)(struct&nbsp;device&nbsp;*dev,&nbsp;void&nbsp;*addr);<BR>&nbsp;<BR>如果接口支持改变硬件地址的能力,可实现这个函数。多数接口要么不支持这个能力,<BR>要么使用缺省的eth_mac_addr实现。这个原形与1.2版也不同。<BR>&nbsp;<BR>#define&nbsp;HAVE_HEADER_CACHE<BR>&nbsp;<BR>void&nbsp;(*header_cache_bind)(struct&nbsp;hh_cache&nbsp;**hhp,&nbsp;struct&nbsp;device&nbsp;*dev,<BR>unsigned&nbsp;short&nbsp;htype,&nbsp;__u32&nbsp;daddr);<BR>&nbsp;<BR>void&nbsp;(*header_cache_update)(struct&nbsp;hh_cache&nbsp;*hh,&nbsp;struct&nbsp;device&nbsp;*dev,<BR>unsigned&nbsp;char&nbsp;*haddr);<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>unsigned&nbsp;char&nbsp;*haddr);<BR>&nbsp;<BR>这些函数和宏在Linux1.2中没有。以太网驱动程序不必关心header_cache的问题,因为e<BR>th_setup会安排使用缺省的方法。<BR>&nbsp;<BR>#define&nbsp;HAVE_CACHE_MTU<BR>&nbsp;<BR>int&nbsp;(*change_mtu)(struct&nbsp;device&nbsp;*dev,&nbsp;int&nbsp;new_mtu);<BR>&nbsp;<BR>如果接口的MTU(最大传送单元)发生了改变,这个函数负责采取动作。这个函数和宏在<BR>Linux1.2中都没有。当MTU改变时,如果驱动程序要做一些特殊的事情,它应该声明它自<BR>己的函数,不然将由缺省函数来完成。如果你感兴趣,snull有一个这个函数的模版。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>工具域<BR>&nbsp;<BR>其余的结构device中的域被接口用来保存一些有用的状态信息。其中一些被ifconfig和n<BR>etstat用来向用户提供当前配置的信息。因此,接口应该对这些域赋值。<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;trans_start;<BR>&nbsp;<BR>unsigned&nbsp;long&nbsp;last_rx;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>unsigned&nbsp;long&nbsp;last_rx;<BR>&nbsp;<BR>这两个域用来保存一些瞬间值。它们目前不用,但核心有可能将来使用这些计时提示。<BR>驱动程序负责在传送开始时和收到包时更新这些值。trans_start域还可以被驱动程序用<BR>来检测锁定。驱动程序可以在等待一个“传送完成”的中断时用trans_start来检查超时<BR>。<BR>&nbsp;<BR>void&nbsp;*priv<BR>&nbsp;<BR>等价于filp-&gt;private_data。驱动程序拥有这个指针,可以随意使用。通常这个私有数<BR>据结构含有一个enet_statistics结构项。这个域在以前的“初始化每个设备”中用过。<BR>&nbsp;<BR>&nbsp;<BR>unsigned&nbsp;char&nbsp;if_prot;<BR>&nbsp;<BR>这个域用来记录哪个硬件端口被接口使用(例如,BNC,AUI,TP)。任何数值都可以按<BR>需要赋给它。<BR>&nbsp;<BR>unsigned&nbsp;char&nbsp;dma;<BR>&nbsp;<BR>被接口使用的DMA通道。这个域被ioctl的SIOCGIFMAP命令使用。<BR>&nbsp;<BR>struct&nbsp;dev_mc_list&nbsp;*mc_list;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>unsigned&nbsp;char&nbsp;dma;<BR>&nbsp;<BR>被接口使用的DMA通道。这个域被ioctl的SIOCGIFMAP命令使用。<BR>&nbsp;<BR>struct&nbsp;dev_mc_list&nbsp;*mc_list;<BR>&nbsp;<BR>int&nbsp;mc_count<BR>&nbsp;<BR>这两个域被用来处理选播传送。Mc_count是mc_list中项的个数。更多的细节见“选播”<BR>结构device中还有一些别的域,但驱动程序没有使用它们<BR>--<BR><FONT 
      color=#00ff00>※&nbsp;来源:.华南网木棉站&nbsp;bbs.gznet.edu.cn.[FROM:&nbsp;202.38.196.234]</FONT><BR>--<BR><FONT 
      color=#00ffff>※&nbsp;转寄:.华南网木棉站&nbsp;bbs.gznet.edu.cn.[FROM:&nbsp;211.80.41.106]</FONT><BR>--<BR><FONT 
      color=#0000ff>※&nbsp;转寄:.华南网木棉站&nbsp;bbs.gznet.edu.cn.[FROM:&nbsp;211.80.41.106]</FONT><BR>--<BR><FONT 
      color=#ffff00>※&nbsp;转载:.南京大学小百合站&nbsp;bbs.nju.edu.cn.[FROM:&nbsp;211.80.41.106]</FONT><BR>--<BR><FONT 
      color=#ff0000>※&nbsp;转载:·饮水思源&nbsp;bbs.sjtu.edu.cn·[FROM:&nbsp;211.80.41.106]</FONT><BR></P></FONT>
      <P align=center><A href="http://joyfire.net/lsdp/index.htm"><FONT 
      color=#ffffff size=2>目录页</FONT></A> | <A 
      href="http://joyfire.net/lsdp/16.htm"><FONT color=#ffffff 
      size=2>上一页</FONT></A> | <A href="http://joyfire.net/lsdp/18.htm"><FONT 
      color=#ffffff size=2>下一页</FONT></A></P></SPAN></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=0>
  <TBODY>
  <TR>
    <TD colSpan=3 height=2>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -