git出源码:
https://github.com/wuqiong/rt2860v2-for-openwrt-mt7620
再rt2860v2中搜索字符串__init
, 找到驱动模块的入口函数:
os/linux/rbus_main_dev.c:37:int __init rt2880_module_init(VOID);
os/linux/pci_main_dev.c:46:static int __init rt2860_init_module(void);
os/linux/pci_main_dev.c:276:static INT __init rt2860_init_module(VOID)
查看rbus_main_dev.c
和pci_main_dev.c
文件,可以发现rt2860v2驱动在pci_main_dev.c
中进行了pci设备模块初始化,在rbus_main_dev.c
中是网络设备模块初始化。
pci_main_dev.c
中分析rt2860v2驱动程序的pci设备模块初始化:
static INT __init rt2860_init_module(VOID)
{
DBGPRINT(RT_DEBUG_ERROR, ("register %s\n", RTMP_DRV_NAME));
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
return pci_register_driver(&rt2860_driver);
#else
return pci_module_init(&rt2860_driver);
#endif
}
/* */
/* Driver module unload function */
/* */
static VOID __exit rt2860_cleanup_module(VOID)
{
pci_unregister_driver(&rt2860_driver);
}
module_init(rt2860_init_module);
module_exit(rt2860_cleanup_module);
在__init
中,pci_register_driver
进行了pci设备注册,rt2860v2驱动模块挂载在pci总线上。
/* */
/* Our PCI driver structure */
/* */
static struct pci_driver rt2860_driver =
{
name: RTMP_DRV_NAME,
id_table: rt2860_pci_tbl,
probe: rt2860_probe,
#if LINUX_VERSION_CODE >= 0x20412
remove: __devexit_p(rt2860_remove_one),
#else
remove: __devexit(rt2860_remove_one),
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#ifdef CONFIG_PM
suspend: rt2860_suspend,
resume: rt2860_resume,
#endif
#endif
};
PCI设备驱动结构,填充结构体
- name :
RTMP_DRV_NAME
就是rt2860 - id_talbe :pci设备表,指明该驱动适合那些设备
- probe :检测驱动设备
- remove:卸载驱动设备
- suspend:挂起设备使之处于节能状态
- resume:唤醒处于挂起态的设备
从id_table
中,驱动将选择对应的硬件设备,用此id来识别硬件信息:
/* */
/* Ralink PCI device table, include all supported chipsets */
/* */
static struct pci_device_id rt2860_pci_tbl[] __devinitdata =
{
#ifdef RT2860
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2860_PCI_DEVICE_ID)}, /*RT28602.4G */
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2860_PCIe_DEVICE_ID)},
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2760_PCI_DEVICE_ID)},
{PCI_DEVICE(NIC_PCI_VENDOR_ID, NIC2790_PCIe_DEVICE_ID)},
{PCI_DEVICE(VEN_AWT_PCI_VENDOR_ID, VEN_AWT_PCIe_DEVICE_ID)},
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7708)},
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7728)},
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7758)},
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7727)},
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7738)},
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7748)},
{PCI_DEVICE(EDIMAX_PCI_VENDOR_ID, 0x7768)},
#endif /* RT2860 */
{0,} /* terminate list */
};
分析pci设备的probe函数,即rt2860v2_probe
,该函数内容如下:
/* */
/* PCI device probe & initialization function */
/* */
static INT __devinit rt2860_probe(
IN struct pci_dev *pci_dev,
IN const struct pci_device_id *pci_id)
{
VOID *pAd = NULL;
struct net_device *net_dev;
PVOID handle;
PSTRING print_name;
ULONG csr_addr;
INT rv = 0;
RTMP_OS_NETDEV_OP_HOOK netDevHook;
ULONG OpMode;
DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_probe\n"));
/*PCIDevInit============================================== */
/* wake up and enable device */
if ((rv = pci_enable_device(pci_dev))!= 0)//使能pci设备
{
DBGPRINT(RT_DEBUG_ERROR, ("Enable PCI device failed, errno=%d!\n", rv));
return rv;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
print_name = pci_name(pci_dev);
#else
print_name = pci_dev->slot_name;
#endif /* LINUX_VERSION_CODE */
if ((rv = pci_request_regions(pci_dev, print_name)) != 0)//申请PCI的resource
{
DBGPRINT(RT_DEBUG_ERROR, ("Request PCI resource failed, errno=%d!\n", rv));
goto err_out;
}
/* map physical address to virtual address for accessing register */