sslug-teknik team mailing list archive
-
sslug-teknik team
-
Mailing list archive
-
Message #41786
Sv: At skrive drivere...
Hej Mads!
>> Har du iøvrigt haft lejlighed til at kigge på den "How To..." som
jeg
>> nævnte? Jeg efterlyste også om nogen kunne fortælle hvordan
forslagene
>> i denne tekst kunne implementeres...
> Gav du en reference til den?
Ja - to gange endda. Men her er den.
---
How To Write Linux PCI Drivers
by Martin Mares <mj@xxxxxxx> 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
Most drivers should export this table using
MODULE_DEVICE_TABLE(pci,...).
Set to NULL to call probe() function for every PCI device known to
the system.
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 -- called when the device goes to
resume 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, normalfunction otherwise.
__devexit The same for __exit.
Tips:
The module_init()/module_exit() functions (and all initialization
functions called only from these) should be marked __init/exit.
The struct pci_driver shouldn't be marked with any of these tags.
The ID table array should be marked __devinitdata.
The probe() and remove() functions (and all initialization functions
called only from these) should be marked __devinit/exit.
If you are sure the driver is not a hotplug driver then use only
__init/exit __initdata/exitdata.
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):
pci_find_class(CLASS_ID, dev)
Searching by both vendor/device and subsystem vendor/device ID:
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 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 ...
}
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.
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 the device, assigns missing resources if needed and wakes
up the device if it was in suspended state. Please note that this
function can fail.
If you want to use the device in bus mastering mode, call
pci_set_master()
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.
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 when successful or an error code (PCIBIOS_...)
which can be translated to a text string by pcibios_strerror. Most
drivers expect that accesses to valid PCI devices don't fail.
If you access fields in the standard portion of the config header,
please use symbolic names of locations and bits declared in
<linux/pci.h>.
If you need to access Extended PCI Capability registers, just call
pci_find_capability() for the particular capability and it will find
the corresponding register block for you.
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 have been remapped by the kernel.
See Documentation/IO-mapping.txt for how to access device memory.
You still need to call request_region() for I/O regions and
request_mem_region() for memory regions to make sure nobody else is
using the same device.
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).
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.
pci_module_init() Inline helper function for ensuring correct
pci_driver initialization and error handling.
pci_resource_start() Returns bus start address for a given PCI region
pci_resource_end() Returns bus end address for a given PCI region
pci_resource_len() Returns the byte length of a PCI region
pci_set_drvdata() Set private driver data pointer for a pci_dev
pci_get_drvdata() Return private driver data pointer for a pci_dev
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.
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.
pcibios_present() Since ages, you don't need to test presence of PCI
subsystem when trying to talk with it. If it's not there, the list
of PCI devices is empty and all functions for searching for devices
just return NULL.
pcibios_(read|write)_* Superseded by their pci_(read|write)_*
counterparts.
pcibios_find_* Superseded by their pci_find_* counterparts.
---
Bedste Hilsner,
Kristian (den stædige :-)
- www.amagerbrofrikirke.dk - en kirke med særpræg -
- stil dine spørgsmål på www.fonager.dk/forum/forum.asp?master_id=3832