Linux Kernel & Device Driver Programming

Ch 12 - PCI Drivers

This file uses the W3C HTML Slidy format. The "a" key toggles between one-slide-at-a-time and single-page mode, and the "c" key toggles on and off the table of contents. The ← and → keys can be used to page forward and backward. For more help on controls see the "help?" link at the bottom.

PCI - Peripheral Component Interconnect

  • An example of a widely used type of bus
  • Connects parts of a computer
  • Defined by a series of standards
  • Covers both electrical and programming interfaces
    • We focus on the programming aspect

PCI - History

PCI - Platform Independence

This slide has additional "handout" notes. You need to use the 'a' key to toggle into handout mode, in order to see them.

PCI was designed to replace the original IBM PC "ISA" bus. It has continued to evolve, including the PCI-Extended (PCI-E) and PCI-Express (PCI-X). These are electrically different from the original PCI, but looks similar from a software point of view.

PCI Bus in Context

Bus Architecture of a PC Using a VIA Chipset for the Pentium IV, reproduced from a VIA Technologies web page, at http://www.via.com.

PCI Addressing

  • address = (bus_number, device_number, function_number)
  • up to 256 buses
  • up to 32 devices per bus (connected by "bridges")
  • up to 8 functions per device
  • Linux type struct pci_dev used to specify address

How to Get Information about PCI Devices

Sample Output of lspci -tv

Numbers are parsed as domain:bus.device.function.

-[0000:00]-+-00.0  Intel Corp. E7501 Memory Controller Hub
           +-00.1  Intel Corp. E7000 Series Host RASUM Controller
           +-02.0-[0000:01-03]--+-1c.0  Intel Corp. 82870P2 P64H2 I/OxAPIC
           |                    +-1d.0-[0000:02]--
           |                    +-1e.0  Intel Corp. 82870P2 P64H2 I/OxAPIC
           |                    \-1f.0-[0000:03]--+-02.0  Intel Corp. 82546EB Gigabit Ethernet Controller (Copper)
           |                                      \-02.1  Intel Corp. 82546EB Gigabit Ethernet Controller (Copper)
           +-04.0-[0000:04-06]--+-1c.0  Intel Corp. 82870P2 P64H2 I/OxAPIC
           |                    +-1d.0-[0000:05]--
           |                    +-1e.0  Intel Corp. 82870P2 P64H2 I/OxAPIC
           |                    \-1f.0-[0000:06]--
           +-1d.0  Intel Corp. 82801CA/CAM USB (Hub #1)
           +-1d.1  Intel Corp. 82801CA/CAM USB (Hub #2)
           +-1d.2  Intel Corp. 82801CA/CAM USB (Hub #3)
           +-1e.0-[0000:07]----01.0  ATI Technologies Inc Rage XL
           +-1f.0  Intel Corp. 82801CA LPC Interface Controller
           +-1f.1  Intel Corp. 82801CA Ultra ATA Storage Controller
           \-1f.3  Intel Corp. 82801CA/CAM SMBus Controller

Sample Output of lspci -tvv

00:00.0 Host bridge: Intel Corp. E7501 Memory Controller Hub (rev 01)
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Capabilities: <available only to root>

00:00.1 Class ff00: Intel Corp. E7000 Series Host RASUM Controller (rev 01)
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O- Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
	Status: Cap- 66Mhz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-

00:02.0 PCI bridge: Intel Corp. E7000 Series Hub Interface B PCI-to-PCI Bridge (rev 01) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap- 66Mhz+ UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 64
	Bus: primary=00, secondary=01, subordinate=03, sec-latency=0
	I/O behind bridge: 00003000-00003fff
	Memory behind bridge: fc100000-fc2fffff
	Expansion ROM at 00003000 [disabled] [size=4K]
	BridgeCtl: Parity- SERR- NoISA+ VGA- MAbort- >Reset- FastB2B-

00:04.0 PCI bridge: Intel Corp. E7000 Series Hub Interface D PCI-to-PCI Bridge (rev 01) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap- 66Mhz+ UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 64
	Bus: primary=00, secondary=04, subordinate=06, sec-latency=0
	Memory behind bridge: fc300000-fc3fffff
	BridgeCtl: Parity- SERR- NoISA+ VGA- MAbort- >Reset- FastB2B-

00:1d.0 USB Controller: Intel Corp. 82801CA/CAM USB (Hub #1) (rev 02) (prog-if 00 [UHCI])
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
	Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Interrupt: pin A routed to IRQ 169
	Region 4: I/O ports at 2000 [size=32]

00:1d.1 USB Controller: Intel Corp. 82801CA/CAM USB (Hub #2) (rev 02) (prog-if 00 [UHCI])
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
	Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Interrupt: pin B routed to IRQ 177
	Region 4: I/O ports at 2020 [size=32]

00:1d.2 USB Controller: Intel Corp. 82801CA/CAM USB (Hub #3) (rev 02) (prog-if 00 [UHCI])
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O+ Mem- BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
	Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Interrupt: pin C routed to IRQ 185
	Region 4: I/O ports at 2040 [size=32]

00:1e.0 PCI bridge: Intel Corp. 82801BA/CA/DB/EB/ER Hub interface to PCI Bridge (rev 42) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Bus: primary=00, secondary=07, subordinate=07, sec-latency=64
	I/O behind bridge: 00004000-00004fff
	Memory behind bridge: fc400000-fdffffff
	BridgeCtl: Parity- SERR- NoISA+ VGA+ MAbort- >Reset- FastB2B-

00:1f.0 ISA bridge: Intel Corp. 82801CA LPC Interface Controller (rev 02)
	Control: I/O+ Mem+ BusMaster+ SpecCycle+ MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0

00:1f.1 IDE interface: Intel Corp. 82801CA Ultra ATA Storage Controller (rev 02) (prog-if 8a [Master SecP PriP])
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
	Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Interrupt: pin A routed to IRQ 185
	Region 0: I/O ports at <ignored>
	Region 1: I/O ports at <ignored>
	Region 2: I/O ports at <ignored>
	Region 3: I/O ports at <ignored>
	Region 4: I/O ports at 2060 [size=16]
	Region 5: Memory at 40000000 (32-bit, non-prefetchable) [size=1K]

00:1f.3 SMBus: Intel Corp. 82801CA/CAM SMBus Controller (rev 02)
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O+ Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B-
	Status: Cap- 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Interrupt: pin B routed to IRQ 193
	Region 4: I/O ports at 1100 [size=32]

01:1c.0 PIC: Intel Corp. 82870P2 P64H2 I/OxAPIC (rev 04) (prog-if 20 [IO(X)-APIC])
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Region 0: Memory at fc100000 (32-bit, non-prefetchable)
	Capabilities: <available only to root>

01:1d.0 PCI bridge: Intel Corp. 82870P2 P64H2 Hub PCI Bridge (rev 04) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 64, Cache Line Size 10
	Bus: primary=01, secondary=02, subordinate=02, sec-latency=64
	BridgeCtl: Parity- SERR- NoISA+ VGA- MAbort- >Reset- FastB2B-
	Capabilities: <available only to root>

01:1e.0 PIC: Intel Corp. 82870P2 P64H2 I/OxAPIC (rev 04) (prog-if 20 [IO(X)-APIC])
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Region 0: Memory at fc101000 (32-bit, non-prefetchable)
	Capabilities: <available only to root>

01:1f.0 PCI bridge: Intel Corp. 82870P2 P64H2 Hub PCI Bridge (rev 04) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 64, Cache Line Size 10
	Bus: primary=01, secondary=03, subordinate=03, sec-latency=64
	I/O behind bridge: 00003000-00003fff
	Memory behind bridge: fc200000-fc2fffff
	Expansion ROM at 00003000 [disabled] [size=4K]
	BridgeCtl: Parity- SERR- NoISA+ VGA- MAbort- >Reset- FastB2B-
	Capabilities: <available only to root>

03:02.0 Ethernet controller: Intel Corp. 82546EB Gigabit Ethernet Controller (Copper) (rev 01)
	Subsystem: Intel Corp. PRO/1000 MT Dual Port Server Adapter
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 64 (63750ns min), Cache Line Size 08
	Interrupt: pin A routed to IRQ 201
	Region 0: Memory at fc200000 (64-bit, non-prefetchable)
	Region 4: I/O ports at 3000 [size=64]
	Capabilities: <available only to root>

03:02.1 Ethernet controller: Intel Corp. 82546EB Gigabit Ethernet Controller (Copper) (rev 01)
	Subsystem: Intel Corp. PRO/1000 MT Dual Port Server Adapter
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV+ VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 64 (63750ns min), Cache Line Size 08
	Interrupt: pin B routed to IRQ 209
	Region 0: Memory at fc220000 (64-bit, non-prefetchable)
	Region 4: I/O ports at 3040 [size=64]
	Capabilities: <available only to root>

04:1c.0 PIC: Intel Corp. 82870P2 P64H2 I/OxAPIC (rev 04) (prog-if 20 [IO(X)-APIC])
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Region 0: Memory at fc300000 (32-bit, non-prefetchable)
	Capabilities: <available only to root>

04:1d.0 PCI bridge: Intel Corp. 82870P2 P64H2 Hub PCI Bridge (rev 04) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 64, Cache Line Size 10
	Bus: primary=04, secondary=05, subordinate=05, sec-latency=64
	BridgeCtl: Parity- SERR- NoISA+ VGA- MAbort- >Reset- FastB2B-
	Capabilities: <available only to root>

04:1e.0 PIC: Intel Corp. 82870P2 P64H2 I/OxAPIC (rev 04) (prog-if 20 [IO(X)-APIC])
	Subsystem: Super Micro Computer Inc: Unknown device 3880
	Control: I/O- Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 0
	Region 0: Memory at fc301000 (32-bit, non-prefetchable)
	Capabilities: <available only to root>

04:1f.0 PCI bridge: Intel Corp. 82870P2 P64H2 Hub PCI Bridge (rev 04) (prog-if 00 [Normal decode])
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR+ FastB2B-
	Status: Cap+ 66Mhz+ UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 64, Cache Line Size 10
	Bus: primary=04, secondary=06, subordinate=06, sec-latency=64
	BridgeCtl: Parity- SERR- NoISA+ VGA- MAbort- >Reset- FastB2B-
	Capabilities: <available only to root>

07:01.0 VGA compatible controller: ATI Technologies Inc Rage XL (rev 27) (prog-if 00 [VGA])
	Subsystem: ATI Technologies Inc Rage XL
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping+ SERR- FastB2B-
	Status: Cap+ 66Mhz- UDF- FastB2B+ ParErr- DEVSEL=medium >TAbort- <TAbort- <MAbort- >SERR- <PERR-
	Latency: 64 (2000ns min), Cache Line Size 08
	Interrupt: pin A routed to IRQ 169
	Region 0: Memory at fd000000 (32-bit, non-prefetchable)
	Region 1: I/O ports at 4000 [size=256]
	Region 2: Memory at fc400000 (32-bit, non-prefetchable) [size=4K]
	Capabilities: <available only to root>

This slide has additional "handout" notes. You need to use the 'a' key to toggle into handout mode, in order to see them.

Numbers above are parsed as bus:device.function.

Other options of lspci produce other forms of output.

Sample output from /proc/bus/pci/devices,

0000    8086254c        0               00000000        00000000
        00000000        00000000        00000000        00000000
        00000000        00000000        00000000        00000000
        00000000        00000000        00000000        00000000
0001    80862541        0               00000000        00000000
        00000000        00000000        00000000        00000000
        00000000        00000000        00000000        00000000
        00000000        00000000        00000000        00000000        
0010    80862543        0               00000000        00000000
        00000000        00000000        00000000        00000000
        00000000        00000000        00000000        00000000
        00000000        00000000        00000000        00000000        
0020    80862547        0               00000000        00000000
        00000000        00000000        00000000        00000000
        00000000        00000000        00000000        00000000
        00000000        00000000        00000000        00000000        
00e8
        80862482        a9              00000000        00000000
        00000000        00000000        00002001        00000000
        00000000        00000000        00000000        00000000
        00000000        00000020        00000000        00000000
        uhci_hcd
00e9    80862484        b1              00000000        00000000
        00000000        00000000        00002021        00000000
        00000000        00000000        00000000        00000000
        00000000        00000020        00000000        00000000
        uhci_hcd
...
00f9    8086248b        b9              00000000        00000000
        00000000        00000000        00002061        40000000
        00000000        00000000        00000000        00000000
        00000000        00000010        00000400        00000000
        PIIX_IDE
...

The above outputs were all from the the FSU CS department's web server as of Summer 2007. Of course, the values will be different for each system.

Output of ls -l /sys/devices/pci0000:00/0000:00:10.2

total 0
-r--r--r--  1 root root 4096 May 30 08:36 class
-rw-r--r--  1 root root  256 May 30 08:36 config
-rw-r--r--  1 root root 4096 May 30 09:30 detach_state
-r--r--r--  1 root root 4096 May 30 08:36 device
-r--r--r--  1 root root 4096 May 30 08:36 irq
  (assigned IRQ)
drwxr-xr-x  2 root root    0 Feb 28 04:05 power
-r--r--r--  1 root root 4096 May 30 08:36 resource
  (memory resources allocated)
-r--r--r--  1 root root 4096 May 30 09:30 subsystem_device
-r--r--r--  1 root root 4096 May 30 09:30 subsystem_vendor
-r--r--r--  1 root root 4096 May 30 08:36 vendor

PCI Interrupts

Addresses Spaces Seen/Implemented by a PCI Device

PCI Configuration Space

Boot Time

PCI Configuration Registers

This slide has additional "handout" notes. You need to use the 'a' key to toggle into handout mode, in order to see them.

PCI register values are always little endian. For portability, you should use the functions and macros in asm/byteorder.h.

Recall that "little endian" means the low-order ("little") byte of the number is stored at the lowest address (and the high-order byte is stored a the highest address). This is in contrast to "big endian". The Intel processor architecture is little-endian. Since PCI is used with more than one processor architecture, a pci I/O device may be used with more than one processor architecture, and so it is desirable that the device driver not depend on any assumptions about the PCI devices and the processor having the same endian-ness.

Generic Kernel Support for PCI Devices

Functions for accessing PCI configuration data

Newer verus older API features

We will look at the newer, more abstract, PCI support functions. If you read the code of older drivers, you will find cases where they drop down to older, lower-level, PCI support functions. It is preferable to use the higher-level interfaces in new drivers.

You will find numerous such instances in Linux, of obsolescent ways of doing things being maintained because no one has the time to bring all of the code up to date with each "improvement" in the kernel internal API.

This makes it risky to learn by imitating just one example. You can examine multiple examples, and look a the authors, to infer which is more likely to be the more up to date style.

If you become a "pro" you will need to follow the kernel developers e-mail group, to know where the kernel is headed.

Kernel pci_device_id Structure

Used to tell kernel about devices a driver supports.

struct pci_device_id {
        __u32 vendor, device;           /* Vendor and device ID or PCI_ANY_ID*/
        __u32 subvendor, subdevice;     /* Subsystem ID's or PCI_ANY_ID */
        __u32 class, class_mask;        /* (class,subclass,prog-if) triplet */
        kernel_ulong_t driver_data;     /* Data private to the driver */
};

Example of a Real PCI Driver

The bttv driver, is the driver for a family of "Brooktree" video input cards.

Registration-Callback Pattern

Provides a way for a dynamically pluggable module to provide services to other system components. Also provides a way to break a circular initialization-order relationship between mutually dependent modules. Example: PCI device registration.

  1. Module registers itself with other subsystem, providing method dispatching vector.
  2. Other subsystem uses dispatching vector to handle events.
  3. If module is removed, it unregisters itself.

This slide has additional "handout" notes. You need to use the 'a' key to toggle into handout mode, in order to see them.

Linux is full of recurring patterns (design and coding). The more you learn to recognize these patterns the more success you will have in reading the code, and the better you will be able to write new code. I wish I had time to point them all out. These are just a few examples.

Auto-Discovery Pattern

Provides a way for a driver to discover devices, which may be plugged and unplugged dynamically. Example: PCI device registrion.

  1. Driver registers itself with bus subsystem, providing a probe function.
  2. Bus subsystem calls the probe function for each device that the driver might support
    • Initially
    • Whenever a new device is plugged in
  3. Probe function is responsible for recognizing devices that can be served, and then registering the devices.

PCI Driver Registration

The bttv module initializer calls pci_register_driver.

ret = pci_register_driver(&bttv_pci_driver);

The parameter to that call is a reference to the struct pci_driver object bttv_pci_driver:

static struct pci_driver bttv_pci_driver = {
    .name     = "bttv",
    .id_table = bttv_pci_tbl,
    .probe    = bttv_probe,
    .remove   = __devexit_p(bttv_remove),
    .suspend  = bttv_suspend,
    .resume   = bttv_resume,
};

The components "suspend" and "resume" are optional. The others are required.

PCI Driver Registration

The id_table component refers to the list of struct pci_device_ide values given in bttv_pci_tbl

static struct pci_device_id bttv_pci_tbl[] = {
    {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,   
     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
    {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849,
     PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878,
        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
       {PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879,
        PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
       {0,}
};

This is an example of an obsolescent style. Linux device drivers are maintained by a horder of different people, who are not able to keep up with all the changes to the kernel API.

PCI Driver Registration

It is better to use the helper macros to build such tables, e.g.

DEFINE_PCI_DEVICE_TABLE(bttv_pci_tbl) = {
   {PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848),
    PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849),
    PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848),
    PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT849),
    PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT878),
    PCI_DEVICE(PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT879),
       {0,}
};

The device id is given by constants like PCI_DEVICE_ID_BT848

#define PCI_DEVICE_ID_BT848     0x350

The vendor id is given by constants like PCI_VENDOR_ID_BROOKTREE

#define PCI_VENDOR_ID_BROOKTREE         0x109e

Probing

The function bttv_probe will be called by the PCI subsystem to probe for all devices whose IDs match an entry in the table bttv_pci_tbl. It will be called when the driver registers, and will be called later if a new card is plugged in.

It returns 0 (success) if the device corresponding to the dev and pci_id parameters is one of the devices that the driver can drive. Otherwise, it returns a negative error code.

If the probe succeeds, it also does whatever per-device initialization is required, including creation of a driver-specific structure btv, and hangs a pointer this driver-specific data on the "hook" of the struct pci_dev object corresponding to dev via a call to pci_set_drvdata.

Accessing Configuration Data

BTTV driver calls generic PCI services to access PCI configuration data in:

This slide has additional "handout" notes. You need to use the 'a' key to toggle into handout mode, in order to see them.

Compare code in MS Windows driver for Pixelsmart frame grabber:

   // Scan for grayscale digis
   pLDI->pciDigis += getPCIBaseAddresses(PCI_PIXELSMART_VENDORID, PCI_PIXELSMART_GRAYDID, &pciData, &BAR0[0], &busNumList[0], &slotNumList[0]);
   // Fill in digiType[]
   setDigiType(&BAR0[0], &dt[0], PCI_DIGI_GRAYSCALE);
   // Scan for color digis
   pLDI->pciDigis += getPCIBaseAddresses(PCI_PIXELSMART_VENDORID, PCI_PIXELSMART_COLORDID, &pciData, &BAR0[0], &busNumList[0], &slotNumList[0]);
   // Fill in digiType[]
   setDigiType(&BAR0[0], &dt[0], PCI_DIGI_COLOR);

Enabling the PCI Device

Removal

The function bttv_remove is called by the PCI subsystem whenever a PCI device is removed. It gives the driver a chance to undo whatever it did in the probe function, including release of any resources allocated for driving that device and removing all references to that device.

static void __devexit bttv_remove(struct pci_dev *pci_dev)
{
...
}

Power Management

If power management is supported, the function bttv_suspend is called by the PCI subsystem whenever the device is suspended

static int bttv_suspend(struct pci_dev *pci_dev, u32 state) { ....  }

And then the function bttv_resume is called by the PCI subsystem whenever the device is resumed

static int bttv_resume(struct pci_dev *pci_dev) { ....
}

De-Registration

The driver module cleanup function calls pci_unregister_driver to undo the driver registration. This will call the remove method specified in the driver registration for all devices that have been successfully probed and which have not previously been removed.

pci_unregister_driver(&bttv_pci_driver);

The remove method is also called in response to hot-plug device removal events.

Examples of Buses

ParallelSerial
  • PCI and variants:
    • PCI-X
    • PCI-E
    • PC104+
  • Microchannel (MCI)
  • VMEbus
  • ISA and variants:
    • EISA
    • VLB
    • PC/104
    • ATA, IDE< EIDE, ATAPI
    • SCSI
  • Infiniband
  • Futurebus
  • USB
  • Firewire
  • SATA
  • SAS
  • I2C
  • PCI-E
  • CAN

ISA ("Industry Standard Architecture")

  • Connects peripherals to motherboard
  • Originally an IBM de facto standard; started the PC industry
  • Advantages: simple, cheap to build
  • Disadvantages
    • slow
    • tightly bound to one architecture
    • device addresses configured by jumpers, prone to unresolvable conflicts

ISA Evolution

ISA Bus Hardware Resources

ISA Driver Chores

Plug-and-Play Specification

PC/104 & PC/104+

  • Allow circuit boards to be stacked vertically
  • Popular for embedded computing systems
  • PC/104 maps to ISA standard
  • PC/104+ maps to PCI standard

MCA