diff --git a/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml index 078aea0740..ca94063864 100644 --- a/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml +++ b/en_US.ISO8859-1/books/arch-handbook/pci/chapter.sgml @@ -1,216 +1,372 @@ - - PCI Devices + + PCI Devices - This chapter will talk about the FreeBSD mechanisms for - writing a device driver for a device on a PCI bus. + This chapter will talk about the FreeBSD mechanisms for + writing a device driver for a device on a PCI bus. - Probe and Attach + + Probe and Attach + + 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. - 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. /* * Simple KLD to play with the PCI functions. * * Murray Stokely */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #include <sys/bus.h> /* structs, prototypes for pci bus stuff */ #include <pci/pcivar.h> /* 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(&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); - Additional Resources - - PCI Special Interest - Group - PCI System Architecture, Fourth Edition by + Additional Resources + + PCI + Special Interest Group + + PCI System Architecture, Fourth Edition by Tom Shanley, et al. - - - - + + + + + + + Bus Resources + + 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). + + + Base Address Registers + + To do anything particularly useful with a PCI device you + will need to obtain the Base Address + Registers (BARs) from the PCI Configuration space. + The PCI-specific details of obtaining the BAR is abstracted in + the bus_alloc_resource() function. + + For example, a typical driver might have something similar + to this in the attach() function. : + + sc->bar0id = 0x10; + sc->bar0res = bus_alloc_resource(dev, SYS_RES_MEMORY, &(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, &(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); + + + + Handles for each base address register are kept in the + softc structure so that they can be + used to write to the device later. + + These handles can then be used to read or write from the + device registers with the bus_space_* + functions. For example, a driver might contain a shorthand + function to read from a board specific register like this : + + +uint16_t +board_read(struct ni_softc *sc, uint16_t address) { + return bus_space_read_2(sc->bar1_bt, sc->bar1_bh, address); +} + + + Similarly, one could write to the registers with : + +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); +} + + + These functions exist in 8bit, 16bit, and 32bit versions + and you should use + bus_space_{read|write}_{1|2|4} + accordingly. + + + + Interrupts + + 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. + + Again, a sample from a device + attach() function says more than + words. + +/* Get the IRQ resource */ + + sc->irqid = 0x0; + sc->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &(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, &(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); + + + + + + DMA + 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, + vtophys() to help. + +#include <vm/vm.h> +#include <vm/pmap.h> + +#define vtophys(virtual_address) (...) + + + The solution is a bit different on the alpha however, and + what we really want is a function called + vtobus(). + +#if defined(__alpha__) +#define vtobus(va) alpha_XXX_dmamap((vm_offset_t)va) +#else +#define vtobus(va) vtophys(va) +#endif + + + + + + Deallocating Resources + + It's very important to deallocate all of the resources + that were allocated during attach(). + 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. + + + + + diff --git a/en_US.ISO8859-1/books/developers-handbook/pci/chapter.sgml b/en_US.ISO8859-1/books/developers-handbook/pci/chapter.sgml index 078aea0740..ca94063864 100644 --- a/en_US.ISO8859-1/books/developers-handbook/pci/chapter.sgml +++ b/en_US.ISO8859-1/books/developers-handbook/pci/chapter.sgml @@ -1,216 +1,372 @@ - - PCI Devices + + PCI Devices - This chapter will talk about the FreeBSD mechanisms for - writing a device driver for a device on a PCI bus. + This chapter will talk about the FreeBSD mechanisms for + writing a device driver for a device on a PCI bus. - Probe and Attach + + Probe and Attach + + 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. - 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. /* * Simple KLD to play with the PCI functions. * * Murray Stokely */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #include <sys/bus.h> /* structs, prototypes for pci bus stuff */ #include <pci/pcivar.h> /* 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(&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); - Additional Resources - - PCI Special Interest - Group - PCI System Architecture, Fourth Edition by + Additional Resources + + PCI + Special Interest Group + + PCI System Architecture, Fourth Edition by Tom Shanley, et al. - - - - + + + + + + + Bus Resources + + 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). + + + Base Address Registers + + To do anything particularly useful with a PCI device you + will need to obtain the Base Address + Registers (BARs) from the PCI Configuration space. + The PCI-specific details of obtaining the BAR is abstracted in + the bus_alloc_resource() function. + + For example, a typical driver might have something similar + to this in the attach() function. : + + sc->bar0id = 0x10; + sc->bar0res = bus_alloc_resource(dev, SYS_RES_MEMORY, &(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, &(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); + + + + Handles for each base address register are kept in the + softc structure so that they can be + used to write to the device later. + + These handles can then be used to read or write from the + device registers with the bus_space_* + functions. For example, a driver might contain a shorthand + function to read from a board specific register like this : + + +uint16_t +board_read(struct ni_softc *sc, uint16_t address) { + return bus_space_read_2(sc->bar1_bt, sc->bar1_bh, address); +} + + + Similarly, one could write to the registers with : + +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); +} + + + These functions exist in 8bit, 16bit, and 32bit versions + and you should use + bus_space_{read|write}_{1|2|4} + accordingly. + + + + Interrupts + + 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. + + Again, a sample from a device + attach() function says more than + words. + +/* Get the IRQ resource */ + + sc->irqid = 0x0; + sc->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &(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, &(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); + + + + + + DMA + 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, + vtophys() to help. + +#include <vm/vm.h> +#include <vm/pmap.h> + +#define vtophys(virtual_address) (...) + + + The solution is a bit different on the alpha however, and + what we really want is a function called + vtobus(). + +#if defined(__alpha__) +#define vtobus(va) alpha_XXX_dmamap((vm_offset_t)va) +#else +#define vtobus(va) vtophys(va) +#endif + + + + + + Deallocating Resources + + It's very important to deallocate all of the resources + that were allocated during attach(). + 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. + + + + + diff --git a/en_US.ISO_8859-1/books/developers-handbook/pci/chapter.sgml b/en_US.ISO_8859-1/books/developers-handbook/pci/chapter.sgml index 078aea0740..ca94063864 100644 --- a/en_US.ISO_8859-1/books/developers-handbook/pci/chapter.sgml +++ b/en_US.ISO_8859-1/books/developers-handbook/pci/chapter.sgml @@ -1,216 +1,372 @@ - - PCI Devices + + PCI Devices - This chapter will talk about the FreeBSD mechanisms for - writing a device driver for a device on a PCI bus. + This chapter will talk about the FreeBSD mechanisms for + writing a device driver for a device on a PCI bus. - Probe and Attach + + Probe and Attach + + 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. - 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. /* * Simple KLD to play with the PCI functions. * * Murray Stokely */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #include <sys/bus.h> /* structs, prototypes for pci bus stuff */ #include <pci/pcivar.h> /* 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(&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); - Additional Resources - - PCI Special Interest - Group - PCI System Architecture, Fourth Edition by + Additional Resources + + PCI + Special Interest Group + + PCI System Architecture, Fourth Edition by Tom Shanley, et al. - - - - + + + + + + + Bus Resources + + 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). + + + Base Address Registers + + To do anything particularly useful with a PCI device you + will need to obtain the Base Address + Registers (BARs) from the PCI Configuration space. + The PCI-specific details of obtaining the BAR is abstracted in + the bus_alloc_resource() function. + + For example, a typical driver might have something similar + to this in the attach() function. : + + sc->bar0id = 0x10; + sc->bar0res = bus_alloc_resource(dev, SYS_RES_MEMORY, &(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, &(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); + + + + Handles for each base address register are kept in the + softc structure so that they can be + used to write to the device later. + + These handles can then be used to read or write from the + device registers with the bus_space_* + functions. For example, a driver might contain a shorthand + function to read from a board specific register like this : + + +uint16_t +board_read(struct ni_softc *sc, uint16_t address) { + return bus_space_read_2(sc->bar1_bt, sc->bar1_bh, address); +} + + + Similarly, one could write to the registers with : + +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); +} + + + These functions exist in 8bit, 16bit, and 32bit versions + and you should use + bus_space_{read|write}_{1|2|4} + accordingly. + + + + Interrupts + + 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. + + Again, a sample from a device + attach() function says more than + words. + +/* Get the IRQ resource */ + + sc->irqid = 0x0; + sc->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, &(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, &(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); + + + + + + DMA + 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, + vtophys() to help. + +#include <vm/vm.h> +#include <vm/pmap.h> + +#define vtophys(virtual_address) (...) + + + The solution is a bit different on the alpha however, and + what we really want is a function called + vtobus(). + +#if defined(__alpha__) +#define vtobus(va) alpha_XXX_dmamap((vm_offset_t)va) +#else +#define vtobus(va) vtophys(va) +#endif + + + + + + Deallocating Resources + + It's very important to deallocate all of the resources + that were allocated during attach(). + 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. + + + + +