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.cpci_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_OpsCFG80211_Opscfg80211_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 */};
0 0
原创粉丝点击