这实际上是由微软开发的一种网络即插即用技术,但可供 Linux 使用。 你将某个东西插入网络,该东西不需要配置,只要它只与网络上其他启用了 UPnP 的设备通信即可。 这里“配置”用于广泛的意义,不仅仅是指配置总线资源。一个目标是允许对网络或配置知之甚少的人安装路由器、网关、网络打印机等。 UPnP 的主要用途将是在无线网络中。
UPnP 使用
本 HOWTO 不涵盖 UPnP。Linux 的 UPnP 由 Intel 支持,Intel 为其开发了软件。还有其他程序可以做与 UPnP 大致相同的事情。其中一些程序的比较位于 http://www.cs.umbc.edu/~dchakr1/papers/mcommerce.html。 Linux 的 UPnP 项目位于 SourceForge:Linux 的 UPnP SDK
有三种类型的地址:主内存地址、I/O 地址(端口)和配置地址。 在 PCI 总线上,配置地址构成一个独立的地址空间,就像 I/O 地址一样。 除了 ISA 配置地址的复杂情况外,总线上的地址是内存地址、I/O 地址还是配置地址,仅取决于总线其他线路(迹线)上的电压。 有关 ISA 配置地址,请参见 ISA 总线配置地址(读取端口等)以了解详细信息
本文档有时使用术语“地址”来表示连续的地址范围。地址以字节为单位。 例如,I/O 地址范围为 3F8-3FF 的串行端口通常仅由其基地址 3F8 引用。 3F8 是该范围内(地址范围)的第一个字节的位置。要查看各种设备的地址范围,请查看 /proc/iomem 和 /proc/ioports。
要访问 I/O 和(主)内存地址“空间”,使用相同的地址总线(用于地址的线路是共享的)。 设备如何知道出现在地址总线上的地址是内存地址还是 I/O 地址? 那么,对于 ISA(对于 PCI 也要阅读),总线上有 4 条专用线路来传达此类信息。 如果这 4 条线路中的某一条被置位,则表示 CPU 想要从 I/O 地址读取,主内存将忽略总线上的地址。 总之,主内存和 I/O 地址都存在读取和写入线路(总共 4 条线路)。
对于 PCI 总线,基本思想相同(也使用 4 条线路),但方式略有不同。 不是仅置位四条线路中的一条,而是将二进制数放在线路上(16 种不同的可能性)。 因此,这 4 条线路可能会传达更多信息。 这 16 个数字中的四个用作上面段落中的 I/O 和内存空间。 此外,还有一个配置地址空间,它占用了另外两个数字。 这留下了 10 个剩余的数字用于其他目的。
这与 IO 和内存地址空间不同,因为配置地址空间是“地理的”。 卡的每个插槽都将插槽号作为地址的一部分。 这样,Linux(或 BIOS)就可以寻址某个插槽并找出该插槽中的卡类型。 每个设备都有 64 个标准字节大小的寄存器,其中一些寄存器保存可以明确识别设备的数字。 由于插槽的数量有限,并且内置在主板中的 PCI 设备数量也有限,因此 Linux(或 BIOS)只需要检查有限数量的地址即可找到所有 PCI 设备。 如果它从设备的首个寄存器中读取到所有 1(十六进制为 0xFF),则表示不存在任何设备。 由于没有卡或设备来提供所有这些 1 (0xFF) 数字,因此主板上的 PCI“主机桥”为所有不存在的设备提供(欺骗)此数字。
PCI 插槽号在 PCI 术语中称为“设备编号”,由于一张卡上最多可以有 8 个设备,因此 0-7 的“功能编号”标识 PCI 卡上的哪个设备。 这些数字是地理地址的一部分。 Linux 程序员将其称为“pci-slot-name”。 因此,Linux 所谓的“设备”实际上是 PCI 术语中的“功能”。 PCI 总线编号(通常为 00)也成为地理地址的一部分。 例如,0000:00:0d.2 是 PCI 总线 0,插槽 0d,功能 2。 对于完整的地理地址,必须包括要访问的设备的配置寄存器的双字编号。 前导 0000(在 1999 年)保留供将来使用。
CPU 如何指定读取或写入是对 PCI 配置空间的? 至少不是直接指定。 相反,当需要访问配置空间时,它会对 IO 空间中的 0cf8-0cfb 进行 32 位(双字)写入,并将完整的地理地址写入其中。 PCI 主机桥正在侦听此地址,并确保接下来对 0cfc-0cff 的任何数据写入都放入指定设备的指定配置寄存器中。 该桥通过在专用线路上向指定的 PCI 卡(或类似物)发送特殊信号来完成此操作,该线路仅到达插入该卡的插槽。 它还在控制总线上放置位,表示现在地址总线上的内容是地理配置空间地址。
为什么不让它简单一点,让 CPU 在控制总线上放置位,表示主总线上的地址是 PCI 配置的地理地址? 嗯,大多数 CPU 都无法做到这一点,因此 PCI 主机桥反而可以做到这一点。
在 ISA 总线上,每个 PnP 卡都内置了一种方法来检查是否存在使用相同 I/O 地址的其他卡。 如果两个或多个卡使用相同的 IO 地址,则两个卡都不太可能正常工作(如果可以工作的话)。 良好的 PnP 软件应分配总线资源,以避免此冲突,但即使在这种情况下,也可能存在具有相同地址的旧卡。
该测试的工作方式是卡将已知的测试编号放入其自己的 IO 寄存器中。 然后,PnP 软件读取它并验证其读取的内容是否与已知的测试编号相同。 如果没有,则出现问题(例如,另一张具有相同地址的卡)。 它使用另一个测试编号重复相同的测试。 由于它实际上检查分配给卡的 IO 地址范围,因此称为“范围检查”。 最好称为地址冲突测试。 如果存在地址冲突,您会收到一条错误消息。
传统上,大多数 I/O 设备仅使用 I/O 内存与 CPU 通信。 在 CPU 上运行的设备驱动程序会将数据读取和写入 I/O 地址空间和主内存。 不幸的是,这需要两个步骤。 例如,1. 从设备(在 IO 地址空间中)读取数据并暂时将其存储在 CPU 中; 2. 将此数据写入主内存。 一种更快的方法是让设备本身将数据直接放入主内存中。 一种方法是使用 ISA DMA 通道或 PCI 总线主控。 另一种方法是让物理设备实际包含一些主内存(位于较高的地址,以免与主内存芯片地址冲突)。 这样,设备可以直接读取和写入其自身包含的主内存,而无需担心 DMA 或总线主控。 这种设备也可能使用 IO 地址。
这些地址也称为“自动配置端口”。 对于 ISA 总线,从技术上讲没有配置地址空间,但是 CPU 可以通过一种特殊方式访问 PnP 卡上的 PnP 配置寄存器。 为此,分配了 3 个 @ I/O 地址,每个地址仅寻址一个字节(没有“范围”)。 这不是每个卡 3 个地址,而是所有 ISA-PnP 卡共享的 3 个地址。
这 3 个地址分别命名为读取端口、写入端口和地址端口。 每个端口的大小仅为一个字节。 每个 PnP 卡都有许多配置寄存器,因此仅 3 个地址甚至不足以满足单个卡上的配置寄存器。 为了解决这个问题,使用一种称为“隔离”的技术为每个卡分配一个卡号(句柄)。 有关复杂的详细信息,请参见 ISA 隔离。
然后,要配置某个卡,其卡号(句柄)会通过写入端口地址发送出去,以告知该卡在其地址端口侦听。 所有其他卡都会注意到这不是它们的卡号,因此不会侦听。 然后,配置寄存器的地址(对于该卡)会被发送到地址端口(对于所有卡 - 但只有一个在侦听)。 接下来,通过读取读取端口或写入写入端口与该卡上的该配置寄存器进行数据传输。
写入端口始终位于 A79,地址端口始终位于 279(十六进制)。 读取端口不是固定的,而是由配置软件在某个地址(在 203-3FF 范围内)设置的,希望该地址不会与任何其他 ISA 卡冲突。 如果存在冲突,它将更改地址。 所有 PnP 卡都使用此地址进行“编程”。 因此,如果您使用 isapnp 设置或检查配置数据,则必须确定此读取端口地址。
之前说过,每个中断都有一条线路。 但是串行化中断(或串行中断)是一个例外。 单根导线用于在该导线上复用的所有中断。 每个中断在中断线路上都有一个时隙。 它在 LPC 总线上使用,也用于 PCI 总线,但很少用于 PCI ??
在进入中断详细信息之前,某些设备除了发送中断之外,还有另一种启动通信的方式。 此方法是 DMA(直接内存访问)请求,用于在有限的时间内从 CPU 接管计算机的控制权。 在 PCI 总线上,它不使用任何“资源”。 并非所有设备都能够执行 DMA。 请参见 DMA 通道。
还有另一种类型的中断,称为“软中断”,本 HOWTO 未涵盖,也不使用任何“资源”。 硬件中断由硬件生成,而软中断由软件启动。 有两种方法可以做到这一点。 一种方法是让软件告诉 CPU 发出中断(中断指令)。 另一种方法是让软件向其他进程发送消息,以便中断它们,尽管尚不清楚这是否应该称为中断。 您可能会发现在 Linux PC 上运行的 ksoftirq 进程是一个为处理设备驱动程序而进行此类中断的程序。 设备驱动程序由于硬件中断而开始运行,但在稍后,软中断用于驱动程序中断服务例程的“下半部分”。 因此,ksoftirq 进程也称为“下半部分”。 有关更多详细信息,请参见内核文档。
中断会间接地传递大量信息。设备发送的中断请求信号(导线上的电压)只是告诉一个名为中断控制器的芯片,某个设备需要关注。然后,中断控制器向 CPU 发出信号。CPU 随后中断它正在执行的任何操作,找到该设备的驱动程序代码,并运行其中的一部分,称为“中断服务例程”(或“中断处理程序”)。这个“例程”尝试查明发生了什么,然后处理问题。例如,可能需要从/向设备传输字节。该程序(例程)可以轻松查明发生了什么,因为设备在驱动程序软件已知的地址处有寄存器(前提是设备的 IRQ 号和 I/O 地址已正确设置)。这些寄存器包含有关设备的状态信息。软件读取这些寄存器的内容,并通过检查这些内容,查明发生了什么并采取适当的措施。
因此,每个设备驱动程序都需要知道要监听哪个中断号 (IRQ)。在 PCI 总线上(以及 ISA 总线上的一些特殊情况下),两个(或更多)设备可以共享同一个 IRQ 号。请注意,您不能将 PCI 中断与 ISA 中断共享(有没有例外??)。当发出共享中断时,CPU 会按顺序为使用该中断的所有设备运行所有中断服务例程。此类服务例程要做的第一件事是检查其设备的寄存器,以查看是否确实发生了针对其设备的中断。如果发现其设备没有发出中断(误报),则它可能会立即退出,并且针对使用同一中断的第二个设备开始下一个服务例程。它像上面描述的那样检查设备。重复此序列,直到找到实际发出中断的设备。一个中断的所有中断例程都被称为构成一个链。因此,遍历链,直到链上的一个例程声明中断,实际上是说:此中断是给我的。在它处理完中断后,链上更远的其它中断服务例程将不会运行。
在 IRQ 线上施加电压只是请求 CPU 中断,以便它可以运行设备驱动程序。在几乎所有情况下,CPU 都会根据请求中断。但是,中断可能会暂时禁用或设置优先级,因此在极少数情况下,CPU 的实际中断不会发生(或会延迟)。因此,上面称为“中断”的更准确地只是一个中断请求,并解释了为什么 IRQ 代表 Interrupt ReQuest(中断请求)。
先前的声明,即设备驱动程序监听其中断,是一种过于简单的说法。实际上,是主板上的一个芯片(或芯片的一部分),称为“中断控制器”,它监听所有中断。当中断控制器捕获到中断时,它会向 CPU 发送信号,以启动相应的设备驱动程序的“中断服务例程”来处理中断。
有各种类型的中断控制器。一种类型是 APIC = 高级可编程中断控制器,它通常具有用于许多中断的输入引脚,包括 PCI 中断。较旧的控制器只有用于 ISA 中断的引脚,但它们仍然可以处理 PCI 中断,因为有一个“可编程中断路由器”,可将 PCI 中断转换为 ISA 中断,并将其路由到 ISA 中断控制器上的某些引脚(= 某些 IRQ)。
这仅适用于旧的 ISA 总线。隔离是一种复杂的方法,用于为 ISA 总线上的每个 PnP 设备分配一个临时句柄(ID 号或卡选择号 = CSN)。由于有更有效(但更复杂)的方法可以做到这一点,因此有些人可能会声称这是一种简单的方法。只有一个写入地址用于对所有 PnP 设备进行 PnP 写入,因此写入此地址会转到所有正在监听的 PnP 设备。此写入地址用于向每个 PnP 设备发送(分配)一个唯一的句柄。要分配此句柄,需要仅当一个设备在监听时,才能将句柄发送(写入)到此公共地址。所有 PnP 设备都有一个唯一的序列号,它们在隔离过程中使用。进行隔离有点像游戏。它是通过等效于仅将所有 PnP 设备连接到隔离程序的公共总线线来完成的。
在“游戏”的第一轮中,所有 PnP 设备都在此导线上监听,并同时向导线发送一系列位。允许的位是 1(正电压)或无电压的“开放 0”(开路或三态)。为此,每个 PnP 设备只需开始按顺序在此导线上发送其序列号,电压(开路或三态)。为此,每个 PnP 设备只需开始按顺序在此导线上发送其序列号,逐位,从高位开始。如果任何设备发送 1,则所有其他设备都将在导线上听到 1。如果所有设备都发送“开放 0”,则在导线上听不到任何声音。目的是(在第一轮结束时)消除除最高序列号设备之外的所有设备。“消除”意味着退出此轮游戏,因此暂时停止再监听导线。(请注意,所有序列号的长度相同。)当只剩下一个设备仍在监听时,它将被赋予一个句柄(卡号)。
首先仅考虑序列号的高位,该高位由所有尚未拥有句柄的设备首先放在导线上。如果任何 PnP 设备发出 0(开放 0)但听到 1,则表示其他某个 PnP 设备具有更高的序列号,因此它暂时退出此轮。现在,游戏中剩余的设备(对于此轮)都具有相同的前导数字 (1),因此我们可以剥离此数字,并且仅考虑生成的“剥离的序列号”以供将来参与此轮。然后转到本段的开头并重复,直到已检查每个设备的整个序列号(有关全 0 情况,请参见下文)。
因此,很明显,只有具有较低序列号的卡会在一轮中被消除。但是,如果游戏中所有设备都发出 0 作为其高位会发生什么?在这种情况下,在线路上发送“开放 0”,并且所有参与者都留在游戏中。如果它们都具有前导 0,则这是一个平局,并且就像上述段落中的 1 一样,将 0 剥离。然后继续游戏,因为发送(序列号的)下一位数字。
在该轮结束时(在发送序列号的低位之后),游戏中仅剩下一个具有最高序列号的 PnP 设备。然后为其分配一个句柄并永久退出游戏。然后,来自上一轮的所有退出者(尚未拥有句柄)重新进入游戏,并且新一轮开始,参与者减少一个。最终,将为所有 PnP 设备分配句柄。很容易证明此算法有效。实际的算法比上面介绍的算法稍微复杂一些,因为每个步骤都会重复两次以确保可靠性,并且重复的执行方式略有不同(但使用相同的基本思想)。
一旦分配了所有句柄,它们将用于寻址每个 PnP 设备以发送/读取配置数据。请注意,这些句柄仅用于 PnP 配置,而不用于与 PnP 设备的正常通信。当计算机启动时,PnP BIOS 通常会执行这样的隔离,然后执行 PnP 配置。之后,所有句柄都将“丢失”,因此如果想再次更改(或检查)配置,则必须重新进行隔离。
如果总线具有可用的总线控制,则该总线不太可能需要任何 DMA 资源。例如,PCI 总线不需要 DMA 资源,因为它具有“总线控制”。但是,“总线控制”通常被称为 DMA。但由于它不是严格的 DMA,因此它不需要 DMA 资源。ISA 和 VESA 局部总线没有总线控制。旧的 MCA 和 EISA 总线确实具有总线控制。
您必须将 IO、IRQ 和 DMA 作为参数传递给模块或将它们编译到内核中。但是一些 PCI 卡会被自动检测到。RedHat 提供了一个程序“sndconfig”,它可以检测 ISA PnP 声卡并自动设置模块以加载检测到的总线资源。
这将通过 PnP 方法检测卡,然后选择相应的驱动程序并加载它。它还将在 ISA-PnP 卡或 PCI 卡上设置总线资源。OSS(开放声音系统)以前很流行。
Windows NT4 不支持 ISAPNP,但有一个 PNPISA 程序,您可以“自行承担风险”使用。对于 NT4,建议用户在 BIOS 中设置“不是 PnP OS”,以便 BIOS 会进行资源配置。因此,在过去,MS Windows 和 Linux 都依赖于 BIOS 进行配置(并且仍然是)。
Plug-and-Play-HOWTO 结束