Http://hi.baidu.com/linux_kernel/blog/item/5c8510dfbfdb9b1363279884.html
In order to see the actual running effect, we select the 8139too Nic as an example. Program Cropping Code .
The driver of a PCI device must describe itself to the PCI core in the kernel. At the same time, it must also tell the PCI core which devices can be driven by itself. The following describes two important data structures.
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 */
};
Struct pci_driver {
Struct list_head node;
Char * Name;
Struct module * owner;
Const struct pci_device_id * id_table; // list of device IDs that the driver can manipulate.
INT (* probe) (struct pci_dev * Dev, const struct pci_device_id * ID); // Insert a new device
Void (* remove) (struct pci_dev * Dev); // remove the device.
INT (* suspend) (struct pci_dev * Dev, pm_message_t State );
INT (* resume) (struct pci_dev * Dev );
INT (* enable_wake) (struct pci_dev * Dev, pci_power_t state, int enable );
Void (* shutdown) (struct pci_dev * Dev );
Struct device_driver driver;
Struct pci_dynids dynids;
};
Pci_device_id uniquely identifies a PCI device. Several of its members are represented in sequence: vendor number, device number, sub-vendor number, sub-device Number, category, category mask (class can be divided into base class, subclass), private data. Each driver of a PCI device has an array of pci_device_id, which is used to tell the PCI core which devices can be driven by itself. The 8139too driver defines its pci_device_id array as follows:
Static struct pci_device_id rtl8139_pci_tbl [];
This array is initialized as a set of NICs of the 8139 series. When the PCI core obtains this array, it compares each entry in the array with the data read in the PCI configuration space, to find the right device for the driver. Pci_driver represents a PCI driver. The member id_talbe is the pointer to the pci_device_id array. Name is the name of the driver. Probe completes the probe, that is, compare the pci_device_id array with the data in the kernel. Remove to remove the driver. These are the key members.
The driver registers itself with the kernel through pci_module_init (we sometimes see the pci_register_driver function, which is actually the same. In the kernel code, we can see that it is just a simple # define ):
Pci_module_init (& pci_driver );
After the function is called, if the device identified in the pci_device_id array exists in the system and the device does not have a driver, the driver will be installed. The following shows the PCI device initialization code cropped from the 8139too driver code:
Pci_driver.h:
/* Pci_driver.h
* Helinqiang@hotmail.com
* 2006-3-5
*/
# Ifndef pci_driver_h
# Define pci_driver_h
# Include <Linux/mod_devicetable.h> // For struct pci_device_id
# Include <Linux/module. h> // For module_device_table
# Include <Linux/PCI. h> // For struct pci_driver
# Define drv_name "8139too"
# Define drv_version "0.9.27"
# Define rtl8139_driver_name drv_name "Fast Ethernet driver" drv_version
Typedef Enum {
Rtl8139 = 0,
Rtl8129,
} Board_t;
Static struct pci_device_id rtl8139_pci_tbl [] = {
{0x10ec, 0x8139, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x10ec, 0x8138, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x1113, 0x1211, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x1500, 0x1360, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x4033, 0x1360, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x1186, 0x1300, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x1186, 0x1340, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x13d1, 0xab06, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x1259, 0xa117, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x1259, 0xa11e, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x14ea, 0xab06, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x14ea, 0xab07, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x11db, 0x1234, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x1432, 0x9130, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x02ac, 0x1012, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x018a, 0x0106, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x126c, 0x1211, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x1743, 0x8139, pci_any_id, pci_any_id, 0, 0, rtl8139 },
{0x021b, 0x8139, pci_any_id, pci_any_id, 0, 0, rtl8139 },
# Ifdef config_sh_secureedge5410
/* Bogus 8139 silicon reports 8129 without external prom */
{0x10ec, 0x8129, pci_any_id, pci_any_id, 0, 0, rtl8139 },
# Endif
# Ifdef config_8139too_8129
{0x10ec, 0x8129, pci_any_id, pci_any_id, 0, 0, rtl8129 },
# Endif
/* Some crazy cards Report invalid vendor IDs like
* 0x0001 here. The other IDs are valid and constant,
* So we simply don't match on the main vendor ID.
*/
{Pci_any_id, 0x8139, 0x10ec, 0x8139, 0, 0, rtl8139 },
{Pci_any_id, 0x8139, 0x1186, 0x1300, 0, 0, rtl8139 },
{Pci_any_id, 0x8139, 0x13d1, 0xab06, 0, 0, rtl8139 },
{0 ,}
};
Module_device_table (PCI, rtl8139_pci_tbl );
Static int _ devinit rtl8139_init_one (struct pci_dev * pdev, const struct pci_device_id * ID );
Static void _ devexit rtl8139_remove_one (struct pci_dev * pdev );
Static struct pci_driver rtl8139_pci_driver = {
. Name = drv_name,
. Id_table = rtl8139_pci_tbl,
. Probe = rtl8139_init_one,
. Remove = _ devexit_p (rtl8139_remove_one ),
};
# Endif // pci_driver_h
Pci_driver.c:
/* Pci_driver.c
* Helinqiang@hotmail.com
* 2006-3-5
*/
# Include "pci_driver.h"
# Include <Linux/init. h>
Module_author ("linqiang he, Hangzhou China ");
Module_license ("dual BSD/GPL ");
Static int _ init rtl8139_init_module (void)
{
/* When we're a module, we always print a version message,
* Even if no 8139 board is found.
*/
# Ifdef Module
Printk (kern_info rtl8139_driver_name "\ n ");
# Endif
Return pci_module_init (& rtl8139_pci_driver );
}
Static void _ exit rtl8139_cleanup_module (void)
{
Pci_unregister_driver (& rtl8139_pci_driver );
}
Module_init (rtl8139_init_module );
Module_exit (rtl8139_cleanup_module );
Int _ devinit rtl8139_init_one (struct pci_dev * pdev, const struct pci_device_id * ID)
{
// Various debugging codes can be inserted here, which will be described in detail below.
Return 0;
}
Void _ devexit rtl8139_remove_one (struct pci_dev * pdev)
{
}
After the driver is successfully registered, rtl8139_init_one will be called. In this function, We can insert some print output statements to see the configuration address space and I/O address areas of PCI.
First, insert the following statement:
2010vendor, device;
Pci_read_config_word (pdev, 0, & vendor );
Pci_read_config_word (pdev, 2, & device );
Printk (kern_info "% x, % x \ n", vendor, device );
This Code reads the first four digits of the IP address space configured for the NIC device, which is the vendor ID and device ID of the device. The output is as follows:
Mar 9 21:44:39 localhost kernel: 10ec, 8139
10ec and 8139 are the vendor and device numbers of my network card.
Insert the following code:
U32 addr1, addr2, addr3, addr4, addr5, addr6;
Pci_read_config_dword (pdev, 16, & addr1 );
Pci_read_config_dword (pdev, 20, & addr2 );
Pci_read_config_dword (pdev, 24, & addr3 );
Pci_read_config_dword (pdev, 28, & addr4 );
Pci_read_config_dword (pdev, 32, & addr5 );
Pci_read_config_dword (pdev, 36, & addr6 );
Printk (kern_info "% x, % x \ n", addr1, addr2, addr3, addr4, addr5, addr6 );
This Code reads the starting location of the six I/O address areas of the NIC device. The output is as follows:
Mar 9 21:55:06 localhost kernel: 3401, e0000800
It can be seen that the device only uses the first two I/O address areas, respectively, to identify its I/O port areas and memory address space.
In addition, the MAC address of the NIC can be printed directly. Not detailed.