qcacld-2.0的wlan分析之二

来源:互联网 发布:java内存溢出 编辑:程序博客网 时间:2024/05/22 04:59

在设备进行pci总线注册之后,进入pci驱动的probe函数,该函数中最为重要的就是开启wlan的主机设备驱动,即hdd_wlan_startup()函数:

/**---------------------------------------------------------------------------  \brief hdd_wlan_startup() - HDD init function  This is the driver startup code executed once a WLAN device has been detected  \param  - dev - Pointer to the underlying device  \return -  0 for success, < 0 for failure  --------------------------------------------------------------------------*/int hdd_wlan_startup(struct device *dev, v_VOID_t *hif_sc){   VOS_STATUS status;   hdd_adapter_t *pAdapter = NULL;#ifdef WLAN_OPEN_P2P_INTERFACE   hdd_adapter_t *pP2pAdapter = NULL;#endif   hdd_context_t *pHddCtx = NULL;   v_CONTEXT_t pVosContext= NULL;#ifdef WLAN_BTAMP_FEATURE   VOS_STATUS vStatus = VOS_STATUS_SUCCESS;   WLANBAP_ConfigType btAmpConfig;   hdd_config_t *pConfig;#endif   eHalStatus hal_status;   int ret;   int i;   struct wiphy *wiphy;   unsigned long rc;   tSmeThermalParams thermalParam;   tSirTxPowerLimit *hddtxlimit;#ifdef FEATURE_WLAN_CH_AVOID   int unsafeChannelIndex;#endif   ENTER();.......pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_INFRA_STATION, "wlan%d",       wlan_hdd_get_intf_addr(pHddCtx), FALSE );......success:   EXIT();   return 0;}

该函数初始化内容繁多,主要集中的有两部分,一个是vos_open 打开开虚拟接口,另外是hdd_open_adapter 函数,提供了网络接口并建立了无线网络适配器。

hdd_wlan_startup 中通过wlan_hdd_cfg80211_wiphy_alloc 为无线设备分配一个wiphy结构体,再通过hdd_open_adapter 函数中hdd_register_interface 实现无线网络设备注册,

/* * FUNCTION: wlan_hdd_cfg80211_wiphy_alloc * This function is called by hdd_wlan_startup() * during initialization. * This function is used to allocate wiphy structure. */struct wiphy *wlan_hdd_cfg80211_wiphy_alloc(int priv_size){    struct wiphy *wiphy;    ENTER();    /*     *   Create wiphy device     */    wiphy = wiphy_new(&wlan_hdd_cfg80211_ops, priv_size);    if (!wiphy)    {        /* Print error and jump into err label and free the memory */        hddLog(VOS_TRACE_LEVEL_ERROR, "%s: wiphy init failed", __func__);        return NULL;    }    return wiphy;}

在分配新的wiphy时,关联了wlan_hdd_cfg80211_ops 结构体,该结构体是cfg80211提供的操作结构体,即struct cfg80211_ops

hdd_adapter_t* hdd_open_adapter( hdd_context_t *pHddCtx, tANI_U8 session_type,                                 const char *iface_name, tSirMacAddr macAddr,                                 tANI_U8 rtnl_held ){   hdd_adapter_t *pAdapter = NULL;   hdd_adapter_list_node_t *pHddAdapterNode = NULL;   VOS_STATUS status = VOS_STATUS_E_FAILURE;   VOS_STATUS exitbmpsStatus = VOS_STATUS_E_FAILURE;   hdd_cfg80211_state_t *cfgState;   int ret;   hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "%s: iface =%s type = %d\n", __func__,                                      iface_name, session_type);   if (pHddCtx->current_intf_count >= pHddCtx->max_intf_count){        /* Max limit reached on the number of vdevs configured by the host.         *  Return error         */        VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,                 "%s: Unable to add virtual intf: currentVdevCnt=%d,hostConfiguredVdevCnt=%d",                 __func__,pHddCtx->current_intf_count, pHddCtx->max_intf_count);        return NULL;   }   if(macAddr == NULL)   {         /* Not received valid macAddr */         VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,                 "%s:Unable to add virtual intf: Not able to get"                             "valid mac address",__func__);         return NULL;   }   status = hdd_check_for_existing_macaddr(pHddCtx, macAddr);   if (VOS_STATUS_E_FAILURE == status) {         VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,                   "%s: Duplicate MAC addr: "MAC_ADDRESS_STR" already exists",                   __func__, MAC_ADDR_ARRAY(macAddr));         return NULL;   }   /*    * If Powersave Offload is enabled    * Fw will take care incase of concurrency    */   if(!pHddCtx->cfg_ini->enablePowersaveOffload)   {      //Disable BMPS incase of Concurrency      exitbmpsStatus = hdd_disable_bmps_imps(pHddCtx, session_type);      if(VOS_STATUS_E_FAILURE == exitbmpsStatus)      {         //Fail to Exit BMPS         hddLog(VOS_TRACE_LEVEL_ERROR, FL("Fail to Exit BMPS"));         VOS_ASSERT(0);         return NULL;      }   }   switch(session_type)   {      case WLAN_HDD_INFRA_STATION:         /* Reset locally administered bit if the device mode is STA */         WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macAddr);         /* fall through */      case WLAN_HDD_P2P_CLIENT:      case WLAN_HDD_P2P_DEVICE:      {         pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );         if( NULL == pAdapter )         {            hddLog(VOS_TRACE_LEVEL_FATAL,                   FL("failed to allocate adapter for session %d"), session_type);            return NULL;          }         if (session_type == WLAN_HDD_INFRA_STATION)            pAdapter->wdev.iftype = NL80211_IFTYPE_STATION;         else if (session_type == WLAN_HDD_P2P_DEVICE)            pAdapter->wdev.iftype = NL80211_IFTYPE_P2P_DEVICE;         else            pAdapter->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT;         pAdapter->device_mode = session_type;         status = hdd_init_station_mode( pAdapter );         if( VOS_STATUS_SUCCESS != status )            goto err_free_netdev;         status = hdd_register_interface( pAdapter, rtnl_held );         if( VOS_STATUS_SUCCESS != status )         {            hdd_deinit_adapter(pHddCtx, pAdapter, rtnl_held);            goto err_free_netdev;         }         // Workqueue which gets scheduled in IPv4 notification callback#ifdef CONFIG_CNSS         cnss_init_work(&pAdapter->ipv4NotifierWorkQueue,                        hdd_ipv4_notifier_work_queue);#else         INIT_WORK(&pAdapter->ipv4NotifierWorkQueue,                   hdd_ipv4_notifier_work_queue);#endif#ifdef WLAN_NS_OFFLOAD         // Workqueue which gets scheduled in IPv6 notification callback.#ifdef CONFIG_CNSS         cnss_init_work(&pAdapter->ipv6NotifierWorkQueue,                        hdd_ipv6_notifier_work_queue);#else         INIT_WORK(&pAdapter->ipv6NotifierWorkQueue,                   hdd_ipv6_notifier_work_queue);#endif#endif         //Stop the Interface TX queue.         netif_tx_disable(pAdapter->dev);         //netif_tx_disable(pWlanDev);         netif_carrier_off(pAdapter->dev);#ifdef QCA_LL_TX_FLOW_CT         /* SAT mode default TX Flow control instance          * This instance will be used for          * STA mode, IBSS mode and TDLS mode */         if (pAdapter->tx_flow_timer_initialized == VOS_FALSE) {            vos_timer_init(&pAdapter->tx_flow_control_timer,                           VOS_TIMER_TYPE_SW,                           hdd_tx_resume_timer_expired_handler,                           pAdapter);            pAdapter->tx_flow_timer_initialized = VOS_TRUE;         }         WLANTL_RegisterTXFlowControl(pHddCtx->pvosContext,                     hdd_tx_resume_cb,                     pAdapter->sessionId,                     (void *)pAdapter);#endif /* QCA_LL_TX_FLOW_CT */         break;      }      case WLAN_HDD_P2P_GO:      case WLAN_HDD_SOFTAP:      {         pAdapter = hdd_wlan_create_ap_dev( pHddCtx, macAddr, (tANI_U8 *)iface_name );         if( NULL == pAdapter )         {            hddLog(VOS_TRACE_LEVEL_FATAL,                   FL("failed to allocate adapter for session %d"), session_type);            return NULL;         }         pAdapter->wdev.iftype = (session_type == WLAN_HDD_SOFTAP) ?                                  NL80211_IFTYPE_AP:                                  NL80211_IFTYPE_P2P_GO;         pAdapter->device_mode = session_type;         status = hdd_init_ap_mode(pAdapter);         if( VOS_STATUS_SUCCESS != status )            goto err_free_netdev;         status = hdd_register_hostapd( pAdapter, rtnl_held );         if( VOS_STATUS_SUCCESS != status )         {            hdd_deinit_adapter(pHddCtx, pAdapter, rtnl_held);            goto err_free_netdev;         }         netif_tx_disable(pAdapter->dev);         netif_carrier_off(pAdapter->dev);         hdd_set_conparam( 1 );         break;      }      case WLAN_HDD_MONITOR:      {         pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );         if( NULL == pAdapter )         {            hddLog(VOS_TRACE_LEVEL_FATAL,                   FL("failed to allocate adapter for session %d"), session_type);            return NULL;         }         pAdapter->wdev.iftype = NL80211_IFTYPE_MONITOR;         pAdapter->device_mode = session_type;         status = hdd_register_interface( pAdapter, rtnl_held );         pAdapter->dev->netdev_ops = &wlan_mon_drv_ops;         hdd_init_tx_rx( pAdapter );         set_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);         //Set adapter to be used for data tx. It will use either GO or softap.         pAdapter->sessionCtx.monitor.pAdapterForTx =                           hdd_get_adapter(pAdapter->pHddCtx, WLAN_HDD_SOFTAP);         if (NULL == pAdapter->sessionCtx.monitor.pAdapterForTx)         {            pAdapter->sessionCtx.monitor.pAdapterForTx =                           hdd_get_adapter(pAdapter->pHddCtx, WLAN_HDD_P2P_GO);         }         /* This work queue will be used to transmit management packet over          * monitor interface. */         if (NULL == pAdapter->sessionCtx.monitor.pAdapterForTx) {             hddLog(VOS_TRACE_LEVEL_ERROR,"%s:Failed:hdd_get_adapter",__func__);             return NULL;         }#ifdef CONFIG_CNSS         cnss_init_work(&pAdapter->sessionCtx.monitor.pAdapterForTx->                        monTxWorkQueue, hdd_mon_tx_work_queue);#else         INIT_WORK(&pAdapter->sessionCtx.monitor.pAdapterForTx->monTxWorkQueue,                   hdd_mon_tx_work_queue);#endif      }         break;      case WLAN_HDD_FTM:      {         pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );         if( NULL == pAdapter )         {            hddLog(VOS_TRACE_LEVEL_FATAL,                   FL("failed to allocate adapter for session %d"), session_type);            return NULL;         }         /* Assign NL80211_IFTYPE_STATION as interface type to resolve Kernel Warning          * message while loading driver in FTM mode. */         pAdapter->wdev.iftype = NL80211_IFTYPE_STATION;         pAdapter->device_mode = session_type;         status = hdd_register_interface( pAdapter, rtnl_held );         hdd_init_tx_rx( pAdapter );         //Stop the Interface TX queue.         netif_tx_disable(pAdapter->dev);         netif_carrier_off(pAdapter->dev);      }         break;      default:      {         hddLog(VOS_TRACE_LEVEL_FATAL,"%s Invalid session type %d",                __func__, session_type);         VOS_ASSERT(0);         return NULL;      }   }......   return NULL;}

hdd_register_interface 函数中实现网络设备注册:

VOS_STATUS hdd_register_interface( hdd_adapter_t *pAdapter, tANI_U8 rtnl_lock_held ){   struct net_device *pWlanDev = pAdapter->dev;   //hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;   //hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );   //eHalStatus halStatus = eHAL_STATUS_SUCCESS;   if( rtnl_lock_held )   {     if (strnchr(pWlanDev->name, strlen(pWlanDev->name), '%')) {         if( dev_alloc_name(pWlanDev, pWlanDev->name) < 0 )         {            hddLog(VOS_TRACE_LEVEL_ERROR,"%s:Failed:dev_alloc_name",__func__);            return VOS_STATUS_E_FAILURE;         }      }      if (register_netdevice(pWlanDev))      {         hddLog(VOS_TRACE_LEVEL_ERROR,"%s:Failed:register_netdev",__func__);         return VOS_STATUS_E_FAILURE;      }   }   else   {      if(register_netdev(pWlanDev))      {         hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed:register_netdev",__func__);         return VOS_STATUS_E_FAILURE;      }   }   set_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags);   return VOS_STATUS_SUCCESS;}

hdd_wlan_startup 中的hdd_alloc_station_adapter 函数为网络设备分配了一个网络适配器,具体实现通过hdd_set_station_ops 函数:

void hdd_set_station_ops( struct net_device *pWlanDev ){      pWlanDev->netdev_ops = &wlan_drv_ops;}

wlan_drv_ops 就是网络设备的操作结构体,定义如下:

static struct net_device_ops wlan_drv_ops = {      .ndo_open = hdd_open,      .ndo_stop = hdd_stop,      .ndo_uninit = hdd_uninit,      .ndo_start_xmit = hdd_hard_start_xmit,      .ndo_tx_timeout = hdd_tx_timeout,      .ndo_get_stats = hdd_stats,      .ndo_do_ioctl = hdd_ioctl,      .ndo_set_mac_address = hdd_set_mac_address,      .ndo_select_queue    = hdd_select_queue,#ifdef WLAN_FEATURE_PACKET_FILTERING#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,1,0))      .ndo_set_rx_mode = hdd_set_multicast_list,#else      .ndo_set_multicast_list = hdd_set_multicast_list,#endif //LINUX_VERSION_CODE#endif };

其中hdd_hard_start_xmit 函数实现数据传输

1 0