patch-2.3.43 linux/Documentation/pci.txt

Next file: linux/Documentation/pm.txt
Previous file: linux/Documentation/networking/tlan.txt
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.42/linux/Documentation/pci.txt linux/Documentation/pci.txt
@@ -1,52 +1,130 @@
-		       Few Notes About The PCI Subsystem
+			 How To Write Linux PCI Drivers
 
-				       or
-
-		"What should you avoid when writing PCI drivers"
-
-		  by Martin Mares <mj@suse.cz> on 21-Nov-1999
+		  by Martin Mares <mj@suse.cz> on 07-Feb-2000
 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The world of PCI is vast and it's full of (mostly unpleasant) surprises.
+Different PCI devices have different requirements and different bugs --
+because of this, the PCI support layer in Linux kernel is not as trivial
+as one would wish. This short pamphlet tries to help all potential driver
+authors to find their way through the deep forests of PCI handling.
+
 
 0. Structure of PCI drivers
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
-   Aa typical PCI device driver needs to perform the following actions:
+There exist two kinds of PCI drivers: new-style ones (which leave most of
+probing for devices to the PCI layer and support online insertion and removal
+of devices [thus supporting PCI, hot-pluggable PCI and CardBus in single
+driver]) and old-style ones which just do all the probing themselves. Unless
+you have a very good reason to do so, please don't use the old way of probing
+in any new code. After the driver finds the devices it wishes to operate
+on (either the old or the new way), it needs to perform the following steps:
+
+	Enable the device
+	Access device configuration space
+	Discover resources (addresses and IRQ numbers) provided by the device
+	Allocate these resources
+	Communicate with the device
+
+Most of these topics are covered by the following sections, for the rest
+look at <linux/pci.h>, it's hopefully well commented.
+
+If the PCI subsystem is not configured (CONFIG_PCI is not set), most of
+the functions described below are defined as inline functions either completely
+empty or just returning an appropriate error codes to avoid lots of ifdefs
+in the drivers.
+
+
+1. New-style drivers
+~~~~~~~~~~~~~~~~~~~~
+The new-style drivers just call pci_register_driver during their initialization
+with a pointer to a structure describing the driver (struct pci_driver) which
+contains:
+
+	name		Name of the driver
+	id_table	Pointer to table of device ID's the driver is
+			interested in
+	probe		Pointer to a probing function which gets called (during
+			execution of pci_register_driver for already existing
+			devices or later if a new device gets inserted) for all
+			PCI devices which match the ID table and are not handled
+			by the other drivers yet. This function gets passed a pointer
+			to the pci_dev structure representing the device and also
+			which entry in the ID table did the device match. It returns
+			zero when the driver has accepted the device or an error
+			code (negative number) otherwise. This function always gets
+			called from process context, so it can sleep.
+	remove		Pointer to a function which gets called whenever a device
+			being handled by this driver is removed (either during
+			deregistration of the driver or when it's manually pulled
+			out of a hot-pluggable slot). This function can be called
+			from interrupt context.
+	suspend,	Power management hooks (currently used only for CardBus
+	resume		cards) -- called when the device goes to sleep or is
+			resumed.
+
+The ID table is an array of struct pci_device_id ending with a all-zero entry.
+Each entry consists of:
+
+	vendor, device	Vendor and device ID to match (or PCI_ANY_ID)
+	subvendor,	Subsystem vendor and device ID to match (or PCI_ANY_ID)
+	subdevice
+	class,		Device class to match. The class_mask tells which bits
+	class_mask	of the class are honored during the comparison.
+	driver_data	Data private to the driver.
+
+When the driver exits, it just calls pci_deregister_driver() and the PCI layer
+automatically calls the remove hook for all devices handled by the driver.
+
+Please mark the initialization and cleanup functions where appropriate
+(the corresponding macros are defined in <linux/init.h>):
+
+	__init		Initialization code. Thrown away after the driver
+			initializes.
+	__exit		Exit code. Ignored for non-modular drivers.
+	__devinit	Device initialization code. Identical to __init if
+			the kernel is not compiled with CONFIG_HOTPLUG, normal
+			function otherwise.
+	__devexit	The same for __exit.
+
+
+2. How to find PCI devices manually (the old style)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+PCI drivers not using the pci_register_driver() interface search
+for PCI devices manually using the following constructs:
+
+Searching by vendor and device ID:
+
+	struct pci_dev *dev = NULL;
+	while (dev = pci_find_device(VENDOR_ID, DEVICE_ID, dev))
+		configure_device(dev);
+
+Searching by class ID (iterate in a similar way):
 
-	1. Find PCI devices it's able to handle
-	2. Enable them
-	3. Access their configuration space
-	4. Discover addresses and IRQ numbers
-
-1. How to find PCI devices
-~~~~~~~~~~~~~~~~~~~~~~~~~~
-   In case your driver wants to search for all devices with given vendor/device
-ID, it should use:
-
-		struct pci_dev *dev = NULL;
-		while (dev = pci_find_device(VENDOR_ID, DEVICE_ID, dev))
-			configure_device(dev);
+	pci_find_class(CLASS_ID, dev)
 
-   For class-based search, use pci_find_class(CLASS_ID, dev).
+Searching by both vendor/device and subsystem vendor/device ID:
 
-   If you need to match by subsystem vendor/device ID, use
-pci_find_subsys(VENDOR_ID, DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev).
+	pci_find_subsys(VENDOR_ID, DEVICE_ID, SUBSYS_VENDOR_ID, SUBSYS_DEVICE_ID, dev).
 
    You can use the constant PCI_ANY_ID as a wildcard replacement for
 VENDOR_ID or DEVICE_ID.  This allows searching for any device from a
 specific vendor, for example.
 
-   In case you want to do some complex matching, you can walk the list of all
-known PCI devices:
+   In case you need to decide according to some more complex criteria,
+you can walk the list of all known PCI devices yourself:
 
-		struct pci_dev *dev;
-		pci_for_each_dev(dev) {
-			... do anything you want with dev ...
-		}
+	struct pci_dev *dev;
+	pci_for_each_dev(dev) {
+		... do anything you want with dev ...
+	}
 
-   The `struct pci_dev *' pointer serves as an identification of a PCI device
-and is passed to all other functions operating on PCI devices.
+For compatibility with device ordering in older kernels, you can also
+use pci_for_each_dev_reverse(dev) for walking the list in the opposite
+direction.
 
-2. Enabling devices
+
+3. Enabling devices
 ~~~~~~~~~~~~~~~~~~~
    Before you do anything with the device you've found, you need to enable
 it by calling pci_enable_device() which enables I/O and memory regions of
@@ -57,7 +135,8 @@
 which enables the bus master bit in PCI_COMMAND register and also fixes
 the latency timer value if it's set to something bogus by the BIOS.
 
-3. How to access PCI config space
+
+4. How to access PCI config space
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    You can use pci_(read|write)_config_(byte|word|dword) to access the config
 space of a device represented by struct pci_dev *. All these functions return 0
@@ -72,7 +151,8 @@
 pci_find_capability() for the particular capability and it will find the
 corresponding register block for you.
 
-4. Addresses and interrupts
+
+5. Addresses and interrupts
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    Memory and port addresses and interrupt numbers should NOT be read from the
 config space. You should use the values in the pci_dev structure as they might
@@ -86,13 +166,33 @@
    All interrupt handlers should be registered with SA_SHIRQ and use the devid
 to map IRQs to devices (remember that all PCI interrupts are shared).
 
-5. Other interesting functions
+
+6. Other interesting functions
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 pci_find_slot()			Find pci_dev corresponding to given bus and
 				slot numbers.
 pci_set_power_state()		Set PCI Power Management state (0=D0 ... 3=D3)
+pci_find_capability()		Find specified capability in device's capability
+				list.
+
+
+7. Miscellaneous hints
+~~~~~~~~~~~~~~~~~~~~~~
+When displaying PCI slot names to the user (for example when a driver wants
+to tell the user what card has it found), please use pci_dev->slot_name
+for this purpose.
+
+Always refer to the PCI devices by a pointer to the pci_dev structure.
+All PCI layer functions use this identification and it's the only
+reasonable one. Don't use bus/slot/function numbers except for very
+special purposes -- on systems with multiple primary buses their semantics
+can be pretty complex.
+
+If you're going to use PCI bus mastering DMA, take a look at
+Documentation/DMA-mapping.txt.
+
 
-6. Obsolete functions
+8. Obsolete functions
 ~~~~~~~~~~~~~~~~~~~~~
 There are several functions kept only for compatibility with old drivers
 not updated to the new PCI interface. Please don't use them in new code.

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)