408 lines
22 KiB
HTML
408 lines
22 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
|
<HTML>
|
|
<HEAD>
|
|
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.21">
|
|
<TITLE> Plug-and-Play-HOWTO: Appendix</TITLE>
|
|
<LINK HREF="Plug-and-Play-HOWTO-10.html" REL=previous>
|
|
<LINK HREF="Plug-and-Play-HOWTO.html#toc11" REL=contents>
|
|
</HEAD>
|
|
<BODY>
|
|
Next
|
|
<A HREF="Plug-and-Play-HOWTO-10.html">Previous</A>
|
|
<A HREF="Plug-and-Play-HOWTO.html#toc11">Contents</A>
|
|
<HR>
|
|
<H2><A NAME="s11">11.</A> <A HREF="Plug-and-Play-HOWTO.html#toc11">Appendix</A></H2>
|
|
|
|
<H2><A NAME="UPnP_"></A> <A NAME="ss11.1">11.1</A> <A HREF="Plug-and-Play-HOWTO.html#toc11.1">Universal Plug and Play (UPnP) </A>
|
|
</H2>
|
|
|
|
<P> This is actually a sort of network plug-and-play developed by
|
|
Microsoft but usable by Linux. You plug something into a network and
|
|
that something doesn't need to be configured provided it will only
|
|
communicate with other UPnP enabled devices on the network. Here
|
|
"configure" is used in the broad sense and doesn't mean just
|
|
configuring bus-resources. One objective is to allow people who know
|
|
little about networks or configuring to install routers, gateways,
|
|
network printers, etc. A major use for UPnP would be in wireless
|
|
networking.</P>
|
|
<P>UPnP uses:
|
|
<UL>
|
|
<LI> Simple Service Discovery Protocol to find
|
|
devices </LI>
|
|
<LI> General Event Notification Architecture </LI>
|
|
<LI> Simple
|
|
Object Access Protocol for controlling devices </LI>
|
|
</UL>
|
|
</P>
|
|
<P>This HOWTO doesn't cover UPnP. UPnP for Linux is supported by Intel
|
|
which has developed software for it. There are other programs which
|
|
do about the same thing as UPnP. A comparison of some of them is at
|
|
<A HREF="http://www.cs.umbc.edu/~dchakr1/papers/mcommerce.html">http://www.cs.umbc.edu/~dchakr1/papers/mcommerce.html</A> A
|
|
UPnP project for Linux is at SourceForge:
|
|
<A HREF="http://sourceforge.net/projects/upnp/">UPnP SDK for Linux</A></P>
|
|
|
|
<H2><A NAME="address_details"></A> <A NAME="ss11.2">11.2</A> <A HREF="Plug-and-Play-HOWTO.html#toc11.2">Address Details </A>
|
|
</H2>
|
|
|
|
<P> There are three types of addresses: main memory addresses, I/O
|
|
addresses (ports) and configuration addresses. On the PCI bus,
|
|
configuration addresses constitute a separate address space just like
|
|
I/O addresses do. Except for the complicated case of ISA
|
|
configuration addresses, whether or not an address on the bus is a
|
|
memory address, I/O address, or configuration address depends only on
|
|
the voltage on other wires (traces) of the bus. For the ISA
|
|
configuration addresses see
|
|
<A HREF="#isa_conf_addresses">ISA Bus Configuration Addresses (Read-Port etc.)</A> for details</P>
|
|
|
|
<H3>Address ranges </H3>
|
|
|
|
<P> The term "address" is sometimes used in this document to mean a
|
|
contiguous range of addresses. Addresses are in units of bytes, So
|
|
for example, a serial port at I/O address range 3F8-3FF will often
|
|
just be referred to by its base address, 3F8. The 3F8 is the location
|
|
of the first byte in the range (address range). To see the address
|
|
ranges for various devices, look at /proc/iomem and /proc/ioports.</P>
|
|
|
|
<H3>Address space </H3>
|
|
|
|
<P>To access both I/O and (main) memory address "spaces" the same
|
|
address bus is used (the wires used for the address are shared). How
|
|
does the device know whether or not an address which appears on the
|
|
address bus is a memory address or I/O address? Well, for ISA (for PCI
|
|
read this too), there are 4 dedicated wires on the bus that convey this
|
|
sort of information. If a certain one of these 4 wires is asserted,
|
|
it says that the CPU wants to read from an I/O address, and the main
|
|
memory ignores the address on the bus. In all, read and write wires
|
|
exist for both main memory and I/O addresses (4 wires in all).</P>
|
|
<P>For the PCI bus it's the same basic idea (also using 4 wires) but it's
|
|
done a little differently. Instead of only one of the four wires
|
|
being asserted, a binary number is put on the wires (16 different
|
|
possibilities). Thus, more info may be conveyed by these 4 wires..
|
|
Four of these 16 numbers serve the I/O and memory spaces as in the
|
|
above paragraph. In addition there is also configuration address
|
|
space which uses up two more numbers. This leaves 10 more numbers
|
|
left over for other purposes.</P>
|
|
|
|
<H3><A NAME="pci_conf"></A> PCI Configuration Address Space </H3>
|
|
|
|
<P>This is different from the IO and memory address spaces because
|
|
configuration address space is "geographic". Each slot for a card has
|
|
the slot number as part of the address. This way, Linux (or the BIOS)
|
|
can address a certain slot and find out what type of card is in that
|
|
slot. Each device has 64 standard byte-size registers and some of
|
|
these hold numbers which can unambiguously identify the device. Since
|
|
the number of slots is limited as are the number of PCI devices built
|
|
into motherboard, Linux (or the BIOS) only needs to check a limited
|
|
number of addresses to find all the PCI devices. If it reads all ones
|
|
(0xFF in hexadecimal) from the first register of a device, then that
|
|
means that no device is present. Since there is no card or device to
|
|
supply all these ones (0xFF) number, the PCI "host bridge" on the
|
|
motherboard supplies (spoofs) this number for all non-existent device.</P>
|
|
<P>The PCI slot number is called (in PCI lingo) the "Device Number" and
|
|
since a card may have up to 8 devices on it, a "Function Number" from
|
|
0-7 identifies which device it is on a PCI card. These numbers are
|
|
part of the geographic address. Linux programmers call it
|
|
"pci-slot-name". Thus what Linux calls a "device" is actually a
|
|
"function" in PCI lingo. The PCI bus number (often 00) also becomes
|
|
part of the geographic address. For example, 0000:00:0d.2 is PCI bus
|
|
0, slot 0d, function 2. For the full geographic address, one must
|
|
include the double-word number of the device's configuration
|
|
registers which one wants to access. The leading 0000 (in 1999) were
|
|
reserved for future use.</P>
|
|
<P>How does the CPU designate that a read or write is to a PCI
|
|
configuration space? It doesn't, at least not directly. Instead when
|
|
access to configuration space is desired it does a 32-bit
|
|
(double-word) write to 0cf8-0cfb in IO space and writes the full
|
|
geographic address there. The PCI host bridge is listening at this
|
|
address and insures that any next write of data to 0cfc-0cff is put into the
|
|
specified configuration registers of the specified device. The bridge
|
|
does this both by sending a special signal to the specified PCI card
|
|
(or the like) on a dedicated wire that goes only to the slot where the
|
|
card is plugged in. It also puts bits on the control bus saying that
|
|
what's on the address bus now is a geographic configuration space
|
|
address.</P>
|
|
<P>Why not make it simple and just have the CPU put bits on the control
|
|
bus to say that the address on the main bus is a geographic one for
|
|
PCI configuration? Well, most CPU's are not capable of doing this so
|
|
the PCI host bridge gets to do it instead.</P>
|
|
|
|
<H3>Range Check (ISA Testing for IO Address Conflicts) </H3>
|
|
|
|
<P> On the ISA bus, there's a method built into each PnP card for
|
|
checking that there are no other cards that use the same I/O address.
|
|
If two or more cards use the same IO address, neither card is likely
|
|
to work right (if at all). Good PnP software should assign
|
|
bus-resources so as to avoid this conflict, but even in this case a
|
|
legacy card might be lurking somewhere with the same address.</P>
|
|
<P>The test works by a card putting a known test number in its own IO
|
|
registers. Then the PnP software reads it and verifies that what it
|
|
reads is the same as the known test number. If not, something is
|
|
wrong (such as another card with the same address). It repeats the
|
|
same test with another test number. Since it actually checks the
|
|
range of IO addresses assigned to the card, it's called a "range
|
|
check". It could be better called an address-conflict test. If there
|
|
is an address conflict you get an error message.</P>
|
|
|
|
<H3>Communicating Directly via Memory </H3>
|
|
|
|
<P> Traditionally, most I/O devices used only I/O memory to
|
|
communicate with the CPU. The device driver, running on the CPU would
|
|
read and write data to/from the I/O address space and main memory.
|
|
Unfortunately, this requires two steps. For example, 1. read data from
|
|
a device (in IO address space) and temporarily store in in the CPU; 2.
|
|
write this data to main memory. A faster way would be for the device
|
|
itself to put the data directly into main memory. One way to do this
|
|
is by using ISA
|
|
<A HREF="Plug-and-Play-HOWTO-2.html#dma_">DMA Channels</A> or PCI bus
|
|
mastering. Another way is for the physical device to actually contain
|
|
some main memory (at high addresses so as not to conflict with main
|
|
memory chip addresses). This way the device reads and writes directly
|
|
to it's self-contained main memory without having to bother with DMA
|
|
or bus mastering. Such a device may also use IO addresses.</P>
|
|
|
|
<H2><A NAME="isa_conf_addresses"></A> <A NAME="ss11.3">11.3</A> <A HREF="Plug-and-Play-HOWTO.html#toc11.3">ISA Bus Configuration Addresses (Read-Port etc.) </A>
|
|
</H2>
|
|
|
|
<P> These addresses are also known as the "Auto-configuration Ports".
|
|
For the ISA bus, there is technically no configuration address space,
|
|
but there is a special way for the CPU to access PnP configuration
|
|
registers on the PnP cards. For this purpose 3 @ I/O addresses are
|
|
allocated and each addresses only a single byte (there is no "range").
|
|
This is not 3 addresses for each card but 3 addresses shared by all
|
|
ISA-PnP cards.</P>
|
|
<P>These 3 addresses are named read-port, write-port, and address-port.
|
|
Each port is just one byte in size. Each PnP card has many
|
|
configuration registers so that just 3 addresses are not even
|
|
sufficient for the configuration registers on a single card. To solve
|
|
this problem, each card is assigned a card number (handle) using a
|
|
technique called "isolation". See
|
|
<A HREF="#isolation_">ISA Isolation</A> for the complex details.</P>
|
|
<P>Then to configure a certain card, its card number (handle) is sent out
|
|
via the write-port address to tell that card that it is to listen at
|
|
its address port. All other cards note that this isn't their card
|
|
number and thus don't listen. Then the address of a configuration
|
|
register (for that card) is sent to the address-port (for all cards
|
|
--but only one is listening). Next, data transfer takes place with
|
|
that configuration register on that card by either doing a read on the
|
|
read-port or a write on the write-port.</P>
|
|
<P>The write-port is always at A79 and the address-port is always at 279
|
|
(hex). The read-port is not fixed but is set by the configuration
|
|
software at some address (in the range 203-3FF) that will hopefully
|
|
not conflict with any other ISA card. If there is a conflict, it will
|
|
change the address. All PnP cards get "programmed" with this address.
|
|
Thus if you use say isapnp to set or check configuration data it must
|
|
determine this read-port address.</P>
|
|
|
|
<H2><A NAME="interrupt_detail"></A> <A NAME="ss11.4">11.4</A> <A HREF="Plug-and-Play-HOWTO.html#toc11.4">Interrupts --Details </A>
|
|
</H2>
|
|
|
|
<H3>Serialized Interrupts</H3>
|
|
|
|
<P>It was previously stated that there was a wire for each interrupt.
|
|
But the serialized interrupt (or serial interrupt) is an exception. A
|
|
single wire is used for all interrupt which are multiplexed on that
|
|
wire. Each interrupt has a time slot on the interrupt line. It's
|
|
used on the LPC bus and is also for the PCI bus, but it's seldom used
|
|
for PCI ??</P>
|
|
|
|
<H3>DMA</H3>
|
|
|
|
<P> Before going into interrupt details, there is another way for some
|
|
devices to initiate communication besides sending out an interrupt.
|
|
This method is a DMA (Direct Memory Access) request to take control of
|
|
the computer from the CPU for a limited amount of time. On the PCI
|
|
bus, it uses no "resources". Not all devices are capable of doing
|
|
DMA. See
|
|
<A HREF="Plug-and-Play-HOWTO-2.html#dma_">DMA Channels</A>. </P>
|
|
|
|
<H3>Soft interrupts</H3>
|
|
|
|
<P>There's also another type of interrupt known as a "soft interrupt"
|
|
which is not covered in this HOWTO and doesn't use any "resources".
|
|
While a hardware interrupt is generated by hardware, a soft interrupt
|
|
is initiated by software. There are a couple of ways to do this. One
|
|
way is for software to tell the CPU to issue an interrupt (an
|
|
interrupt instruction). Another way is for the software to send
|
|
messages to other processes so as to interrupt them although it's not
|
|
clear that this should be called an interrupt. The ksoftirq process,
|
|
which you may find running on a Linux PC, is a program which does this
|
|
kind of interrupt for dealing with device drivers. The device driver
|
|
starts running due to a hardware interrupt but later on, software
|
|
interrupts are used for the "bottom half" of the driver's interrupt
|
|
service routine. Thus, the ksoftirq process is also known as
|
|
"bottom-half". For more details see the kernel documentation.</P>
|
|
|
|
<H3>Hardware interrupts</H3>
|
|
|
|
<P>Interrupts convey a lot of information but only indirectly. The
|
|
interrupt request signal (a voltage on a wire) sent by a device just
|
|
tells a chip called the interrupt controller that a certain device
|
|
needs attention. The interrupt controller then signals the CPU. The
|
|
CPU then interrupts whatever it was doing, finds the driver code for
|
|
this device and runs a part of it known as an "interrupt service
|
|
routine" (or "interrupt handler"). This "routine" tries to find out
|
|
what has happened and then deals with the problem. For example, bytes
|
|
may need to be transferred from/to the device. This program
|
|
(routine) can easily find out what has happened since the device has
|
|
registers at addresses known to the driver software (provided the IRQ
|
|
number and the I/O address of the device has been set correctly).
|
|
These registers contain status information about the device . The
|
|
software reads the contents of these registers and by inspecting the
|
|
contents, finds out what happened and takes appropriate action.</P>
|
|
<P>
|
|
<A NAME="pci_irq_share"></A>
|
|
Thus each device driver needs to know what interrupt number (IRQ) to
|
|
listen for. On the PCI bus (and for some special cases on the ISA bus)
|
|
it's possible for two (or more) devices to share the same IRQ number.
|
|
Note that you can't share a PCI interrupt with an ISA interrupt (are
|
|
there any exceptions ??). When a shared interrupt is issued, the CPU
|
|
runs all interrupt service routines sequentially for all devices using
|
|
that interrupt. The first thing such a service routine does is to
|
|
check its device's registers to see if an interrupt actually happened
|
|
for its device. If it finds that its device didn't issue an interrupt
|
|
(a false alarm) then it likely will immediately exit and the next service
|
|
routine begins for the second device which uses that same interrupt.
|
|
It checks out the device like described above. This sequence is
|
|
repeated until the device is found that actually issued the interrupt.
|
|
All the interrupt routines for an interrupt are said to be
|
|
constitute a chain. So the chain is traversed until a routine on the
|
|
chain claims the interrupt by saying in effect: this interrupt was for
|
|
me. After it handles the interrupt, the interrupt service routines
|
|
further out on the chain don't run. </P>
|
|
<P>The putting of a voltage on the IRQ line is only a request that the
|
|
CPU be interrupted so it can run a device driver. In almost all cases
|
|
the CPU is interrupted per the request. But interrupts may be
|
|
temporarily disabled or prioritized so that in rare cases the actual
|
|
interrupt of the CPU doesn't happen (or gets delayed). Thus what was
|
|
above called an "interrupt" is more precisely only an interrupt
|
|
request and explains why IRQ stands for Interrupt ReQuest.</P>
|
|
|
|
<H2><A NAME="ss11.5">11.5</A> <A HREF="Plug-and-Play-HOWTO.html#toc11.5">How the Device Driver Catches its Interrupt</A>
|
|
</H2>
|
|
|
|
<P>The previous statement, that device drivers listen for their
|
|
interrupt, was an oversimplification. Actually it's a chip (or part
|
|
of a chip) on the motherboard called the "interrupt controller" that
|
|
listens for all interrupts. When the interrupt controller catches an
|
|
interrupt, it sends a signal to the CPU to start the appropriate
|
|
device driver's "interrupt service routine" to handle the interrupt.</P>
|
|
<P>There are various types of interrupt controllers. One type is the
|
|
APIC = Advanced Programmable Interrupt Controller which usually has
|
|
input pins for many interrupts, including PCI interrupts. Older
|
|
controllers only have pins for ISA interrupts but they can still
|
|
handle PCI interrupts since there is a "programmable interrupt router"
|
|
that converts PCI interrupts to ISA interrupts and routes them to
|
|
certain pins (= certain IRQs) on the ISA interrupt controller.</P>
|
|
|
|
<H2><A NAME="isolation_"></A> <A NAME="ss11.6">11.6</A> <A HREF="Plug-and-Play-HOWTO.html#toc11.6">ISA Isolation </A>
|
|
</H2>
|
|
|
|
<P> This is only for the old ISA bus. Isolation is a complex method
|
|
of assigning a temporary handle (id number or Card Select Number =
|
|
CSN) to each PnP device on the ISA bus. Since there are more
|
|
efficient (but more complex) ways to do this, some might claim that
|
|
it's a simple method. Only one write address is used for PnP writes
|
|
to all PnP devices so that writing to this address goes to all PnP
|
|
device that are listening. This write address is used to send
|
|
(assign) a unique handle to each PnP device. To assign this handle
|
|
requires that only one device be listening when the handle is sent
|
|
(written) to this common address. All PnP devices have a unique
|
|
serial number which they use for the process of isolation. Doing
|
|
isolation is something like a game. It's done using the equivalent of
|
|
just one common bus wire connecting all PnP devices to the isolation
|
|
program.</P>
|
|
<P>For the first round of the "game" all PnP devices listen on this wire
|
|
and send out simultaneously a sequence of bits to the wire. The
|
|
allowed bits are either a 1 (positive voltage) or an "open 0" of no
|
|
voltage (open circuit or tri-state). To do this, each PnP device just
|
|
starts to sequentially send out its serial number on this wire,
|
|
voltage (open circuit or tri-state). To do this, each PnP device just
|
|
starts to sequentially send out its serial number on this wire,
|
|
bit-by-bit, starting with the high-order bit. If any device sends a
|
|
1, a 1 will be heard on the wire by all other devices. If all devices
|
|
send an "open 0" nothing will be heard on the wire. The object is to
|
|
eliminate (by the end of this first round) all but highest serial
|
|
number device. "Eliminate" means to drop out of this round of the
|
|
game and thus temporarily cease to listen anymore to the wire. (Note
|
|
that all serial numbers are of the same length.) When there remains
|
|
only one device still listening, it will be given a handle (card
|
|
number).</P>
|
|
<P>First consider only the high-order bit of the serial number which is
|
|
put on the wire first by all devices which have no handle yet. If any
|
|
PnP device sends out a 0 (open 0) but hears a 1, this means that some
|
|
other PnP device has a higher serial number, so it temporarily drops
|
|
out of this round. Now the devices remaining in the game (for this
|
|
round) all have the same leading digit (a 1) so we may strip off this
|
|
digit and consider only the resulting "stripped serial number" for
|
|
future participation in this round. Then go to the start of this
|
|
paragraph and repeat until the entire serial number has been examined
|
|
for each device (see below for the all-0 case).</P>
|
|
<P>Thus it's clear that only cards with the lower serial number get
|
|
eliminated during a round. But what happens if all devices in the
|
|
game all send out a 0 as their high-order bit? In this case an "open
|
|
0" is sent on the line and all participants stay in the game. If they
|
|
all have a leading 0 then this is a tie and the 0's are stripped off
|
|
just like the 1's were in the above paragraph. The game then
|
|
continues as the next digit (of the serial number) is sent out.</P>
|
|
<P>At the end of the round (after the low-order bit of the serial number
|
|
has been sent out) only one PnP device with the highest serial number
|
|
remains in the game. It then gets assigned a handle and drops out of
|
|
the game permanently. Then all the dropouts from the previous round
|
|
(that don't have a handle yet) reenter the game and a new round begins
|
|
with one less participant. Eventually, all PnP devices are assigned
|
|
handles. It's easy to prove that this algorithm works. The actual
|
|
algorithm is a little more complex than that presented above since
|
|
each step is repeated twice to ensure reliability and the repeats are
|
|
done somewhat differently (but use the same basic idea).</P>
|
|
<P>Once all handles are assigned, they are used to address each PnP
|
|
device for sending/reading configuration data. Note that these
|
|
handles are only used for PnP configuration and are not used for
|
|
normal communication with the PnP device. When the computer starts up
|
|
a PnP BIOS will often do such an isolation and then a PnP
|
|
configuration. After that, all the handles are "lost" so that if one
|
|
wants to change (or inspect) the configuration again, the isolation
|
|
must be done over again.</P>
|
|
|
|
<H2><A NAME="ss11.7">11.7</A> <A HREF="Plug-and-Play-HOWTO.html#toc11.7">Bus Mastering and DMA resources</A>
|
|
</H2>
|
|
|
|
<P>If a bus has bus mastering available, it's unlikely that any
|
|
resources will be needed for DMA on that bus. For example, the PCI bus
|
|
doesn't need DMA resources since it has "bus mastering". However, "bus
|
|
mastering" is often called DMA. But since it's not strictly DMA it
|
|
needs no DMA resources. The ISA and VESA local bus had no bus
|
|
mastering. The old MCA and EISA buses did have bus mastering.</P>
|
|
|
|
<H2><A NAME="ss11.8">11.8</A> <A HREF="Plug-and-Play-HOWTO.html#toc11.8">Historical and Obsolete</A>
|
|
</H2>
|
|
|
|
<H3>OSS-Lite Sound Driver</H3>
|
|
|
|
<P>You must give the IO, IRQ, and DMA as parameters to a module or
|
|
compile them into the kernel. But some PCI cards will get
|
|
automatically detected. RedHat supplies a program "sndconfig" which
|
|
detects ISA PnP sound cards and automatically sets up the modules for
|
|
loading with the detected bus-resources.</P>
|
|
|
|
<H3>ALSA (Advanced Linux Sound Architecture) as of 2000</H3>
|
|
|
|
<P> This will detect the card by PnP methods and then select the
|
|
appropriate driver and load it. It will also set the bus-resources on
|
|
an ISA-PnP cards or PCI cards. OSS (Open Sound System) was formerly
|
|
popular.</P>
|
|
|
|
<H3>MS Windows Notes </H3>
|
|
|
|
<P>Windows NT4 didn't support ISAPNP but had a
|
|
PNPISA program which one could "use at your own risk". For NT4 users
|
|
were advised to set "not a PnP OS" in the BIOS so that the BIOS would
|
|
do the resource configuring. Thus both MS Windows and Linux were in
|
|
olden days dependent on the BIOS doing the configuring (and still are).</P>
|
|
<P>END OF Plug-and-Play-HOWTO</P>
|
|
<HR>
|
|
Next
|
|
<A HREF="Plug-and-Play-HOWTO-10.html">Previous</A>
|
|
<A HREF="Plug-and-Play-HOWTO.html#toc11">Contents</A>
|
|
</BODY>
|
|
</HTML>
|