How to find a PCI device in linux kernel module?

Last few days I am reading about PCI system. A part of this, I thought of getting my hand dirty by experimenting with PCI device specific code in linux kernel module. I expect the reader should have some fundamental knowledge about PCI devices and linux kernel module.

Here is a damn simple kernel module developed, whose job is to simply identify the SATA PCI Controller (HBA) which we are looking for. It prints the 64-bit addressing capability of this HBA. Apart from this, this module find the device by class code.

Test System:

Scientific Linux 6.0 (RHEL clone) on VirtualBOX OSE with SATA Controller from Intel (0x8086 is the vendor id) and product id of 0x2829.

I run the following command in test system to identify the above vendor and product ids of this SATA controller.

# lspci -x
………………………………………………..

00:0d.0 SATA controller: Intel Corporation 82801HBM/HEM (ICH8M/ICH8M-E) SATA AHCI Controller (rev 02)

00: 86 80 29 28 07 00 10 00 02 01 06 01 00 40 00 0010: 41 d0 00 00 49 d0 00 00 51 d0 00 00 59 d0 00 0020: 61 d0 00 00 00 60 80 f0 00 00 00 00 00 00 00 0030: 00 00 00 00 70 00 00 00 00 00 00 00 05 01 00 00

I assume you have kernel build environment ready. Here are the two files necessary. One is Makefile and another one is source code of module (aboutpci.c).

aboutpci.c:

#include
<linux/init.h>
#include
<linux/module.h>
#include
<linux/pci.h>

MODULE_LICENSE("Dual BSD/GPL");

#define    OUR_SATA_VENDOR_ID    0x8086
#define    OUR_SATA_PROD_ID    0x2829

static int aboutpci_init(void)
{
    struct pci_dev *dev = NULL;

    //Finding the device by Vendor/Device ID Pair
    dev = pci_get_device(OUR_SATA_VENDOR_ID, OUR_SATA_PROD_ID, dev);
    if (dev != NULL) {
        printk(KERN_ALERT "Our SATA HBA found!\n");
        if ( dev->dma_mask == DMA_BIT_MASK(64) )
            printk(KERN_ALERT "64-bit addressing capable!\n");
        else if ( dev->dma_mask == DMA_BIT_MASK(32) )
            printk(KERN_ALERT "32-bit addressing capable!\n");
    }
    else
        printk(KERN_ALERT "Our SATA HBA Not found!\n");

    //Finding the device by its class code
    dev = NULL;
    dev = pci_get_class(PCI_CLASS_STORAGE_SATA_AHCI, dev);
    if (dev != NULL) {
        printk(KERN_ALERT "SATA HBA Class device found!\n");
        printk(KERN_ALERT "Device Vendor ID: 0x%X\n", dev->vendor);
        printk(KERN_ALERT "Device Product ID: 0x%X\n", dev->device);
    }
    else
        printk(KERN_ALERT "SATA HBA Class device Not found!\n");

    return 0;
}

static void aboutpci_exit(void)
{
    printk(KERN_ALERT "Goodbye, pci hackers\n");
}

module_init(aboutpci_init);
module_exit(aboutpci_exit);

Makefile:

ifneq ($(KERNELRELEASE),)
    obj-m := aboutpci.o
else
    KERNELDIR := /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)
default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif

Reference:

  1. Wikipedia on PCI
  2. Decoding PCI data and lspci output on Linux hosts
  3. PCI Vendor and Device Lists
Share this post

4 comments

    1. struct pci_dev * pci_get_device ( unsigned int vendor,
      unsigned int device,
      struct pci_dev * from);

      Iterates through the list of known PCI devices. If a PCI device is found with a matching vendor and device, the reference count to the device is incremented and a pointer to its device structure is returned. Otherwise, NULL is returned. A new search is initiated by passing NULL as the from argument. Otherwise if from is not NULL, searches continue from next device on the global list. The reference count for from is always decremented if it is not NULL.

      Ref: https://www.kernel.org/doc/htmldocs/kernel-api/API-pci-get-device.html

Leave a Reply

Your email address will not be published. Required fields are marked *