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

📄 ch09s02.html

📁 真正LDD3中文
💻 HTML
📖 第 1 页 / 共 2 页
字号:
<dt><span class="term"><span>void outsb(unsigned port, void *addr, unsigned long count);</span></span></dt><dd><p>读或写从内存地址 addr 开始的 count 字节. 数据读自或者写入单个 port 端口.</p></dd><dt><span class="term"><span>void insw(unsigned port, void *addr, unsigned long count);</span></span></dt><dd></dd><dt><span class="term"><span>void outsw(unsigned port, void *addr, unsigned long count);</span></span></dt><dd><p>读或写 16-位 值到一个单个 16-位 端口.</p></dd><dt><span class="term"><span>void insl(unsigned port, void *addr, unsigned long count);</span></span></dt><dd></dd><dt><span class="term"><span>void outsl(unsigned port, void *addr, unsigned long count);</span></span></dt><dd><p>读或写 32-位 值到一个单个 32-位 端口.</p></dd></dl></div><p>有件事要记住, 当使用字串函数时: 它们移动一个整齐的字节流到或自端口. 当端口和主系统有不同的字节对齐规则, 结果可能是令人惊讶的. 使用 inw 读取一个端口交换这些字节, 如果需要, 来使读取的值匹配主机字节序. 字串函数, 相反, 不进行这个交换.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="PausingIO.sect"></a>9.2.5.&#160;暂停 I/O</h3></div></div></div><p>一些平台 - 最有名的 i386 - 可能有问题当处理器试图太快传送数据到或自总线. 当处理器对于外设总线被过度锁定时可能引起问题( 想一下 ISA )并且可能当设备单板太慢时表现出来. 解决方法是插入一个小的延时在每个 I/O 指令后面, 如果跟随着另一个指令. 在 x86 上, 这个暂停是通过进行一个 outb 指令到端口 0x80 ( 正常地不是常常用到 )实现的, 或者通过忙等待. 细节见你的平台的 asm 子目录的 io.h 文件.</p><p>如果你的设备丢失一些数据, 或者如果你担心它可能丢失一些, 你可以使用暂停函数代替正常的那些. 暂停函数正如前面列出的, 但是它们的名子以 _p 结尾; 它们称为 inb_p, outb_p, 等等. 这些函数定义给大部分被支持的体系, 尽管它们常常扩展为与非暂停 I/O 同样的代码, 因为没有必要额外暂停, 如果体系使用一个合理的现代外设总线.</p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="PlatformDependencies.sect"></a>9.2.6.&#160;平台依赖性</h3></div></div></div><p>I/O 指令, 由于它们的特性, 是高度处理器依赖的. 因为它们使用处理器如何处理移进移出的细节, 是非常难以隐藏系统间的不同. 作为一个结果, 大部分的关于端口 I/O 的源码是平台依赖的.</p><p>你可以看到一个不兼容, 数据类型, 通过回看函数的列表, 这里参数是不同的类型, 基于平台间的体系不同点. 例如, 一个端口是 unsigned int 在 x86 (这里处理器支持一个 64-KB I/O 空间), 但是在别的平台是 unsiged long, 这里的端口只是同内存一样的同一个地址空间中的特殊位置.</p><p>其他的平台依赖性来自处理器中的基本的结构性不同, 并且, 因此, 无可避免地. 我们不会进入这个依赖性的细节, 因为我们假定你不会给一个特殊的系统编写设备驱动而没有理解底层的硬件. 相反, 这是一个内核支持的体系的能力的概括:</p><div class="variablelist"><dl><dt><span class="term"><span>IA-32 (x86)</span></span></dt><dd></dd><dt><span class="term"><span>x86_64 </span></span></dt><dd><p>这个体系支持所有的本章描述的函数. 端口号是 unsigned short 类型.</p></dd><dt><span class="term"><span>IA-64 (Itanium)</span></span></dt><dd><p>支持所有函数; 端口是 unsigned long(以及内存映射的)). 字串函数用 C 实现.</p></dd><dt><span class="term"><span>Alpha </span></span></dt><dd><p>支持所有函数, 并且端口是内存映射的. 端口 I/O 的实现在不同 Alpha 平台上是不同的, 根据它们使用的芯片组. 字串函数用 C 实现并且定义在 arch/alpha/lib/io.c 中定义. 端口是 unsigned long.</p></dd><dt><span class="term"><span>ARM </span></span></dt><dd><p>端口是内存映射的, 并且支持所有函数; 字串函数用 C 实现. 端口是 unsigned int 类型.</p></dd><dt><span class="term"><span>Cris </span></span></dt><dd><p>这个体系不支持 I/O 端口抽象, 甚至在一个模拟模式; 各种端口操作定义成什么不做.</p></dd><dt><span class="term"><span>M68k</span></span></dt><dd></dd><dt><span class="term"><span>M68k</span></span></dt><dd><p>端口是内存映射的. 支持字串函数, 并且端口类型是 unsigned char.</p></dd><dt><span class="term"><span>MIPS</span></span></dt><dd></dd><dt><span class="term"><span>MIPS64 </span></span></dt><dd><p>MIPS 端口支持所有的函数. 字串操作使用紧凑汇编循环来实现, 因为处理器缺乏机器级别的字串 I/O. 端口是内存映射的; 它们是 unsigned long.</p></dd><dt><span class="term"><span>PA</span></span></dt><dd><p>支持所有函数; 端口是 int 在基于 PCI 的系统上以及 unsigned short 在 EISA 系统, 除了字串操作, 它们使用 unsigned long 端口号.</p></dd><dt><span class="term"><span>PowerPC</span></span></dt><dd></dd><dt><span class="term"><span>PowerPC64 </span></span></dt><dd><p>支持所有函数; 端口有 unsigned char * 类型在 32-位 系统上并且 unsigned long 在 64-位 系统上.</p></dd><dt><span class="term"><span>S390 </span></span></dt><dd>类似于 M68k, 这个平台的头文件只支持字节宽的端口 I/O, 而没有字串操作. 端口是 char 指针并且是内存映射的.<p></p></dd><dt><span class="term"><span>Super</span></span></dt><dd><p>端口是 unsigned int ( 内存映射的 ), 并且支持所有函数.</p></dd><dt><span class="term"><span>SPARC SPARC64 </span></span></dt><dd><p>再一次, I/O 空间是内存映射的. 端口函数的版本定义来使用 unsigned long 端口.</p></dd></dl></div><p>好奇的读者能够从 io.h 文件中获得更多信息, 这个文件有时定义几个结构特定的函数, 加上我们在本章中描述的那些. 但是, 警告有些这些文件是相当难读的.</p><p>有趣的是注意没有 x86 家族之外的处理器具备一个不同的地址空间给端口, 尽管几个被支持的家族配备有 ISA 和/或 PCI 插槽 ( 并且 2 种总线实现分开的 I/O 和地址空间 ).</p><p>更多地, 有些处理器(最有名的是早期的 Alphas)缺乏一次移动一个或 2 个字节的指令.<sup>[<a name="id456626" href="#ftn.id456626">35</a>]</sup> 因此, 它们的外设芯片组模拟 8-位 和 16-位 I/O 存取, 通过映射它们到内存地址空间的特殊的地址范围. 因此, 操作同一个端口的一个 inb 和 一个 inw 指令, 通过 2 个操作不同地址的 32-位内存读来实现. 幸运的是, 所有这些都对设备驱动编写者隐藏了, 通过本节中描述的宏的内部, 但是我们觉得它是一个要注意的有趣的特性. 如果你想深入探究, 查找在 include/asm-alpha/core_lca.h 中的例子.</p><p>在每个平台的程序员手册中充分描述了I/O 操作如何在每个平台上进行; 这些手册常常在 WEB 上作为 PDF 下载.</p></div><div class="footnotes"><br><hr width="100" align="left"><div class="footnote"><p><sup>[<a name="ftn.id455968" href="#id455968">33</a>] </sup>有时 I/O 端口象内存一样安排, 并且你可(例如)绑定 2 个 8-位 写为一个单个 16-位 操作. 例如, 这应用于 PC 视频板. 但是通常, 你不能指望这个特色.</p></div><div class="footnote"><p><sup>[<a name="ftn.id456132" href="#id456132">34</a>] </sup>技术上, 它必须有 CAP_SYS_RAWIO 能力, 但是在大部分当前系统中这是与作为 root 运行是同样的.</p></div><div class="footnote"><p><sup>[<a name="ftn.id456626" href="#id456626">35</a>] </sup>单字节 I/O 不是一个人可能想象的那么重要, 因为它是一个稀少的操作. 为读/写一个单字节到任何地址空间, 你需要实现一个数据通道, 连接寄存器组的数据总线的低位到外部数据总线的任意字节位置. 这些数据通道需要额外的逻辑门在每个数据传输的通道上. 丢掉字节宽的载入和存储能够使整个系统性能受益.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch09.html">上一页</a>&#160;</td><td width="20%" align="center"><a accesskey="u" href="ch09.html">上一级</a></td><td width="40%" align="right">&#160;<a accesskey="n" href="ch09s03.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">第&#160;9&#160;章&#160;与硬件通讯&#160;</td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top">&#160;9.3.&#160;一个 I/O 端口例子</td></tr></table></div></body></html>

⌨️ 快捷键说明

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