在linux系统中,其网卡驱动大多通过PCI总线与系统相连,同时,内核对于所有PCI总线上的设备是通过PCI子系统来进行管理,通过PCI子系统提供各种PCI设备驱动程序共同的所有通用功能。因此,作为linux系统中的PCI网卡设备,其加载的流程必然分为两个部分:作为PCI设备向PCI子系统注册;作为网卡设备向网络子系统注册。
下面也将从两个方面,分析一下网卡驱动在内核加载的两个流程。
PCI设备驱动程序的注册:
PCI设备驱动程序使用pci_register_driver函数完成内核的注册,其定义在include/linux/pci.h文件内
/*
* pci_register_driver must be a macro so that KBUILD_MODNAME can be expanded
*/
#define pci_register_driver(driver) \
__pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
其主要结构是名为driver的pci_driver结构体,
struct pci_driver {
struct list_head node;
const char *name;
/* 驱动所关联的PCI设备 */
const struct pci_device_id *id_table; /* must be non-NULL for probe to be called */
int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */
void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */
int (*suspend_late) (struct pci_dev *dev, pm_message_t state);
int (*resume_early) (struct pci_dev *dev);
int (*resume) (struct pci_dev *dev); /* Device woken up */
void (*shutdown) (struct pci_dev *dev);
struct pci_error_handlers *err_handler;
struct device_driver driver;
struct pci_dynids dynids;
};
在pri_driver结构体中有两个比较关键的函数,分别是struct pci_device_id *id_table、以及probe函数。其中id_table是一个id向量表,内核通过其来把一些相关的设备关联到此驱动程序,PCI设备独一无二的识别方式是通过一些参数的组合,包含开发商以及模型等,这些参数都存储在内核的pci_device_id数据结构中:
struct pci_device_id {
__u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/
__u32 subvendor, subdevice; /* Subsystem ID's