aboutsummaryrefslogtreecommitdiff
path: root/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml
diff options
context:
space:
mode:
Diffstat (limited to 'en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml')
-rw-r--r--en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml372
1 files changed, 0 insertions, 372 deletions
diff --git a/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml
deleted file mode 100644
index ca94063864..0000000000
--- a/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml
+++ /dev/null
@@ -1,372 +0,0 @@
-<!--
- The FreeBSD Documentation Project
-
- $FreeBSD: doc/en_US.ISO_8859-1/books/developers-handbook/pci/chapter.sgml,v 1.2 2001/04/09 00:33:42 dd Exp $
--->
-
-<chapter id="pci">
- <title>PCI Devices</title>
-
- <para>This chapter will talk about the FreeBSD mechanisms for
- writing a device driver for a device on a PCI bus.</para>
-
- <sect1>
- <title>Probe and Attach</title>
-
- <para>Information here about how the PCI bus code iterates through
- the unattached devices and see if a newly loaded kld will attach
- to any of them.</para>
-
-<programlisting>/*
- * Simple KLD to play with the PCI functions.
- *
- * Murray Stokely
- */
-
-#define MIN(a,b) (((a) < (b)) ? (a) : (b))
-
-#include &lt;sys/types.h&gt;
-#include &lt;sys/module.h&gt;
-#include &lt;sys/systm.h&gt; /* uprintf */
-#include &lt;sys/errno.h&gt;
-#include &lt;sys/param.h&gt; /* defines used in kernel.h */
-#include &lt;sys/kernel.h&gt; /* types used in module initialization */
-#include &lt;sys/conf.h&gt; /* cdevsw struct */
-#include &lt;sys/uio.h&gt; /* uio struct */
-#include &lt;sys/malloc.h&gt;
-#include &lt;sys/bus.h&gt; /* structs, prototypes for pci bus stuff */
-
-#include &lt;pci/pcivar.h&gt; /* For get_pci macros! */
-
-/* Function prototypes */
-d_open_t mypci_open;
-d_close_t mypci_close;
-d_read_t mypci_read;
-d_write_t mypci_write;
-
-/* Character device entry points */
-
-static struct cdevsw mypci_cdevsw = {
- mypci_open,
- mypci_close,
- mypci_read,
- mypci_write,
- noioctl,
- nopoll,
- nommap,
- nostrategy,
- "mypci",
- 36, /* reserved for lkms - /usr/src/sys/conf/majors */
- nodump,
- nopsize,
- D_TTY,
- -1
-};
-
-/* vars */
-static dev_t sdev;
-
-/* We're more interested in probe/attach than with
- open/close/read/write at this point */
-
-int
-mypci_open(dev_t dev, int oflags, int devtype, struct proc *p)
-{
- int err = 0;
-
- uprintf("Opened device \"mypci\" successfully.\n");
- return(err);
-}
-
-int
-mypci_close(dev_t dev, int fflag, int devtype, struct proc *p)
-{
- int err=0;
-
- uprintf("Closing device \"mypci.\"\n");
- return(err);
-}
-
-int
-mypci_read(dev_t dev, struct uio *uio, int ioflag)
-{
- int err = 0;
-
- uprintf("mypci read!\n");
- return err;
-}
-
-int
-mypci_write(dev_t dev, struct uio *uio, int ioflag)
-{
- int err = 0;
-
- uprintf("mypci write!\n");
- return(err);
-}
-
-/* PCI Support Functions */
-
-/*
- * Return identification string if this is device is ours.
- */
-static int
-mypci_probe(device_t dev)
-{
- uprintf("MyPCI Probe\n"
- "Vendor ID : 0x%x\n"
- "Device ID : 0x%x\n",pci_get_vendor(dev),pci_get_device(dev));
-
- if (pci_get_vendor(dev) == 0x11c1) {
- uprintf("We've got the Winmodem, probe successful!\n");
- return 0;
- }
-
- return ENXIO;
-}
-
-/* Attach function is only called if the probe is successful */
-
-static int
-mypci_attach(device_t dev)
-{
- uprintf("MyPCI Attach for : deviceID : 0x%x\n",pci_get_vendor(dev));
- sdev = make_dev(<literal>&</literal>mypci_cdevsw,
- 0,
- UID_ROOT,
- GID_WHEEL,
- 0600,
- "mypci");
- uprintf("Mypci device loaded.\n");
- return ENXIO;
-}
-
-/* Detach device. */
-
-static int
-mypci_detach(device_t dev)
-{
- uprintf("Mypci detach!\n");
- return 0;
-}
-
-/* Called during system shutdown after sync. */
-
-static int
-mypci_shutdown(device_t dev)
-{
- uprintf("Mypci shutdown!\n");
- return 0;
-}
-
-/*
- * Device suspend routine.
- */
-static int
-mypci_suspend(device_t dev)
-{
- uprintf("Mypci suspend!\n");
- return 0;
-}
-
-/*
- * Device resume routine.
- */
-
-static int
-mypci_resume(device_t dev)
-{
- uprintf("Mypci resume!\n");
- return 0;
-}
-
-static device_method_t mypci_methods[] = {
- /* Device interface */
- DEVMETHOD(device_probe, mypci_probe),
- DEVMETHOD(device_attach, mypci_attach),
- DEVMETHOD(device_detach, mypci_detach),
- DEVMETHOD(device_shutdown, mypci_shutdown),
- DEVMETHOD(device_suspend, mypci_suspend),
- DEVMETHOD(device_resume, mypci_resume),
-
- { 0, 0 }
-};
-
-static driver_t mypci_driver = {
- "mypci",
- mypci_methods,
- 0,
- /* sizeof(struct mypci_softc), */
-};
-
-static devclass_t mypci_devclass;
-
-DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0);</programlisting>
-
- <para>Additional Resources
- <itemizedlist>
- <listitem><simpara><ulink url="http://www.pcisig.org">PCI
- Special Interest Group</ulink></simpara></listitem>
-
- <listitem><simpara>PCI System Architecture, Fourth Edition by
- Tom Shanley, et al.</simpara></listitem>
-
- </itemizedlist>
- </para>
- </sect1>
-
- <sect1>
- <title>Bus Resources</title>
-
- <para>FreeBSD provides an object-oriented mechanism for requesting
- resources from a parent bus. Almost all devices will be a child
- member of some sort of bus (PCI, ISA, USB, SCSI, etc) and these
- devices need to acquire resources from their parent bus (such as
- memory segments, interrupt lines, or DMA channels).</para>
-
- <sect2>
- <title>Base Address Registers</title>
-
- <para>To do anything particularly useful with a PCI device you
- will need to obtain the <emphasis>Base Address
- Registers</emphasis> (BARs) from the PCI Configuration space.
- The PCI-specific details of obtaining the BAR is abstracted in
- the <function>bus_alloc_resource()</function> function.</para>
-
- <para>For example, a typical driver might have something similar
- to this in the <function>attach()</function> function. : </para>
-
-<programlisting> sc->bar0id = 0x10;
- sc->bar0res = bus_alloc_resource(dev, SYS_RES_MEMORY, &amp;(sc->bar0id),
- 0, ~0, 1, RF_ACTIVE);
- if (sc->bar0res == NULL) {
- uprintf("Memory allocation of PCI base register 0 failed!\n");
- error = ENXIO;
- goto fail1;
- }
-
- sc->bar1id = 0x14;
- sc->bar1res = bus_alloc_resource(dev, SYS_RES_MEMORY, &amp;(sc->bar1id),
- 0, ~0, 1, RF_ACTIVE);
- if (sc->bar1res == NULL) {
- uprintf("Memory allocation of PCI base register 1 failed!\n");
- error = ENXIO;
- goto fail2;
- }
- sc->bar0_bt = rman_get_bustag(sc->bar0res);
- sc->bar0_bh = rman_get_bushandle(sc->bar0res);
- sc->bar1_bt = rman_get_bustag(sc->bar1res);
- sc->bar1_bh = rman_get_bushandle(sc->bar1res);
-
-</programlisting>
-
- <para>Handles for each base address register are kept in the
- <structname>softc</structname> structure so that they can be
- used to write to the device later.</para>
-
- <para>These handles can then be used to read or write from the
- device registers with the <function>bus_space_*</function>
- functions. For example, a driver might contain a shorthand
- function to read from a board specific register like this :
- </para>
-
-<programlisting>uint16_t
-board_read(struct ni_softc *sc, uint16_t address) {
- return bus_space_read_2(sc->bar1_bt, sc->bar1_bh, address);
-}
-</programlisting>
-
- <para>Similarly, one could write to the registers with : </para>
-
-<programlisting>void
-board_write(struct ni_softc *sc, uint16_t address, uint16_t value) {
- bus_space_write_2(sc->bar1_bt, sc->bar1_bh, address, value);
-}
-</programlisting>
-
- <para>These functions exist in 8bit, 16bit, and 32bit versions
- and you should use
- <function>bus_space_{read|write}_{1|2|4}</function>
- accordingly.</para>
-
- </sect2>
- <sect2>
- <title>Interrupts</title>
-
- <para>Interrupts are allocated from the object-oriented bus code
- in a way similar to the memory resources. First an IRQ
- resource must be allocated from the parent bus, and then the
- interrupt handler must be setup to deal with this IRQ.</para>
-
- <para>Again, a sample from a device
- <function>attach()</function> function says more than
- words.</para>
-
-<programlisting>/* Get the IRQ resource */
-
- sc->irqid = 0x0;
- sc->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &amp;(sc->irqid),
- 0, ~0, 1, RF_SHAREABLE | RF_ACTIVE);
- if (sc->irqres == NULL) {
- uprintf("IRQ allocation failed!\n");
- error = ENXIO;
- goto fail3;
- }
-
- /* Now we should setup the interrupt handler */
-
- error = bus_setup_intr(dev, sc->irqres, INTR_TYPE_MISC,
- my_handler, sc, &amp;(sc->handler));
- if (error) {
- printf("Couldn't set up irq\n");
- goto fail4;
- }
-
- sc->irq_bt = rman_get_bustag(sc->irqres);
- sc->irq_bh = rman_get_bushandle(sc->irqres);
-</programlisting>
-
- </sect2>
-
- <sect2>
- <title>DMA</title>
- <para>On the PC, peripherals that want to do bus-mastering DMA
- must deal with physical addresses. This is a problem since
- FreeBSD uses virtual memory and deals almost exclusively with
- virtual addresses. Fortunately, there is a function,
- <function>vtophys()</function> to help.</para>
-
-<programlisting>#include &lt;vm/vm.h&gt;
-#include &lt;vm/pmap.h&gt;
-
-#define vtophys(virtual_address) (...)
-</programlisting>
-
- <para>The solution is a bit different on the alpha however, and
- what we really want is a function called
- <function>vtobus()</function>.</para>
-
-<programlisting>#if defined(__alpha__)
-#define vtobus(va) alpha_XXX_dmamap((vm_offset_t)va)
-#else
-#define vtobus(va) vtophys(va)
-#endif
-</programlisting>
-
- </sect2>
-
- <sect2>
- <title>Deallocating Resources</title>
-
- <para>It's very important to deallocate all of the resources
- that were allocated during <function>attach()</function>.
- Care must be taken to deallocate the correct stuff even on a
- failure condition so that the system will remain useable while
- your driver dies.</para>
-
- </sect2>
- </sect1>
-
-</chapter>
-
-