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
- qcacld-2.0的wlan分析之二
- qcacld-2.0的wlan分析
- Qualcomm WLAN Driver qcacld-2.0源码分析
- WLAN协议分析的网站
- wlan分析
- 3G、WLAN、Bluetooth三者关系之分析
- 四网协同之WLAN专利分析与启示
- WLAN 安全二
- Wlan简明流程分析
- WLAN驱动分析文档
- WLAN驱动分析文档
- WLAN驱动分析文档
- UMA铺设蜂窝网络和WLAN的融合之路
- wlan信道利用效率分析
- 3G入门之第三课 3G、WLAN、Bluetooth三者关系之分析
- WLAN的测试
- WLAN的安全选型
- WLAN的通信协议结构
- 常用设计者模式---策略模式
- 算法导论 红黑树 学习 删除(四)
- leetcode之AddTwoNumbers
- java中获取当前服务器的Ip地址的方法
- 09给定任意俩组字符串S1和S2,请编程输出他们间的最大相同子串
- qcacld-2.0的wlan分析之二
- Java 中的 File 类
- 欢迎使用CSDN-markdown编辑器
- web常用英语词汇
- VSCode c++配置文件
- Activity启动过程分析
- QT学习之路四(信号与槽----通讯录的再次改版)
- C++简单工厂模式(Simple Factory Pattern)实现
- Hadoop集群搭建