网卡收包
在下水平相当有限,有不当之处,还请大家斧正^_^
驱动的初始化如下的rtl8169_init_module函数是此驱动的初始化代码,此函数只干了一件事,就是向内核注册一个pci驱动rtl8169_pci_driver。
static int __init rtl8169_init_module(void)
{
returnpci_register_driver(&rtl8169_pci_driver);
}
rtl8169_pci_driver驱动的定义如下。
static struct pci_driver rtl8169_pci_driver= {
.name = MODULENAME,
.id_table = rtl8169_pci_tbl,
.probe = rtl8169_init_one,
.remove = __devexit_p(rtl8169_remove_one),
.shutdown = rtl_shutdown,
.driver.pm = RTL8169_PM_OPS,
};
.id_table成员是一个驱动程序支持的全部设备列表。对于rtl8169_pci_driver,id_tabl就是b rtl8169_pci_tbl了,其内容如下。可见此驱动支持多种不同型号的网卡芯片。
static struct pci_device_idrtl8169_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129),0, 0, RTL_CFG_0 },
{PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136),0, 0, RTL_CFG_2 },
{PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167),0, 0, RTL_CFG_0 },
{PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168),0, 0, RTL_CFG_1 },
{PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169),0, 0, RTL_CFG_0 },
{PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300),0, 0, RTL_CFG_0 },
{PCI_DEVICE(PCI_VENDOR_ID_AT, 0xc107),0, 0, RTL_CFG_0 },
{PCI_DEVICE(0x16ec, 0x0116),0, 0, RTL_CFG_0 },
{PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
{0x0001, 0x8168, PCI_ANY_ID, 0x2410, 0, 0, RTL_CFG_2 },
{0,},
};
需要注意到,驱动中还有如下一行代码。
MODULE_DEVICE_TABLE(pci, rtl8169_pci_tbl);
这个宏貌似是给rtl8169_pci_tbl变量起了一个别名__mod_pci_device_table。可见__mod_pci_device_table是pci设备驱动中的一个统一的符号名。他包含了此驱动支持的全部设备的列表。
这是干什么的呢?这时解释一下。
如果此驱动被编译到了内核中,或者此驱动已经被加载到内核中。那么这一句话就没什么作用了。因为内核随时可以根据rtl8169_pci_driver中的信息,来判断某一设备是否匹配此驱动。代码见pci_match_device函数。
但是,如果此驱动被编译成了一个模块文件r8169.ko,并且没有被加载到内核中(正常情况下,大量的设备驱动都应该是被编译成模块的,并且都是不加载到内核中的。机器上电时,根据扫描到的设备,动态加载相应的驱动模块。不然的话,如果各种驱动都加载到内核中,那内核就太臃肿了)。此时,如果内核扫描到了一个pci设备,就得加载相应的驱动模块文件。但内核只掌握了此设备的类似Vendorand device ID这样的信息,如何将这种信息对应到具体的驱动模块文件r8169.ko呢。这时候MODULE_DEVICE_TABLE这句话就发挥作用了。具体细节,可以参考udev与modprobe等相关知识。
这里顺便多说两句,当一个pci驱动被加载到内核中时(见调用链pci_register_driver ->__pci_register_driver -> driver_register ->bus_add_driver ->driver_attach),或者当内核发现一个新设备时(见调用链device_add->bus_probe_device->device_attach),都会做一次驱动与设备的匹配操作。
probe一块网卡rtl8169_init_one当某一块网卡匹配了rtl8169_pci_driver时,rtl8169_pci_driver. probe函数(即rtl8169_init_one)即被调用,此函数针对此网卡做一些初始化操作,然后此网卡就可用了。
这里顺便说一下,一个设备,如何与业务流程关联起来。不同的设备,,可能是不一样的。
例如,有些设备(如看门狗设备,块设备),是在文件系统中创建一个文件(如/dev/ watchdog)。业务通过打开设备文件,操作/读/写设备文件,就将设备用起来了。
而网卡设备,则不是这样。网卡设备是向内核注册一个struct net_device结构。注册以后,ifconfig命令就能看到此网卡了。内核协议栈及路由系统也就与此net_device结构关联起来了。struct net_device结构,是内核对网络设备的一种抽象,他使得内核可以用统一的方式操作一切网络设备。
下面看看rtl8169_init_one的主要任务:
l 将网卡配置寄存器区间映射到内核虚存空间
l 执行硬件初始化
l 构建一个net_device结构,注册到内核中
温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/71384.html