rt2860v2源码分析一
来源:互联网 发布:易到用车客户端软件 编辑:程序博客网 时间:2024/05/08 14:34
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 */ csr_addr = (unsigned long) ioremap(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); if (!csr_addr) { DBGPRINT(RT_DEBUG_ERROR, ("ioremap failed for device %s, region 0x%lX @ 0x%lX\n", print_name, (ULONG)pci_resource_len(pci_dev, 0), (ULONG)pci_resource_start(pci_dev, 0))); goto err_out_free_res; } else { DBGPRINT(RT_DEBUG_TRACE, ("%s: at 0x%lx, VA 0x%lx, IRQ %d. \n", print_name, (ULONG)pci_resource_start(pci_dev, 0), (ULONG)csr_addr, pci_dev->irq)); } /* Set DMA master */ pci_set_master(pci_dev);/*RtmpDevInit============================================== */ /* Allocate RTMP_ADAPTER adapter structure *//* handle = kmalloc(sizeof(struct os_cookie), GFP_KERNEL); */ os_alloc_mem(NULL, (UCHAR **)&handle, sizeof(struct os_cookie)); if (handle == NULL) { DBGPRINT(RT_DEBUG_ERROR, ("%s(): Allocate memory for os handle failed!\n", __FUNCTION__)); goto err_out_iounmap; } memset(handle, 0, sizeof(struct os_cookie)); ((POS_COOKIE)handle)->pci_dev = pci_dev;#ifdef OS_ABL_FUNC_SUPPORT{ RTMP_PCI_CONFIG PciConfig; PciConfig.ConfigVendorID = PCI_VENDOR_ID; /* get DRIVER operations */ RTMP_DRV_OPS_FUNCTION(pRtmpDrvOps, NULL, &PciConfig, NULL);}#endif /* OS_ABL_FUNC_SUPPORT */ rv = RTMPAllocAdapterBlock(handle, &pAd); /* we may need the pci_dev for allocate structure of "RTMP_ADAPTER" */ if (rv != NDIS_STATUS_SUCCESS) goto err_out_iounmap; /* Here are the RTMP_ADAPTER structure with pci-bus specific parameters. *//* pAd->CSRBaseAddress = (PUCHAR)csr_addr; */ RTMP_DRIVER_PCI_CSR_SET(pAd, csr_addr);/* RTMPInitPCIeDevice(pci_dev, pAd); */ RTMP_DRIVER_PCIE_INIT(pAd, pci_dev);/*NetDevInit============================================== */ net_dev = RtmpPhyNetDevInit(pAd, &netDevHook);//网络设备的初始化 if (net_dev == NULL) goto err_out_free_radev; /* Here are the net_device structure with pci-bus specific parameters. */ net_dev->irq = pci_dev->irq; /* Interrupt IRQ number */ net_dev->base_addr = csr_addr; /* Save CSR virtual address and irq to device structure */ pci_set_drvdata(pci_dev, net_dev); /* Set driver data */#ifdef NATIVE_WPA_SUPPLICANT_SUPPORT/* for supporting Network Manager */ /* Set the sysfs physical device reference for the network logical device * if set prior to registration will cause a symlink during initialization. */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) SET_NETDEV_DEV(net_dev, &(pci_dev->dev));#endif#endif /* NATIVE_WPA_SUPPLICANT_SUPPORT *//*All done, it's time to register the net device to linux kernel. */ /* Register this device */#ifdef RT_CFG80211_SUPPORT{/* pAd->pCfgDev = &(pci_dev->dev); *//* pAd->CFG80211_Register = CFG80211_Register; *//* RTMP_DRIVER_CFG80211_INIT(pAd, pci_dev); */ /* In 2.6.32, cfg80211 register must be before register_netdevice(); We can not put the register in rt28xx_open(); Or you will suffer NULL pointer in list_add of cfg80211_netdev_notifier_call(). */ CFG80211_Register(pAd, &(pci_dev->dev), net_dev);//cfg80211提供的无线网络注册接口}#endif /* RT_CFG80211_SUPPORT */ RTMP_DRIVER_OP_MODE_GET(pAd, &OpMode); rv = RtmpOSNetDevAttach(OpMode, net_dev, &netDevHook); if (rv) goto err_out_free_netdev;#ifdef CONFIG_STA_SUPPORT //配置为sta模式/* pAd->StaCfg.OriDevType = net_dev->type; */ RTMP_DRIVER_STA_DEV_TYPE_SET(pAd, net_dev->type);#endif /* CONFIG_STA_SUPPORT *//*#ifdef KTHREAD_SUPPORT */#ifdef PRE_ASSIGN_MAC_ADDR //设置固定的mac地址 UCHAR PermanentAddress[MAC_ADDR_LEN]; RTMP_DRIVER_MAC_ADDR_GET(pAd, &PermanentAddress[0]); DBGPRINT(RT_DEBUG_TRACE, ("@%s MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, PermanentAddress[0], PermanentAddress[1],PermanentAddress[2],PermanentAddress[3],PermanentAddress[4],PermanentAddress[5])); /* Set up the Mac address */ RtmpOSNetDevAddrSet(OpMode, net_dev, &PermanentAddress[0], NULL);#endif /* PRE_ASSIGN_MAC_ADDR */ DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_probe\n")); return 0; /* probe ok */ /* --------------------------- ERROR HANDLE --------------------------- */err_out_free_netdev: RtmpOSNetDevFree(net_dev);err_out_free_radev: /* free RTMP_ADAPTER strcuture and os_cookie*/ RTMPFreeAdapter(pAd);err_out_iounmap: iounmap((void *)(csr_addr)); release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); err_out_free_res: pci_release_regions(pci_dev);err_out: pci_disable_device(pci_dev); DBGPRINT(RT_DEBUG_ERROR, ("<=== rt2860_probe failed with rv = %d!\n", rv)); return -ENODEV; /* probe fail */}
其中重要的部分是 RTMPAllocAdapterBlock
函数,该函数分配网络设备。 RtmpPhyNetDevInit
函数,该函数实现了驱动底层设备的初始化。 CFG80211_Register
函数是kernel中cfg80211的无线网络设备的注册接口。 RtmpOSNetDevAttach
函数,该函数实现了网络设备的创建。 RtmpOSNetDevAddrSet
函数,该函数设置了网络设备的固定mac地址。
其中CFG80211_Register
函数,是无线无线网络的设备的初始化和接口注册,内容如下:
/*========================================================================Routine Description: Register MAC80211 Module.Arguments: pAdCB - WLAN control block pointer pDev - Generic device interface pNetDev - Network deviceReturn Value: NONENote: pDev != pNetDev #define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev)) Can not use pNetDev to replace pDev; Or kernel panic.========================================================================*/BOOLEAN CFG80211_Register( IN VOID *pAd, IN struct device *pDev, IN struct net_device *pNetDev){ CFG80211_CB *pCfg80211_CB = NULL; CFG80211_BAND BandInfo; /* allocate MAC80211 structure */ os_alloc_mem(NULL, (UCHAR **)&pCfg80211_CB, sizeof(CFG80211_CB)); if (pCfg80211_CB == NULL) { DBGPRINT(RT_DEBUG_ERROR, ("80211> Allocate MAC80211 CB fail!\n")); return FALSE; } /* End of if */ /* allocate wireless device */ RTMP_DRIVER_80211_BANDINFO_GET(pAd, &BandInfo); pCfg80211_CB->pCfg80211_Wdev = \ CFG80211_WdevAlloc(pCfg80211_CB, &BandInfo, pAd, pDev); if (pCfg80211_CB->pCfg80211_Wdev == NULL) { DBGPRINT(RT_DEBUG_ERROR, ("80211> Allocate Wdev fail!\n")); os_free_mem(NULL, pCfg80211_CB); return FALSE; } /* End of if */ /* bind wireless device with net device */#ifdef CONFIG_AP_SUPPORT /* default we are AP mode */ pCfg80211_CB->pCfg80211_Wdev->iftype = NL80211_IFTYPE_AP;#endif /* CONFIG_AP_SUPPORT */#ifdef CONFIG_STA_SUPPORT /* default we are station mode */ pCfg80211_CB->pCfg80211_Wdev->iftype = NL80211_IFTYPE_STATION;#endif /* CONFIG_STA_SUPPORT */ pNetDev->ieee80211_ptr = pCfg80211_CB->pCfg80211_Wdev; SET_NETDEV_DEV(pNetDev, wiphy_dev(pCfg80211_CB->pCfg80211_Wdev->wiphy)); pCfg80211_CB->pCfg80211_Wdev->netdev = pNetDev;#ifdef RFKILL_HW_SUPPORT wiphy_rfkill_start_polling(pCfg80211_CB->pCfg80211_Wdev->wiphy);#endif /* RFKILL_HW_SUPPORT */ RTMP_DRIVER_80211_CB_SET(pAd, pCfg80211_CB); CFG80211DBG(RT_DEBUG_ERROR, ("80211> CFG80211_Register\n")); return TRUE;} /* End of CFG80211_Register */
其中重要的内容: CFG80211_RegNotifier
函数是驱动网络调度的通知回调函数。 CFG80211_SupBandInit
函数初始了无线设备的chinnel CFG80211_WdevAlloc
函数实习了无线网络wiphy的分配和注册。
/*========================================================================Routine Description: Allocate a wireless device.Arguments: pAd - WLAN control block pointer pDev - Generic device interfaceReturn Value: wireless device========================================================================*/static struct wireless_dev *CFG80211_WdevAlloc( IN CFG80211_CB *pCfg80211_CB, IN CFG80211_BAND *pBandInfo, IN VOID *pAd, IN struct device *pDev){ struct wireless_dev *pWdev; ULONG *pPriv; /* * We're trying to have the following memory layout: * * +------------------------+ * | struct wiphy | * +------------------------+ * | pAd pointer | * +------------------------+ */ pWdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (pWdev == NULL) { DBGPRINT(RT_DEBUG_ERROR, ("80211> Wireless device allocation fail!\n")); return NULL; } /* End of if */ pWdev->wiphy = wiphy_new(&CFG80211_Ops, sizeof(ULONG *)); if (pWdev->wiphy == NULL) { DBGPRINT(RT_DEBUG_ERROR, ("80211> Wiphy device allocation fail!\n")); goto LabelErrWiphyNew; } /* End of if */ /* keep pAd pointer */ pPriv = (ULONG *)(wiphy_priv(pWdev->wiphy)); *pPriv = (ULONG)pAd; set_wiphy_dev(pWdev->wiphy, pDev);#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) pWdev->wiphy->max_scan_ssids = pBandInfo->MaxBssTable;#endif /* KERNEL_VERSION */#ifdef CONFIG_AP_SUPPORT pWdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_AP);#ifdef WDS_SUPPORT pWdev->wiphy->interface_modes | = BIT(NL80211_IFTYPE_WDS);#endif /* WDS_SUPPORT */#endif /* CONFIG_STA_SUPPORT */#ifdef CONFIG_STA_SUPPORT pWdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR);#endif /* CONFIG_STA_SUPPORT */ pWdev->wiphy->reg_notifier = CFG80211_RegNotifier; /* init channel information */ CFG80211_SupBandInit(pCfg80211_CB, pBandInfo, pWdev->wiphy, NULL, NULL);#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) /* CFG80211_SIGNAL_TYPE_MBM: signal strength in mBm (100*dBm) */ pWdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;#endif /* KERNEL_VERSION */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)) pWdev->wiphy->cipher_suites = CipherSuites; pWdev->wiphy->n_cipher_suites = ARRAY_SIZE(CipherSuites);#endif /* LINUX_VERSION_CODE */ if (wiphy_register(pWdev->wiphy) < 0) { DBGPRINT(RT_DEBUG_ERROR, ("80211> Register wiphy device fail!\n")); goto LabelErrReg; } /* End of if */ return pWdev; LabelErrReg: wiphy_free(pWdev->wiphy); LabelErrWiphyNew: os_free_mem(NULL, pWdev); return NULL;} /* End of CFG80211_WdevAlloc */
其中wiphy_new
函数分配了wiphy并关联了CFG80211_Ops
,CFG80211_Ops
是cfg80211_ops
结构体,是对无线设备接口的操作结构体。 wiphy_register
函数注册了无线设备的wiphy,建立无线网络设备接口。
CFG80211_Ops
cfg80211提供的无线网络设备操作结构体,在rt2860v2的定义如下:
struct cfg80211_ops CFG80211_Ops = { /* set channel for a given wireless interface */ .set_channel = CFG80211_OpsChannelSet, /* change type/configuration of virtual interface */ .change_virtual_intf = CFG80211_OpsVirtualInfChg,#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) /* request to do a scan */ /* Note: must exist whatever AP or STA mode; Or your kernel will crash in v2.6.38. */ .scan = CFG80211_OpsScan,#endif /* LINUX_VERSION_CODE */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31))#ifdef CONFIG_STA_SUPPORT /* join the specified IBSS (or create if necessary) */ .join_ibss = CFG80211_OpsIbssJoin, /* leave the IBSS */ .leave_ibss = CFG80211_OpsIbssLeave,#endif /* CONFIG_STA_SUPPORT */#endif /* LINUX_VERSION_CODE */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)) /* set the transmit power according to the parameters */ .set_tx_power = CFG80211_OpsTxPwrSet, /* store the current TX power into the dbm variable */ .get_tx_power = CFG80211_OpsTxPwrGet, /* configure WLAN power management */ .set_power_mgmt = CFG80211_OpsPwrMgmt, /* get station information for the station identified by @mac */ .get_station = CFG80211_OpsStaGet, /* dump station callback */ .dump_station = CFG80211_OpsStaDump, /* notify that wiphy parameters have changed */ .set_wiphy_params = CFG80211_OpsWiphyParamsSet, /* add a key with the given parameters */ .add_key = CFG80211_OpsKeyAdd, /* get information about the key with the given parameters */ .get_key = CFG80211_OpsKeyGet, /* remove a key given the @mac_addr */ .del_key = CFG80211_OpsKeyDel, /* set the default key on an interface */ .set_default_key = CFG80211_OpsKeyDefaultSet,#ifdef CONFIG_STA_SUPPORT /* connect to the ESS with the specified parameters */ .connect = CFG80211_OpsConnect, /* disconnect from the BSS/ESS */ .disconnect = CFG80211_OpsDisconnect,#endif /* CONFIG_STA_SUPPORT */#endif /* LINUX_VERSION_CODE */#ifdef RFKILL_HW_SUPPORT /* polls the hw rfkill line */ .rfkill_poll = CFG80211_OpsRFKill,#endif /* RFKILL_HW_SUPPORT */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33)) /* get site survey information */ .dump_survey = CFG80211_OpsSurveyGet, /* cache a PMKID for a BSSID */ .set_pmksa = CFG80211_OpsPmksaSet, /* delete a cached PMKID */ .del_pmksa = CFG80211_OpsPmksaDel, /* flush all cached PMKIDs */ .flush_pmksa = CFG80211_OpsPmksaFlush,#endif /* LINUX_VERSION_CODE */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34)) /* Request the driver to remain awake on the specified channel for the specified duration to complete an off-channel operation (e.g., public action frame exchange). */ .remain_on_channel = NULL, /* cancel an on-going remain-on-channel operation */ .cancel_remain_on_channel = NULL,#if (LINUX_VERSION_CODE == KERNEL_VERSION(2,6,34)) /* transmit an action frame */ .action = NULL,#endif /* LINUX_VERSION_CODE */#endif /* LINUX_VERSION_CODE */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)) /* configure connection quality monitor RSSI threshold */ .set_cqm_rssi_config = NULL,#endif /* LINUX_VERSION_CODE */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)) /* notify driver that a management frame type was registered */ .mgmt_frame_register = NULL,#endif /* LINUX_VERSION_CODE */#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) /* set antenna configuration (tx_ant, rx_ant) on the device */ .set_antenna = NULL, /* get current antenna configuration from device (tx_ant, rx_ant) */ .get_antenna = NULL,#endif /* LINUX_VERSION_CODE */};
- rt2860v2源码分析一
- rt2860v2源码分析三
- rt2860v2源码解析四
- quake2源码分析(一)
- Tomcat源码分析(一)
- Lua 源码分析(一)
- Jquery源码分析(一)
- 源码分析(一)
- KUIX源码分析一
- Logcat源码分析(一)
- gSOAP 源码分析(一)
- asihttp 源码分析一
- shopqi源码分析(一)
- VLC源码分析(一)
- pomelo源码分析(一)
- Struts2源码分析一
- tomcat源码分析[一]
- gSOAP 源码分析(一)
- 在某域名下搭建网站
- 使用Neo4j进行全栈Web开发
- 概念笔记之[javascript<-1->]函数思想
- CountDowmLatch解析
- wifi绵羊墙搭建
- rt2860v2源码分析一
- Qualcomm’s Connectivity Engine (CnE)
- APFS 强在哪里?
- javascript清除浏览器缓存的几种方法
- vs2010编译 时 char* 类型形参与LPWSTR 类型的实参不兼容 的解决办法
- iOS 正则表达式的简单使用介绍
- Wikioi 1222 信与信封问题(二分图匹配)
- hjr教程-JavaScript(一):js面向对象
- c语言初学-- 反序数 对称数