Date: Sun, 23 Aug 1998 13:47:51 -0400 (EDT) From: Bill Paul <wpaul@skynet.ctr.columbia.edu> To: chuckr@glue.umd.edu (Chuck Robey) Cc: hackers@FreeBSD.ORG Subject: Re: PCI devices Message-ID: <199808231747.NAA18976@skynet.ctr.columbia.edu> In-Reply-To: <Pine.BSF.4.00.9808231030210.361-100000@picnic.mat.net> from "Chuck Robey" at Aug 23, 98 10:32:37 am
next in thread | previous in thread | raw e-mail | index | archive | help
Of all the gin joints in all the towns in all the world, Chuck Robey had to walk into mine and say: > Does anyone know where I might find a good example of probing and > attaching a pci device? I'm talking about the C code. I'm looking at a > PCI sound card, but I can't find anything on how to do sound stuff using > PCI. > > Thanks. I would start by looking at the device drivers in /sys/pci. That's where I started. For the most part, you don't need to do very much to probe a PCI device: the PCI support code finds all PCI devices that are in the system for you. The PCI support code knows about what drivers are in the system by using linker sets: each driver has a linker set which specifies the name of the probe and attach routines in the driver (which are normally declared static), and the PCI code will run down the list of available drivers and call the probe routine of each one. The probe routine is very simple: the PCI support code takes the PCI device ID (which is a 32-bit value containing a 16-bit vendor ID and 16-bit device ID) for all the PCI devices that it finds and passes them in turn to all available device drivers. The driver probe routine compares the ID to a list of vendor/drvice IDs that it knows about, and if the supplied ID matches one in its list, it returns a pointer to a string describing the device. If there's no match, it returns NULL. Once the PCI code gets a positive result back from a probe routine, it will call back to the attach routine later to complete the setup. The attach routine is passed a PCI config_id handle which can be used with various functions to read or write PCI registers from the device. There are a couple of things you have to do in the attach routine: - Obtain the iobase or membase address of the device. You need this in order to be able to issue commands to the device or read its non-PCI registers. PCI devices can be controlled in one of two ways: you can either use PIO accesses through I/O space using inb/outb and friends, or you can map the device's register directly into system memory, in which case you can just read and write directly to memory locations. Not all devices support memory mapping however; check your manual. Also, sometimes the PCI BIOS will not enable memory mapped access when configuring the device: if this is the case, you need to use pci_conf_write() to flip on the right bit in the command register. There's also a bit for enabling iospace access. (You can use pci_conf_read() to read the register.) - If you choose to use memory mapped access, you need to call pci_map_mem() to map the memory region and obtain its base address. You will get both a kernel virtual address and a physical one. You will most likely want the kernel virtual one. - Enable bus mastering support. If your device uses bus-master DMA, you might have to enable it by setting the correct bit in the command register. Again, this should be set by the PCI BIOS, but sometimes it isn't. Note that when using bus-master DMA, you generally have to give the chip the address of a memory buffer from which data will be transfered (or into which data will be transfered). This address must be a physical address, not a kernel virtual address, since the device knows nothing about the kernel's virtual memory mappings. You obtain the physical address using vtophys(), however once you have the physical address I don't think you can transform it back to a kernel virtual address since there may be more than one virtual to physical mapping. Also note that sometimes bus master PCI devices will exhibit strange failure modes if you put them in the wrong slot. My understanding is that PCI bus master devices must go in bus master slots, and putting them in PCI slave slots won't work. - You need to install your interrupt handler. This is done using pci_map_int(). You need to supply a pointer to your interrupt handler routine. This is generic PCI setup which applies to any PCI device: the offsets of the command register and IRQ line register are well known and defined in /sys/pci/pcireg.h, along with other standard register offsets common to all PCI devices. Your device may have other non-standard PCI registers; if so, they should be described in the documentation. If not, LART the vendor. One newer wrinkle is power management. Devices which support power management have a capabilities ID register, which will have a bit set to indicate that power management is available. There's also a power management status register and control register. You may need to insure that the device is set to the correct power mode (D0 is usually the full power mode) before putting the device into operation. Windoze is known to set some devices into low power mode during shutdown; if you warm boot from Windoze to FreeBSD, you may then have to put the device back into the right power mode in the attach routine (the PCI BIOS is supposed to do this, but older BIOSes may not). As for 'PCI sound stuff,' that I don't know about. So far I've only written network drivers, but I'd wager that there are a couple of similarities. You probably have to provide a way to transfer large streams of encoded audio data into and out of the adapter, which is probably where DMA comes in. You have to give the card pointers to buffers containing audio data to be played, then wait for an interrupt from the card telling you the transfer is complete so you can free the buffers and transfer more. And you need to be able to program mixer levels and things using internal registers. I don't know about things like MIDI or wave tables so I can't imagine how those work. I'm assuming you do have the proper documentation for your board; if not you're going to be totally lost. -Bill P.S.: Don't be fooled by marketing literature (or clueless lusers) who talk about PCI adapters with "plug & play" support. PCI implies "plug & play" in that the PCI BIOS works out what iospace and membase addresses and IRQs to assign to cards in order to avoid resource conflicts. But this is not the same as Plug & Play (tm), which I think only applies to ISA boards. I sometimes see people on mailing lists or newsgroups complaining that their PCI devices don't work for some reason, and often someone follows up with a suggestion to "disable plug & play| support. These people are confused: PCI devices don't support Plug & Play (tm), so there's nothing to turn off. -- ============================================================================= -Bill Paul (212) 854-6020 | System Manager, Master of Unix-Fu Work: wpaul@ctr.columbia.edu | Center for Telecommunications Research Home: wpaul@skynet.ctr.columbia.edu | Columbia University, New York City ============================================================================= "It is not I who am crazy; it is I who am mad!" - Ren Hoek, "Space Madness" ============================================================================= To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199808231747.NAA18976>