prima: WLAN Driver Release 3.1.7.9
This is the initial release of the Prima WLAN Driver
diff --git a/CORE/HDD/src/wlan_hdd_main.c b/CORE/HDD/src/wlan_hdd_main.c
new file mode 100644
index 0000000..53397a0
--- /dev/null
+++ b/CORE/HDD/src/wlan_hdd_main.c
@@ -0,0 +1,4469 @@
+/*
+ * Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*========================================================================
+
+ \file wlan_hdd_main.c
+
+ \brief WLAN Host Device Driver implementation
+
+ Copyright 2008 (c) Qualcomm, Incorporated. All Rights Reserved.
+
+ Qualcomm Confidential and Proprietary.
+
+ ========================================================================*/
+
+/**=========================================================================
+
+ EDIT HISTORY FOR FILE
+
+
+ This section contains comments describing changes made to the module.
+ Notice that changes are listed in reverse chronological order.
+
+
+ $Header:$ $DateTime: $ $Author: $
+
+
+ when who what, where, why
+ -------- --- --------------------------------------------------------
+ 04/5/09 Shailender Created module.
+ 02/24/10 Sudhir.S.Kohalli Added to support param for SoftAP module
+ 06/03/10 js - Added support to hostapd driven deauth/disassoc/mic failure
+ ==========================================================================*/
+
+/*--------------------------------------------------------------------------
+ Include Files
+ ------------------------------------------------------------------------*/
+//#include <wlan_qct_driver.h>
+#include <wlan_hdd_includes.h>
+#ifdef ANI_BUS_TYPE_SDIO
+#include <wlan_sal_misc.h>
+#endif // ANI_BUS_TYPE_SDIO
+#include <vos_api.h>
+#include <vos_sched.h>
+#include <vos_power.h>
+#include <linux/etherdevice.h>
+#include <linux/firmware.h>
+#ifdef ANI_BUS_TYPE_SDIO
+#include <linux/mmc/sdio_func.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32))
+// added in 2.6.32, need to define locally if using an earlier kernel
+#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
+#endif
+#endif // ANI_BUS_TYPE_SDIO
+#ifdef ANI_BUS_TYPE_PLATFORM
+#include <linux/wcnss_wlan.h>
+#endif //ANI_BUS_TYPE_PLATFORM
+#ifdef ANI_BUS_TYPE_PCI
+#include "wcnss_wlan.h"
+#endif /* ANI_BUS_TYPE_PCI */
+#include <wlan_hdd_tx_rx.h>
+#include <palTimer.h>
+#include <wniApi.h>
+#include <wlan_nlink_srv.h>
+#include <wlan_btc_svc.h>
+#include <wlan_hdd_cfg.h>
+#include <wlan_ptt_sock_svc.h>
+#include <wlan_hdd_wowl.h>
+#include <wlan_hdd_misc.h>
+#include <wlan_hdd_wext.h>
+#ifdef WLAN_BTAMP_FEATURE
+#include <bap_hdd_main.h>
+#include <bapInternal.h>
+#endif // WLAN_BTAMP_FEATURE
+
+#ifdef CONFIG_CFG80211
+#include <linux/wireless.h>
+#include <net/cfg80211.h>
+#include "wlan_hdd_cfg80211.h"
+#include "wlan_hdd_p2p.h"
+#endif
+#include <linux/rtnetlink.h>
+#ifdef ANI_MANF_DIAG
+int wlan_hdd_ftm_start(hdd_context_t *pAdapter);
+#endif
+#ifdef WLAN_SOFTAP_FEATURE
+#include "sapApi.h"
+#include <linux/semaphore.h>
+#include <mach/subsystem_restart.h>
+#include <wlan_hdd_hostapd.h>
+#include <wlan_hdd_softap_tx_rx.h>
+#endif
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+#include "cfgApi.h"
+#endif
+#include "wlan_hdd_dev_pwr.h"
+#ifdef WLAN_BTAMP_FEATURE
+#include "bap_hdd_misc.h"
+#endif
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+#include "wlan_qct_pal_trace.h"
+#endif /* FEATURE_WLAN_INTEGRATED_SOC */
+#include "qwlan_version.h"
+
+#ifdef MODULE
+#define WLAN_MODULE_NAME module_name(THIS_MODULE)
+#else
+#define WLAN_MODULE_NAME "wlan"
+#endif
+
+#ifdef TIMER_MANAGER
+#define TIMER_MANAGER_STR " +TIMER_MANAGER"
+#else
+#define TIMER_MANAGER_STR ""
+#endif
+
+#ifdef MEMORY_DEBUG
+#define MEMORY_DEBUG_STR " +MEMORY_DEBUG"
+#else
+#define MEMORY_DEBUG_STR ""
+#endif
+
+/* the Android framework expects this param even though we don't use it */
+#define BUF_LEN 20
+static char fwpath[BUF_LEN];
+module_param_string(fwpath, fwpath, BUF_LEN,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+static struct wake_lock wlan_wake_lock;
+/* set when SSR is needed after unload */
+static v_U8_t isSsrRequired;
+
+//internal function declaration
+v_U16_t hdd_select_queue(struct net_device *dev,
+ struct sk_buff *skb);
+
+#ifdef WLAN_FEATURE_PACKET_FILTERING
+static void hdd_set_multicast_list(struct net_device *dev);
+#endif
+
+void hdd_wlan_initial_scan(hdd_adapter_t *pAdapter);
+
+extern int hdd_setBand_helper(struct net_device *dev, tANI_U8* ptr);
+
+static int hdd_netdev_notifier_call(struct notifier_block * nb,
+ unsigned long state,
+ void *ndev)
+{
+ struct net_device *dev = ndev;
+ hdd_adapter_t *pAdapter = NULL;
+#ifdef WLAN_BTAMP_FEATURE
+ VOS_STATUS status;
+ hdd_context_t *pHddCtx;
+#endif
+
+ //Make sure that this callback corresponds to our device.
+ if((strncmp( dev->name, "wlan", 4 )) &&
+ (strncmp( dev->name, "p2p-wlan", 8))
+ )
+ return NOTIFY_DONE;
+
+#ifdef CONFIG_CFG80211
+ if (!dev->ieee80211_ptr)
+ return NOTIFY_DONE;
+#endif
+
+ pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+
+ if(NULL == pAdapter)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: HDD Adaptor Null Pointer", __func__);
+ VOS_ASSERT(0);
+ return NOTIFY_DONE;
+ }
+
+ hddLog(VOS_TRACE_LEVEL_INFO,"%s: New Net Device State = %lu", __func__, state);
+
+ switch (state) {
+ case NETDEV_REGISTER:
+ break;
+
+ case NETDEV_UNREGISTER:
+ break;
+
+ case NETDEV_UP:
+ break;
+
+ case NETDEV_DOWN:
+ break;
+
+ case NETDEV_CHANGE:
+ if(VOS_STA_MODE == hdd_get_conparam())
+ {
+ if(TRUE == pAdapter->isLinkUpSvcNeeded)
+ complete(&pAdapter->linkup_event_var);
+ }
+ break;
+
+ case NETDEV_GOING_DOWN:
+ if( pAdapter->scan_info.mScanPending != FALSE )
+ {
+ int result;
+ INIT_COMPLETION(pAdapter->abortscan_event_var);
+ hdd_abort_mac_scan(pAdapter->pHddCtx);
+ result = wait_for_completion_interruptible_timeout(
+ &pAdapter->abortscan_event_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN));
+ if(!result)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: Timeout occured while waiting for abortscan" ,
+ __FUNCTION__);
+ }
+ }
+ else
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s: Scan is not Pending from user" , __FUNCTION__);
+ }
+#ifdef WLAN_BTAMP_FEATURE
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s: disabling AMP", __FUNCTION__);
+ pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
+ status = WLANBAP_StopAmp();
+ if(VOS_STATUS_SUCCESS != status )
+ {
+ pHddCtx->isAmpAllowed = VOS_TRUE;
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: Failed to stop AMP", __func__);
+ }
+ else
+ {
+ //a state m/c implementation in PAL is TBD to avoid this delay
+ msleep(500);
+ pHddCtx->isAmpAllowed = VOS_FALSE;
+ WLANBAP_DeregisterFromHCI();
+ }
+#endif //WLAN_BTAMP_FEATURE
+ break;
+
+ default:
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+struct notifier_block hdd_netdev_notifier = {
+ .notifier_call = hdd_netdev_notifier_call,
+};
+
+/*---------------------------------------------------------------------------
+ * Function definitions
+ *-------------------------------------------------------------------------*/
+extern int isWDresetInProgress(void);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+extern void register_wlan_suspend(void);
+extern void unregister_wlan_suspend(void);
+void hdd_unregister_mcast_bcast_filter(hdd_context_t *pHddCtx);
+void hdd_register_mcast_bcast_filter(hdd_context_t *pHddCtx);
+#endif
+#ifdef WLAN_SOFTAP_FEATURE
+//variable to hold the insmod parameters
+static int con_mode = 0;
+#endif
+
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+/**---------------------------------------------------------------------------
+
+ \brief hdd_wdi_trace_enable() - Configure initial WDI Trace enable
+
+ Called immediately after the cfg.ini is read in order to configure
+ the desired trace levels in the WDI.
+
+ \param - moduleId - module whose trace level is being configured
+ \param - bitmask - bitmask of log levels to be enabled
+
+ \return - void
+
+ --------------------------------------------------------------------------*/
+static void hdd_wdi_trace_enable(wpt_moduleid moduleId, v_U32_t bitmask)
+{
+ wpt_tracelevel level;
+
+ /* if the bitmask is the default value, then a bitmask was not
+ specified in cfg.ini, so leave the logging level alone (it
+ will remain at the "compiled in" default value) */
+ if (CFG_WDI_TRACE_ENABLE_DEFAULT == bitmask)
+ {
+ return;
+ }
+
+ /* a mask was specified. start by disabling all logging */
+ wpalTraceSetLevel(moduleId, eWLAN_PAL_TRACE_LEVEL_NONE, 0);
+
+ /* now cycle through the bitmask until all "set" bits are serviced */
+ level = eWLAN_PAL_TRACE_LEVEL_FATAL;
+ while (0 != bitmask)
+ {
+ if (bitmask & 1)
+ {
+ wpalTraceSetLevel(moduleId, level, 1);
+ }
+ level++;
+ bitmask >>= 1;
+ }
+}
+#endif /* FEATURE_WLAN_INTEGRATED_SOC */
+
+int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_priv_data_t priv_data;
+ tANI_U8 *command = NULL;
+ int ret = 0;
+
+ if (NULL == pAdapter)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD adapter context is Null", __FUNCTION__);
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ if ((!ifr) && (!ifr->ifr_data))
+ {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(hdd_priv_data_t)))
+ {
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ command = kmalloc(priv_data.total_len, GFP_KERNEL);
+ if (!command)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: failed to allocate memory\n", __FUNCTION__);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ if (copy_from_user(command, priv_data.buf, priv_data.total_len))
+ {
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ if ((SIOCDEVPRIVATE + 1) == cmd)
+ {
+ hdd_context_t *pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
+
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "***Received %s cmd from Wi-Fi GUI***", command);
+
+ if (strncmp(command, "P2P_DEV_ADDR", 12) == 0 )
+ {
+ if (copy_to_user(priv_data.buf, pHddCtx->p2pDeviceAddress.bytes,
+ sizeof(tSirMacAddr)))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: failed to copy data to user buffer\n", __FUNCTION__);
+ ret = -EFAULT;
+ }
+ }
+ if(strncmp(priv_data.buf, "SETBAND", 7) == 0)
+ {
+ tANI_U8 *ptr = (tANI_U8*)priv_data.buf ;
+ int ret = 0 ;
+
+ /* Change band request received */
+
+ /* First 8 bytes will have "SETBAND " and
+ * 9 byte will have band setting value */
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ "%s: SetBandCommand Info comm %s UL %d, TL %d", __FUNCTION__, priv_data.buf, priv_data.used_len, priv_data.total_len);
+
+ /* Change band request received */
+ ret = hdd_setBand_helper(dev, ptr);
+ }
+ }
+exit:
+ if (command)
+ {
+ kfree(command);
+ }
+ return ret;
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_open() - HDD Open function
+
+ This is called in response to ifconfig up
+
+ \param - dev Pointer to net_device structure
+
+ \return - 0 for success non-zero for failure
+
+ --------------------------------------------------------------------------*/
+int hdd_open (struct net_device *dev)
+{
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_context_t *pHddCtx;
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ VOS_STATUS status;
+ v_BOOL_t in_standby = TRUE;
+
+ if (NULL == pAdapter)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD adapter context is Null", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
+ if (NULL == pHddCtx)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD context is Null", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+ while ( (NULL != pAdapterNode) && (VOS_STATUS_SUCCESS == status) )
+ {
+ if( pAdapterNode->pAdapter->event_flags & DEVICE_IFACE_OPENED)
+ {
+ hddLog(VOS_TRACE_LEVEL_INFO, "%s: chip already out of "
+ "standby", __func__, pAdapter->device_mode);
+ in_standby = FALSE;
+ break;
+ }
+ else
+ {
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+ }
+
+ if (TRUE == in_standby)
+ {
+ if (VOS_STATUS_SUCCESS != wlan_hdd_exit_lowpower(pHddCtx, pAdapter))
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Failed to bring "
+ "wlan out of power save", __func__);
+ return -EINVAL;
+ }
+ }
+
+ pAdapter->event_flags |= DEVICE_IFACE_OPENED;
+ if (hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
+ "%s: Enabling Tx Queues", __FUNCTION__);
+ /* Enable TX queues only when we are connected */
+ netif_tx_start_all_queues(dev);
+ }
+
+ return 0;
+}
+
+int hdd_mon_open (struct net_device *dev)
+{
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+
+ if(pAdapter == NULL) {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD adapter context is Null", __FUNCTION__);
+ return -1;
+ }
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+/**---------------------------------------------------------------------------
+
+ \brief hdd_stop() - HDD stop function
+
+ This is called in response to ifconfig down
+
+ \param - dev Pointer to net_device structure
+
+ \return - 0 for success non-zero for failure
+
+ --------------------------------------------------------------------------*/
+
+int hdd_stop (struct net_device *dev)
+{
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_context_t *pHddCtx;
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ VOS_STATUS status;
+ v_BOOL_t enter_standby = TRUE;
+
+ ENTER();
+
+ if (NULL == pAdapter)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD adapter context is Null", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
+ if (NULL == pHddCtx)
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: HDD context is Null", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ pAdapter->event_flags &= ~(DEVICE_IFACE_OPENED);
+ hddLog(VOS_TRACE_LEVEL_INFO, "%s: Disabling OS Tx queues", __func__);
+ netif_tx_disable(pAdapter->dev);
+ netif_carrier_off(pAdapter->dev);
+
+
+ /* SoftAP ifaces should never go in power save mode
+ making sure same here. */
+ if ( (WLAN_HDD_SOFTAP == pAdapter->device_mode )
+ || (WLAN_HDD_MONITOR == pAdapter->device_mode )
+#ifdef WLAN_FEATURE_P2P
+ || (WLAN_HDD_P2P_GO == pAdapter->device_mode )
+#endif
+ )
+ {
+ /* SoftAP mode, so return from here */
+ EXIT();
+ return 0;
+ }
+
+ /* Find if any iface is up then
+ if any iface is up then can't put device to sleep/ power save mode. */
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+ while ( (NULL != pAdapterNode) && (VOS_STATUS_SUCCESS == status) )
+ {
+ if ( pAdapterNode->pAdapter->event_flags & DEVICE_IFACE_OPENED)
+ {
+ hddLog(VOS_TRACE_LEVEL_INFO, "%s: Still other ifaces are up cannot "
+ "put device to sleep", __func__, pAdapter->device_mode);
+ enter_standby = FALSE;
+ break;
+ }
+ else
+ {
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+ }
+
+ if (TRUE == enter_standby)
+ {
+ hddLog(VOS_TRACE_LEVEL_INFO, "%s: All Interfaces are Down "
+ "entering standby", __func__);
+ if (VOS_STATUS_SUCCESS != wlan_hdd_enter_lowpower(pHddCtx))
+ {
+ /*log and return success*/
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Failed to put "
+ "wlan in power save", __func__);
+ }
+ }
+
+ EXIT();
+ return 0;
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_uninit() - HDD uninit function
+
+ This is called during the netdev unregister to uninitialize all data
+associated with the device
+
+ \param - dev Pointer to net_device structure
+
+ \return - void
+
+ --------------------------------------------------------------------------*/
+static void hdd_uninit (struct net_device *dev)
+{
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+
+ ENTER();
+
+ do
+ {
+ if (NULL == pAdapter)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: NULL pAdapter", __func__);
+ break;
+ }
+
+ if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: Invalid magic", __func__);
+ break;
+ }
+
+ if (NULL == pAdapter->pHddCtx)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: NULL pHddCtx", __func__);
+ break;
+ }
+
+ if (dev != pAdapter->dev)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: Invalid device reference", __func__);
+ /* we haven't validated all cases so let this go for now */
+ }
+
+ hdd_deinit_adapter(pAdapter->pHddCtx, pAdapter);
+
+ /* after uninit our adapter structure will no longer be valid */
+ pAdapter->dev = NULL;
+ pAdapter->magic = 0;
+ } while (0);
+
+ EXIT();
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_release_firmware() -
+
+ This function calls the release firmware API to free the firmware buffer.
+
+ \param - pFileName Pointer to the File Name.
+ pCtx - Pointer to the adapter .
+
+
+ \return - 0 for success, non zero for failure
+
+ --------------------------------------------------------------------------*/
+
+VOS_STATUS hdd_release_firmware(char *pFileName,v_VOID_t *pCtx)
+{
+ VOS_STATUS status = VOS_STATUS_SUCCESS;
+ hdd_context_t *pHddCtx = (hdd_context_t*)pCtx;
+ ENTER();
+
+
+ if (!strcmp(WLAN_FW_FILE, pFileName)) {
+
+ hddLog(VOS_TRACE_LEVEL_INFO_HIGH,"%s: Loaded firmware file is %s",__func__,pFileName);
+
+ if(pHddCtx->fw) {
+ release_firmware(pHddCtx->fw);
+ pHddCtx->fw = NULL;
+ }
+ else
+ status = VOS_STATUS_E_FAILURE;
+ }
+ else if (!strcmp(WLAN_NV_FILE,pFileName)) {
+ if(pHddCtx->nv) {
+ release_firmware(pHddCtx->nv);
+ pHddCtx->nv = NULL;
+ }
+ else
+ status = VOS_STATUS_E_FAILURE;
+
+ }
+
+ EXIT();
+ return status;
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_request_firmware() -
+
+ This function reads the firmware file using the request firmware
+ API and returns the the firmware data and the firmware file size.
+
+ \param - pfileName - Pointer to the file name.
+ - pCtx - Pointer to the adapter .
+ - ppfw_data - Pointer to the pointer of the firmware data.
+ - pSize - Pointer to the file size.
+
+ \return - VOS_STATUS_SUCCESS for success, VOS_STATUS_E_FAILURE for failure
+
+ --------------------------------------------------------------------------*/
+
+
+VOS_STATUS hdd_request_firmware(char *pfileName,v_VOID_t *pCtx,v_VOID_t **ppfw_data, v_SIZE_t *pSize)
+{
+ int status;
+ VOS_STATUS retval = VOS_STATUS_SUCCESS;
+ hdd_context_t *pHddCtx = (hdd_context_t*)pCtx;
+ ENTER();
+
+ if( (!strcmp(WLAN_FW_FILE, pfileName)) ) {
+
+ status = request_firmware(&pHddCtx->fw, pfileName, pHddCtx->parent_dev);
+
+ if(status || !pHddCtx->fw || !pHddCtx->fw->data) {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Firmware %s download failed",
+ __func__, pfileName);
+ retval = VOS_STATUS_E_FAILURE;
+ }
+
+ else {
+ *ppfw_data = (v_VOID_t *)pHddCtx->fw->data;
+ *pSize = pHddCtx->fw->size;
+ hddLog(VOS_TRACE_LEVEL_INFO, "%s: Firmware size = %d",
+ __func__, *pSize);
+ }
+ }
+ else if(!strcmp(WLAN_NV_FILE, pfileName)) {
+
+ status = request_firmware(&pHddCtx->nv, pfileName, pHddCtx->parent_dev);
+
+ if(status || !pHddCtx->nv || !pHddCtx->nv->data) {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: nv %s download failed",
+ __func__, pfileName);
+ retval = VOS_STATUS_E_FAILURE;
+ }
+
+ else {
+ *ppfw_data = (v_VOID_t *)pHddCtx->nv->data;
+ *pSize = pHddCtx->nv->size;
+ hddLog(VOS_TRACE_LEVEL_INFO, "%s: nv file size = %d",
+ __func__, *pSize);
+ }
+ }
+
+ EXIT();
+ return retval;
+}
+/**---------------------------------------------------------------------------
+ \brief hdd_full_pwr_cbk() - HDD full power callbackfunction
+
+ This is the function invoked by SME to inform the result of a full power
+ request issued by HDD
+
+ \param - callbackcontext - Pointer to cookie
+ status - result of request
+
+ \return - None
+
+--------------------------------------------------------------------------*/
+void hdd_full_pwr_cbk(void *callbackContext, eHalStatus status)
+{
+ hdd_context_t *pHddCtx = (hdd_context_t*)callbackContext;
+
+ hddLog(VOS_TRACE_LEVEL_ERROR,"HDD full Power callback status = %d", status);
+ if(&pHddCtx->full_pwr_comp_var)
+ {
+ complete(&pHddCtx->full_pwr_comp_var);
+ }
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_req_bmps_cbk() - HDD Request BMPS callback function
+
+ This is the function invoked by SME to inform the result of BMPS
+ request issued by HDD
+
+ \param - callbackcontext - Pointer to cookie
+ status - result of request
+
+ \return - None
+
+--------------------------------------------------------------------------*/
+void hdd_req_bmps_cbk(void *callbackContext, eHalStatus status)
+{
+
+ struct completion *completion_var = (struct completion*) callbackContext;
+
+ hddLog(VOS_TRACE_LEVEL_ERROR, "HDD BMPS request Callback, status = %d\n", status);
+ if(completion_var != NULL)
+ {
+ complete(completion_var);
+ }
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_get_cfg_file_size() -
+
+ This function reads the configuration file using the request firmware
+ API and returns the configuration file size.
+
+ \param - pCtx - Pointer to the adapter .
+ - pFileName - Pointer to the file name.
+ - pBufSize - Pointer to the buffer size.
+
+ \return - 0 for success, non zero for failure
+
+ --------------------------------------------------------------------------*/
+
+VOS_STATUS hdd_get_cfg_file_size(v_VOID_t *pCtx, char *pFileName, v_SIZE_t *pBufSize)
+{
+ int status;
+ hdd_context_t *pHddCtx = (hdd_context_t*)pCtx;
+
+ ENTER();
+
+ status = request_firmware(&pHddCtx->fw, pFileName, pHddCtx->parent_dev);
+
+ if(status || !pHddCtx->fw || !pHddCtx->fw->data) {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: CFG download failed",__func__);
+ status = VOS_STATUS_E_FAILURE;
+ }
+ else {
+ *pBufSize = pHddCtx->fw->size;
+ hddLog(VOS_TRACE_LEVEL_INFO, "%s: CFG size = %d", __func__, *pBufSize);
+ release_firmware(pHddCtx->fw);
+ pHddCtx->fw = NULL;
+ }
+
+ EXIT();
+ return VOS_STATUS_SUCCESS;
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_read_cfg_file() -
+
+ This function reads the configuration file using the request firmware
+ API and returns the cfg data and the buffer size of the configuration file.
+
+ \param - pCtx - Pointer to the adapter .
+ - pFileName - Pointer to the file name.
+ - pBuffer - Pointer to the data buffer.
+ - pBufSize - Pointer to the buffer size.
+
+ \return - 0 for success, non zero for failure
+
+ --------------------------------------------------------------------------*/
+
+VOS_STATUS hdd_read_cfg_file(v_VOID_t *pCtx, char *pFileName,
+ v_VOID_t *pBuffer, v_SIZE_t *pBufSize)
+{
+ int status;
+ hdd_context_t *pHddCtx = (hdd_context_t*)pCtx;
+
+ ENTER();
+
+ status = request_firmware(&pHddCtx->fw, pFileName, pHddCtx->parent_dev);
+
+ if(status || !pHddCtx->fw || !pHddCtx->fw->data) {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: CFG download failed",__func__);
+ return VOS_STATUS_E_FAILURE;
+ }
+ else {
+ if(*pBufSize != pHddCtx->fw->size) {
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Caller sets invalid CFG "
+ "file size", __func__);
+ release_firmware(pHddCtx->fw);
+ pHddCtx->fw = NULL;
+ return VOS_STATUS_E_FAILURE;
+ }
+ else {
+ if(pBuffer) {
+ vos_mem_copy(pBuffer,pHddCtx->fw->data,*pBufSize);
+ }
+ release_firmware(pHddCtx->fw);
+ pHddCtx->fw = NULL;
+ }
+ }
+
+ EXIT();
+
+ return VOS_STATUS_SUCCESS;
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_set_mac_addr_cb() -
+
+ This function is the call back function for setting the station
+ mac adrress called by ccm module to indicate the
+ success/failure result.
+
+ \param - hHal - Pointer to the hal module.
+ - result - returns the result of the set mac address.
+
+ \return - void
+
+ --------------------------------------------------------------------------*/
+#ifndef FEATURE_WLAN_INTEGRATED_SOC
+static void hdd_set_mac_addr_cb( tHalHandle hHal, tANI_S32 result )
+{
+ // ignore the STA_ID response for now.
+
+ VOS_ASSERT( CCM_IS_RESULT_SUCCESS( result ) );
+}
+#endif
+
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_set_mac_address() -
+
+ This function sets the user specified mac address using
+ the command ifconfig wlanX hw ether <mac adress>.
+
+ \param - dev - Pointer to the net device.
+ - addr - Pointer to the sockaddr.
+ \return - 0 for success, non zero for failure
+
+ --------------------------------------------------------------------------*/
+
+static int hdd_set_mac_address(struct net_device *dev, void *addr)
+{
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ struct sockaddr *psta_mac_addr = addr;
+ eHalStatus halStatus = eHAL_STATUS_SUCCESS;
+
+ ENTER();
+
+ memcpy(&pAdapter->macAddressCurrent, psta_mac_addr->sa_data, ETH_ALEN);
+
+#ifdef HDD_SESSIONIZE
+ // set the MAC address though the STA ID CFG.
+ halStatus = ccmCfgSetStr( pAdapter->hHal, WNI_CFG_STA_ID,
+ (v_U8_t *)&pAdapter->macAddressCurrent,
+ sizeof( pAdapter->macAddressCurrent ),
+ hdd_set_mac_addr_cb, VOS_FALSE );
+#endif
+
+ memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN);
+
+ EXIT();
+ return halStatus;
+}
+
+tANI_U8* wlan_hdd_get_intf_addr(hdd_context_t* pHddCtx)
+{
+ int i;
+ for ( i = 0; i < VOS_MAX_CONCURRENCY_PERSONA; i++)
+ {
+ if( 0 == (pHddCtx->cfg_ini->intfAddrMask >> i))
+ break;
+ }
+
+ if( VOS_MAX_CONCURRENCY_PERSONA == i)
+ return NULL;
+
+ pHddCtx->cfg_ini->intfAddrMask |= (1 << i);
+ return &pHddCtx->cfg_ini->intfMacAddr[i].bytes[0];
+}
+
+void wlan_hdd_release_intf_addr(hdd_context_t* pHddCtx, tANI_U8* releaseAddr)
+{
+ int i;
+ for ( i = 0; i < VOS_MAX_CONCURRENCY_PERSONA; i++)
+ {
+ if ( !memcmp(releaseAddr, &pHddCtx->cfg_ini->intfMacAddr[i].bytes[0], 6) )
+ {
+ pHddCtx->cfg_ini->intfAddrMask &= ~(1 << i);
+ break;
+ }
+ }
+ return;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
+ 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
+ };
+#ifdef CONFIG_CFG80211
+ static struct net_device_ops wlan_mon_drv_ops = {
+ .ndo_open = hdd_mon_open,
+ .ndo_stop = hdd_stop,
+ .ndo_uninit = hdd_uninit,
+ .ndo_start_xmit = hdd_mon_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,
+ };
+#endif
+
+#endif
+
+void hdd_set_station_ops( struct net_device *pWlanDev )
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
+ pWlanDev->tx_queue_len = NET_DEV_TX_QUEUE_LEN,
+ pWlanDev->netdev_ops = &wlan_drv_ops;
+#else
+ pWlanDev->open = hdd_open;
+ pWlanDev->stop = hdd_stop;
+ pWlanDev->uninit = hdd_uninit;
+ pWlanDev->hard_start_xmit = NULL;
+ pWlanDev->tx_timeout = hdd_tx_timeout;
+ pWlanDev->get_stats = hdd_stats;
+ pWlanDev->do_ioctl = hdd_ioctl;
+ pWlanDev->tx_queue_len = NET_DEV_TX_QUEUE_LEN;
+ pWlanDev->set_mac_address = hdd_set_mac_address;
+#endif
+}
+
+hdd_adapter_t* hdd_alloc_station_adapter( hdd_context_t *pHddCtx, tSirMacAddr macAddr, char* name )
+{
+ struct net_device *pWlanDev = NULL;
+ hdd_adapter_t *pAdapter = NULL;
+#ifdef CONFIG_CFG80211
+ /*
+ * cfg80211 initialization and registration....
+ */
+ pWlanDev = alloc_netdev_mq(sizeof( hdd_adapter_t ), name, ether_setup, NUM_TX_QUEUES);
+
+#else
+ //Allocate the net_device and private data (station ctx)
+ pWlanDev = alloc_etherdev_mq(sizeof( hdd_adapter_t ), NUM_TX_QUEUES);
+
+#endif
+
+ if(pWlanDev != NULL)
+ {
+
+ //Save the pointer to the net_device in the HDD adapter
+ pAdapter = (hdd_adapter_t*) netdev_priv( pWlanDev );
+
+#ifndef CONFIG_CFG80211
+ //Init the net_device structure
+ ether_setup(pWlanDev);
+#endif
+
+ vos_mem_zero( pAdapter, sizeof( hdd_adapter_t ) );
+
+ pAdapter->dev = pWlanDev;
+ pAdapter->pHddCtx = pHddCtx;
+ pAdapter->magic = WLAN_HDD_ADAPTER_MAGIC;
+
+ init_completion(&pAdapter->session_open_comp_var);
+ init_completion(&pAdapter->session_close_comp_var);
+ init_completion(&pAdapter->disconnect_comp_var);
+ init_completion(&pAdapter->linkup_event_var);
+ init_completion(&pAdapter->cancel_rem_on_chan_var);
+ init_completion(&pAdapter->rem_on_chan_ready_event);
+ init_completion(&pAdapter->abortscan_event_var);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
+ init_completion(&pAdapter->offchannel_tx_event);
+#endif
+#ifdef CONFIG_CFG80211
+ init_completion(&pAdapter->tx_action_cnf_event);
+#endif
+ init_completion(&pHddCtx->mc_sus_event_var);
+ init_completion(&pHddCtx->tx_sus_event_var);
+
+ init_completion(&pAdapter->scan_info.scan_req_completion_event);
+
+ pAdapter->isLinkUpSvcNeeded = FALSE;
+ pAdapter->higherDtimTransition = eANI_BOOLEAN_TRUE;
+ //Init the net_device structure
+ strlcpy(pWlanDev->name, name, IFNAMSIZ);
+
+ vos_mem_copy(pWlanDev->dev_addr, (void *)macAddr, sizeof(tSirMacAddr));
+ vos_mem_copy( pAdapter->macAddressCurrent.bytes, macAddr, sizeof(tSirMacAddr));
+ pWlanDev->watchdog_timeo = HDD_TX_TIMEOUT;
+ pWlanDev->hard_header_len += LIBRA_HW_NEEDED_HEADROOM;
+
+ hdd_set_station_ops( pAdapter->dev );
+
+ pWlanDev->destructor = free_netdev;
+#ifdef CONFIG_CFG80211
+ pWlanDev->ieee80211_ptr = &pAdapter->wdev ;
+ pAdapter->wdev.wiphy = pHddCtx->wiphy;
+ pAdapter->wdev.netdev = pWlanDev;
+#endif
+ /* set pWlanDev's parent to underlying device */
+ SET_NETDEV_DEV(pWlanDev, pHddCtx->parent_dev);
+ }
+
+ return pAdapter;
+}
+
+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 (strchr(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;
+}
+
+eHalStatus hdd_smeCloseSessionCallback(void *pContext)
+{
+ if(pContext != NULL)
+ {
+ clear_bit(SME_SESSION_OPENED, &((hdd_adapter_t*)pContext)->event_flags);
+
+ /* need to make sure all of our scheduled work has completed.
+ * This callback is called from MC thread context, so it is safe to
+ * to call below flush workqueue API from here.
+ */
+ flush_scheduled_work();
+ complete(&((hdd_adapter_t*)pContext)->session_close_comp_var);
+ }
+ return eHAL_STATUS_SUCCESS;
+}
+
+VOS_STATUS hdd_init_station_mode( hdd_adapter_t *pAdapter )
+{
+ 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;
+ VOS_STATUS status = VOS_STATUS_E_FAILURE;
+ int rc = 0;
+
+ INIT_COMPLETION(pAdapter->session_open_comp_var);
+ //Open a SME session for future operation
+ halStatus = sme_OpenSession( pHddCtx->hHal, hdd_smeRoamCallback, pAdapter,
+ (tANI_U8 *)&pAdapter->macAddressCurrent, &pAdapter->sessionId );
+ if ( !HAL_STATUS_SUCCESS( halStatus ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "sme_OpenSession() failed with status code %08d [x%08lx]",
+ halStatus, halStatus );
+ status = VOS_STATUS_E_FAILURE;
+ goto error_sme_open;
+ }
+
+ //Block on a completion variable. Can't wait forever though.
+ rc = wait_for_completion_interruptible_timeout(
+ &pAdapter->session_open_comp_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
+ if (!rc)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "Session is not opened within timeout period code %08d", rc );
+ status = VOS_STATUS_E_FAILURE;
+ goto error_sme_open;
+ }
+
+ // Register wireless extensions
+ if( eHAL_STATUS_SUCCESS != (halStatus = hdd_register_wext(pWlanDev)))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "hdd_register_wext() failed with status code %08d [x%08lx]",
+ halStatus, halStatus );
+ status = VOS_STATUS_E_FAILURE;
+ goto error_register_wext;
+ }
+ //Safe to register the hard_start_xmit function again
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
+ wlan_drv_ops.ndo_start_xmit = hdd_hard_start_xmit;
+#else
+ pWlanDev->hard_start_xmit = hdd_hard_start_xmit;
+#endif
+
+ //Set the Connection State to Not Connected
+ pHddStaCtx->conn_info.connState = eConnectionState_NotConnected;
+
+ //Set the default operation channel
+ pHddStaCtx->conn_info.operationChannel = pHddCtx->cfg_ini->OperatingChannel;
+
+ /* Make the default Auth Type as OPEN*/
+ pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM;
+
+ if( VOS_STATUS_SUCCESS != ( status = hdd_init_tx_rx( pAdapter ) ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "hdd_init_tx_rx() failed with status code %08d [x%08lx]",
+ status, status );
+ goto error_init_txrx;
+ }
+
+ set_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
+
+ if( VOS_STATUS_SUCCESS != ( status = hdd_wmm_adapter_init( pAdapter ) ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "hdd_wmm_adapter_init() failed with status code %08d [x%08lx]",
+ status, status );
+ goto error_wmm_init;
+ }
+
+ set_bit(WMM_INIT_DONE, &pAdapter->event_flags);
+
+ return VOS_STATUS_SUCCESS;
+
+error_wmm_init:
+ clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
+ hdd_deinit_tx_rx(pAdapter);
+error_init_txrx:
+ hdd_UnregisterWext(pWlanDev);
+error_register_wext:
+ if(test_bit(SME_SESSION_OPENED, &pAdapter->event_flags))
+ {
+ INIT_COMPLETION(pAdapter->session_close_comp_var);
+ if( eHAL_STATUS_SUCCESS == sme_CloseSession( pHddCtx->hHal,
+ pAdapter->sessionId,
+ hdd_smeCloseSessionCallback, pAdapter ) )
+ {
+ //Block on a completion variable. Can't wait forever though.
+ wait_for_completion_interruptible_timeout(
+ &pAdapter->session_close_comp_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
+ }
+}
+error_sme_open:
+ return status;
+}
+
+#ifdef WLAN_FEATURE_P2P
+/**
+ * hdd_init_p2p_device_mode
+ *
+ *FUNCTION:
+ * This function is called from hdd_wlan_startup function when wlan
+ * driver module is loaded.
+ *
+ *LOGIC:
+ * Open New SME session with P2P Device Mac Address which is different
+ * from STA Mac Address SME session. When driver receive any frame on STA Mac
+ * Address then we divert all the frame using P2P Device Mac Address instaed of
+ * STA Mac address.
+ *
+ *ASSUMPTIONS:
+ *
+ *
+ *NOTE:
+ *
+ * @param pAdapter Pointer to pAdapter structure
+ *
+ * @return None
+ */
+VOS_STATUS hdd_init_p2p_device_mode( hdd_adapter_t *pAdapter)
+{
+ hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
+ eHalStatus halStatus = eHAL_STATUS_SUCCESS;
+ VOS_STATUS status = VOS_STATUS_E_FAILURE;
+ int rc = 0;
+
+ INIT_COMPLETION(pAdapter->session_open_comp_var);
+ //Open a SME session for future operation
+ halStatus = sme_OpenSession( pHddCtx->hHal, hdd_smeRoamCallback, pAdapter,
+ (tANI_U8 *)&pHddCtx->p2pDeviceAddress, &pAdapter->p2pSessionId);
+ if ( !HAL_STATUS_SUCCESS( halStatus ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "sme_OpenSession() failed with status code %08d [x%08lx]",
+ halStatus, halStatus );
+ status = VOS_STATUS_E_FAILURE;
+ return status;
+ }
+
+ //Block on a completion variable. Can't wait forever though.
+ rc = wait_for_completion_interruptible_timeout(
+ &pAdapter->session_open_comp_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
+ if (!rc)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "Session is not opened within timeout period code %08d", rc );
+ status = VOS_STATUS_E_FAILURE;
+ return status;
+ }
+
+ return VOS_STATUS_SUCCESS;
+}
+#endif
+
+#ifdef CONFIG_CFG80211
+void hdd_cleanup_actionframe( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
+{
+ hdd_cfg80211_state_t *cfgState;
+
+ cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
+
+ if( NULL != cfgState->buf )
+ {
+ int rc;
+ INIT_COMPLETION(pAdapter->tx_action_cnf_event);
+ rc = wait_for_completion_interruptible_timeout(
+ &pAdapter->tx_action_cnf_event,
+ msecs_to_jiffies(ACTION_FRAME_TX_TIMEOUT));
+ if(!rc)
+ {
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+ ("ERROR: HDD Wait for Action Confirmation Failed!!\n"));
+ }
+ }
+ return;
+}
+#endif
+
+void hdd_deinit_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
+{
+ ENTER();
+ switch ( pAdapter->device_mode )
+ {
+ case WLAN_HDD_INFRA_STATION:
+ case WLAN_HDD_P2P_CLIENT:
+ {
+ if(test_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags))
+ {
+ hdd_deinit_tx_rx( pAdapter );
+ clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
+ }
+
+ if(test_bit(WMM_INIT_DONE, &pAdapter->event_flags))
+ {
+ hdd_wmm_adapter_close( pAdapter );
+ clear_bit(WMM_INIT_DONE, &pAdapter->event_flags);
+ }
+
+#ifdef CONFIG_CFG80211
+ hdd_cleanup_actionframe(pHddCtx, pAdapter);
+#endif
+
+ break;
+ }
+
+ case WLAN_HDD_SOFTAP:
+ case WLAN_HDD_P2P_GO:
+#ifdef WLAN_SOFTAP_FEATURE
+ {
+#ifdef CONFIG_CFG80211
+ hdd_cleanup_actionframe(pHddCtx, pAdapter);
+#endif
+
+ hdd_unregister_hostapd(pAdapter);
+ hdd_set_conparam( 0 );
+#ifdef CONFIG_CFG80211
+ wlan_hdd_set_monitor_tx_adapter( WLAN_HDD_GET_CTX(pAdapter), NULL );
+#endif
+ break;
+ }
+
+ case WLAN_HDD_MONITOR:
+ {
+#ifdef CONFIG_CFG80211
+ hdd_adapter_t* pAdapterforTx = pAdapter->sessionCtx.monitor.pAdapterForTx;
+#endif
+ if(test_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags))
+ {
+ hdd_deinit_tx_rx( pAdapter );
+ clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
+ }
+#ifdef CONFIG_CFG80211
+ if(NULL != pAdapterforTx)
+ {
+ hdd_cleanup_actionframe(pHddCtx, pAdapterforTx);
+ }
+#endif
+#endif //WLAN_SOFTAP_FEATURE
+ break;
+ }
+
+
+ default:
+ break;
+ }
+
+ EXIT();
+}
+
+void hdd_cleanup_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, tANI_U8 rtnl_held )
+{
+ struct net_device *pWlanDev = pAdapter->dev;
+
+ if(test_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags)) {
+ if( rtnl_held )
+ {
+ unregister_netdevice(pWlanDev);
+ }
+ else
+ {
+ unregister_netdev(pWlanDev);
+ }
+ // note that the pAdapter is no longer valid at this point
+ // since the memory has been reclaimed
+ }
+
+}
+
+VOS_STATUS hdd_enable_bmps_imps(hdd_context_t *pHddCtx)
+{
+ VOS_STATUS status = VOS_STATUS_SUCCESS;
+
+ if(pHddCtx->cfg_ini->fIsBmpsEnabled)
+ {
+ sme_EnablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE);
+ }
+
+ if(pHddCtx->cfg_ini->fIsAutoBmpsTimerEnabled)
+ {
+ sme_StartAutoBmpsTimer(pHddCtx->hHal);
+ }
+
+ if (pHddCtx->cfg_ini->fIsImpsEnabled)
+ {
+ sme_EnablePowerSave (pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE);
+ }
+
+ return status;
+}
+
+VOS_STATUS hdd_disable_bmps_imps(hdd_context_t *pHddCtx, tANI_U8 session_type)
+{
+ hdd_adapter_t *pAdapter = NULL;
+ eHalStatus halStatus;
+ VOS_STATUS status = VOS_STATUS_E_INVAL;
+ v_BOOL_t disableBmps = FALSE;
+ v_BOOL_t disableImps = FALSE;
+
+ switch(session_type)
+ {
+ case WLAN_HDD_INFRA_STATION:
+ case WLAN_HDD_SOFTAP:
+#ifdef WLAN_FEATURE_P2P
+ case WLAN_HDD_P2P_CLIENT:
+ case WLAN_HDD_P2P_GO:
+#endif
+ //Exit BMPS -> Is Sta/P2P Client is already connected
+ pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION);
+ if((NULL != pAdapter)&&
+ hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
+ {
+ disableBmps = TRUE;
+ }
+
+ pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_P2P_CLIENT);
+ if((NULL != pAdapter)&&
+ hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
+ {
+ disableBmps = TRUE;
+ }
+
+ //Exit both Bmps and Imps incase of Go/SAP Mode
+ if((WLAN_HDD_SOFTAP == session_type) ||
+ (WLAN_HDD_P2P_GO == session_type))
+ {
+ disableBmps = TRUE;
+ disableImps = TRUE;
+ }
+
+ if(TRUE == disableImps)
+ {
+ if (pHddCtx->cfg_ini->fIsImpsEnabled)
+ {
+ sme_DisablePowerSave (pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE);
+ }
+ }
+
+ if(TRUE == disableBmps)
+ {
+ if(pHddCtx->cfg_ini->fIsBmpsEnabled)
+ {
+ halStatus = sme_DisablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE);
+
+ if(eHAL_STATUS_SUCCESS != halStatus)
+ {
+ status = VOS_STATUS_E_FAILURE;
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Fail to Disable Power Save\n", __func__);
+ VOS_ASSERT(0);
+ return status;
+ }
+ }
+
+ if(pHddCtx->cfg_ini->fIsAutoBmpsTimerEnabled)
+ {
+ halStatus = sme_StopAutoBmpsTimer(pHddCtx->hHal);
+
+ if(eHAL_STATUS_SUCCESS != halStatus)
+ {
+ status = VOS_STATUS_E_FAILURE;
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Fail to Stop Auto Bmps Timer\n", __func__);
+ VOS_ASSERT(0);
+ return status;
+ }
+ }
+ }
+
+ if((TRUE == disableBmps) ||
+ (TRUE == disableImps))
+ {
+ /* Now, get the chip into Full Power now */
+ INIT_COMPLETION(pHddCtx->full_pwr_comp_var);
+ halStatus = sme_RequestFullPower(pHddCtx->hHal, hdd_full_pwr_cbk,
+ pHddCtx, eSME_FULL_PWR_NEEDED_BY_HDD);
+
+ if(halStatus != eHAL_STATUS_SUCCESS)
+ {
+ if(halStatus == eHAL_STATUS_PMC_PENDING)
+ {
+ //Block on a completion variable. Can't wait forever though
+ wait_for_completion_interruptible_timeout(
+ &pHddCtx->full_pwr_comp_var, msecs_to_jiffies(1000));
+ }
+ else
+ {
+ status = VOS_STATUS_E_FAILURE;
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Request for Full Power failed\n", __func__);
+ VOS_ASSERT(0);
+ return status;
+ }
+ }
+
+ status = VOS_STATUS_SUCCESS;
+ }
+
+ break;
+ }
+ return status;
+}
+
+hdd_adapter_t* hdd_open_adapter( hdd_context_t *pHddCtx, tANI_U8 session_type,
+ 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;
+
+ hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "%s iface =%s type = %d\n",__func__,iface_name,session_type);
+
+ //Disable BMPS incase of Concurrency
+ exitbmpsStatus = hdd_disable_bmps_imps(pHddCtx, session_type);
+
+ if(VOS_STATUS_E_FAILURE == exitbmpsStatus)
+ {
+ //Fail to Exit BMPS
+ VOS_ASSERT(0);
+ return NULL;
+ }
+
+ switch(session_type)
+ {
+ case WLAN_HDD_INFRA_STATION:
+#ifdef WLAN_FEATURE_P2P
+ case WLAN_HDD_P2P_CLIENT:
+#endif
+ {
+ pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );
+
+ if( NULL == pAdapter )
+ return NULL;
+
+#ifdef CONFIG_CFG80211
+ pAdapter->wdev.iftype = (session_type == WLAN_HDD_INFRA_STATION) ?
+ NL80211_IFTYPE_STATION :
+ NL80211_IFTYPE_P2P_CLIENT;
+#endif
+
+
+ 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);
+ goto err_free_netdev;
+ }
+ //Stop the Interface TX queue.
+ netif_tx_disable(pAdapter->dev);
+ //netif_tx_disable(pWlanDev);
+ netif_carrier_off(pAdapter->dev);
+
+ break;
+ }
+
+#ifdef WLAN_FEATURE_P2P
+ case WLAN_HDD_P2P_GO:
+#endif
+ case WLAN_HDD_SOFTAP:
+ {
+ pAdapter = hdd_wlan_create_ap_dev( pHddCtx, macAddr, (tANI_U8 *)iface_name );
+ if( NULL == pAdapter )
+ return NULL;
+
+#ifdef CONFIG_CFG80211
+ pAdapter->wdev.iftype = (session_type == WLAN_HDD_SOFTAP) ?
+ NL80211_IFTYPE_AP:
+ NL80211_IFTYPE_P2P_GO;
+#endif
+ 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);
+ goto err_free_netdev;
+ }
+
+ netif_tx_disable(pAdapter->dev);
+ netif_carrier_off(pAdapter->dev);
+
+ hdd_set_conparam( 1 );
+ break;
+ }
+ case WLAN_HDD_MONITOR:
+ {
+#ifdef CONFIG_CFG80211
+ pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );
+ if( NULL == pAdapter )
+ return NULL;
+
+ pAdapter->wdev.iftype = NL80211_IFTYPE_MONITOR;
+ pAdapter->device_mode = session_type;
+ status = hdd_register_interface( pAdapter, rtnl_held );
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)
+ pAdapter->dev->netdev_ops = &wlan_mon_drv_ops;
+#else
+ pAdapter->dev->open = hdd_mon_open;
+ pAdapter->dev->hard_start_xmit = hdd_mon_hard_start_xmit;
+#endif
+ 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);
+#ifdef WLAN_FEATURE_P2P
+ if (NULL == pAdapter->sessionCtx.monitor.pAdapterForTx)
+ {
+ pAdapter->sessionCtx.monitor.pAdapterForTx =
+ hdd_get_adapter(pAdapter->pHddCtx, WLAN_HDD_P2P_GO);
+ }
+#endif
+ /* This workqueue will be used to transmit management packet over
+ * monitor interface. */
+ INIT_WORK(&pAdapter->sessionCtx.monitor.pAdapterForTx->monTxWorkQueue,
+ hdd_mon_tx_work_queue);
+#endif
+ }
+ break;
+#ifdef ANI_MANF_DIAG
+ case WLAN_HDD_FTM:
+ {
+ pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );
+
+ if( NULL == pAdapter )
+ 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 );
+ }
+ break;
+#endif
+ default:
+ {
+ VOS_ASSERT(0);
+ return NULL;
+ }
+ }
+
+
+ if( VOS_STATUS_SUCCESS == status )
+ {
+ //Add it to the hdd's session list.
+ pHddAdapterNode = vos_mem_malloc( sizeof( hdd_adapter_list_node_t ) );
+ if( NULL == pHddAdapterNode )
+ {
+ status = VOS_STATUS_E_NOMEM;
+ }
+ else
+ {
+ pHddAdapterNode->pAdapter = pAdapter;
+ status = hdd_add_adapter_back ( pHddCtx,
+ pHddAdapterNode );
+ }
+ }
+
+ if( VOS_STATUS_SUCCESS != status )
+ {
+ if( NULL != pAdapter )
+ {
+ hdd_cleanup_adapter( pHddCtx, pAdapter, rtnl_held );
+ pAdapter = NULL;
+ }
+ if( NULL != pHddAdapterNode )
+ {
+ vos_mem_free( pHddAdapterNode );
+ }
+
+ goto resume_bmps;
+ }
+
+ if(VOS_STATUS_SUCCESS == status)
+ {
+ wlan_hdd_set_concurrency_mode(pHddCtx, session_type);
+
+#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
+ /* If there are concurrent session enable SW frame translation
+ * for all registered STA
+ * This is not required in case of PRIMA as HW frame translation
+ * is disabled in PRIMA*/
+ if (vos_concurrent_sessions_running())
+ {
+ WLANTL_ConfigureSwFrameTXXlationForAll(pHddCtx->pvosContext, TRUE);
+ }
+#endif
+ }
+
+ return pAdapter;
+
+err_free_netdev:
+ free_netdev(pAdapter->dev);
+ wlan_hdd_release_intf_addr( pHddCtx,
+ pAdapter->macAddressCurrent.bytes );
+
+resume_bmps:
+ //If bmps disabled enable it
+ if(VOS_STATUS_SUCCESS == exitbmpsStatus)
+ {
+ hdd_enable_bmps_imps(pHddCtx);
+ }
+ return NULL;
+}
+
+VOS_STATUS hdd_close_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter,
+ tANI_U8 rtnl_held )
+{
+ hdd_adapter_list_node_t *pAdapterNode, *pCurrent, *pNext;
+ VOS_STATUS status;
+
+ status = hdd_get_front_adapter ( pHddCtx, &pCurrent );
+ if( VOS_STATUS_SUCCESS != status )
+ return status;
+
+ while ( pCurrent->pAdapter != pAdapter )
+ {
+ status = hdd_get_next_adapter ( pHddCtx, pCurrent, &pNext );
+ if( VOS_STATUS_SUCCESS != status )
+ break;
+
+ pCurrent = pNext;
+ }
+ pAdapterNode = pCurrent;
+ if( VOS_STATUS_SUCCESS == status )
+ {
+ wlan_hdd_clear_concurrency_mode(pHddCtx, pAdapter->device_mode);
+ hdd_cleanup_adapter( pHddCtx, pAdapterNode->pAdapter, rtnl_held );
+ hdd_remove_adapter( pHddCtx, pAdapterNode );
+ vos_mem_free( pAdapterNode );
+
+#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
+ /* If there is no concurrent session disable SW frame translation
+ * for all registered STA */
+ /* This is not required in case of PRIMA as HW frame translation
+ * is disabled in PRIMA*/
+ if (!vos_concurrent_sessions_running())
+ {
+ WLANTL_ConfigureSwFrameTXXlationForAll(pHddCtx->pvosContext, FALSE);
+ }
+#endif
+
+ /* If there is a single session of STA/P2P client, re-enable BMPS */
+ if ((!vos_concurrent_sessions_running()) &&
+ ((pHddCtx->no_of_sessions[VOS_STA_MODE] >= 1) ||
+ (pHddCtx->no_of_sessions[VOS_P2P_CLIENT_MODE] >= 1)))
+ {
+ hdd_enable_bmps_imps(pHddCtx);
+ }
+
+ return VOS_STATUS_SUCCESS;
+ }
+
+ return VOS_STATUS_E_FAILURE;
+}
+
+VOS_STATUS hdd_close_all_adapters( hdd_context_t *pHddCtx )
+{
+ hdd_adapter_list_node_t *pHddAdapterNode;
+ VOS_STATUS status;
+
+ ENTER();
+
+ do
+ {
+ status = hdd_remove_front_adapter( pHddCtx, &pHddAdapterNode );
+ if( pHddAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ hdd_cleanup_adapter( pHddCtx, pHddAdapterNode->pAdapter, FALSE );
+ vos_mem_free( pHddAdapterNode );
+ }
+ }while( NULL != pHddAdapterNode && VOS_STATUS_E_EMPTY != status );
+
+ EXIT();
+
+ return VOS_STATUS_SUCCESS;
+}
+
+void wlan_hdd_reset_prob_rspies(hdd_adapter_t* pHostapdAdapter)
+{
+ v_U8_t addIE[1] = {0};
+
+ if ( eHAL_STATUS_FAILURE == ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal,
+ WNI_CFG_PROBE_RSP_ADDNIE_DATA1,(tANI_U8*)addIE, 0, NULL,
+ eANI_BOOLEAN_FALSE) )
+ {
+ hddLog(LOGE,
+ "Could not pass on WNI_CFG_PROBE_RSP_ADDNIE_DATA1 to CCM\n");
+ }
+
+ if ( eHAL_STATUS_FAILURE == ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal,
+ WNI_CFG_PROBE_RSP_ADDNIE_DATA2, (tANI_U8*)addIE, 0, NULL,
+ eANI_BOOLEAN_FALSE) )
+ {
+ hddLog(LOGE,
+ "Could not pass on WNI_CFG_PROBE_RSP_ADDNIE_DATA2 to CCM\n");
+ }
+
+ if ( eHAL_STATUS_FAILURE == ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal,
+ WNI_CFG_PROBE_RSP_ADDNIE_DATA3, (tANI_U8*)addIE, 0, NULL,
+ eANI_BOOLEAN_FALSE) )
+ {
+ hddLog(LOGE,
+ "Could not pass on WNI_CFG_PROBE_RSP_ADDNIE_DATA3 to CCM\n");
+ }
+}
+
+VOS_STATUS hdd_stop_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
+{
+ eHalStatus halStatus = eHAL_STATUS_SUCCESS;
+ hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
+ union iwreq_data wrqu;
+
+ ENTER();
+
+ switch(pAdapter->device_mode)
+ {
+ case WLAN_HDD_INFRA_STATION:
+ case WLAN_HDD_P2P_CLIENT:
+ if( hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR( pAdapter )) )
+ {
+ if (pWextState->roamProfile.BSSType == eCSR_BSS_TYPE_START_IBSS)
+ halStatus = sme_RoamDisconnect(pHddCtx->hHal,
+ pAdapter->sessionId,
+ eCSR_DISCONNECT_REASON_IBSS_LEAVE);
+ else
+ halStatus = sme_RoamDisconnect(pHddCtx->hHal,
+ pAdapter->sessionId,
+ eCSR_DISCONNECT_REASON_UNSPECIFIED);
+ //success implies disconnect command got queued up successfully
+ if(halStatus == eHAL_STATUS_SUCCESS)
+ {
+ wait_for_completion_interruptible_timeout(&pAdapter->disconnect_comp_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT));
+ }
+ memset(&wrqu, '\0', sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ memset(wrqu.ap_addr.sa_data,'\0',ETH_ALEN);
+ wireless_send_event(pAdapter->dev, SIOCGIWAP, &wrqu, NULL);
+ }
+ else
+ {
+ hdd_abort_mac_scan(pHddCtx);
+ }
+
+ if (test_bit(SME_SESSION_OPENED, &pAdapter->event_flags))
+ {
+ INIT_COMPLETION(pAdapter->session_close_comp_var);
+ if (eHAL_STATUS_SUCCESS ==
+ sme_CloseSession(pHddCtx->hHal, pAdapter->sessionId,
+ hdd_smeCloseSessionCallback, pAdapter))
+ {
+ //Block on a completion variable. Can't wait forever though.
+ wait_for_completion_interruptible_timeout(
+ &pAdapter->session_close_comp_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
+ }
+ }
+
+ break;
+
+ case WLAN_HDD_SOFTAP:
+ case WLAN_HDD_P2P_GO:
+ //Any softap specific cleanup here...
+ mutex_lock(&pHddCtx->sap_lock);
+ if (test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags))
+ {
+ VOS_STATUS status;
+ hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+
+ //Stop Bss.
+ status = WLANSAP_StopBss(pHddCtx->pvosContext);
+ if (VOS_IS_STATUS_SUCCESS(status))
+ {
+ hdd_hostapd_state_t *pHostapdState =
+ WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter);
+
+ status = vos_wait_single_event(&pHostapdState->vosEvent, 10000);
+
+ if (!VOS_IS_STATUS_SUCCESS(status))
+ {
+ hddLog(LOGE, "%s: failure waiting for WLANSAP_StopBss",
+ __FUNCTION__);
+ }
+ }
+ else
+ {
+ hddLog(LOGE, "%s: failure in WLANSAP_StopBss", __FUNCTION__);
+ }
+ clear_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags);
+
+ if (eHAL_STATUS_FAILURE ==
+ ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG,
+ 0, NULL, eANI_BOOLEAN_FALSE))
+ {
+ hddLog(LOGE,
+ "%s: Failed to set WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG",
+ __FUNCTION__);
+ }
+
+ if ( eHAL_STATUS_FAILURE == ccmCfgSetInt((WLAN_HDD_GET_CTX(pAdapter))->hHal,
+ WNI_CFG_ASSOC_RSP_ADDNIE_FLAG, 0, NULL,
+ eANI_BOOLEAN_FALSE) )
+ {
+ hddLog(LOGE,
+ "Could not pass on WNI_CFG_ASSOC_RSP_ADDNIE_FLAG to CCM");
+ }
+
+ // Reset WNI_CFG_PROBE_RSP Flags
+ wlan_hdd_reset_prob_rspies(pAdapter);
+ kfree(pAdapter->sessionCtx.ap.beacon);
+ pAdapter->sessionCtx.ap.beacon = NULL;
+ }
+ mutex_unlock(&pHddCtx->sap_lock);
+ break;
+ case WLAN_HDD_MONITOR:
+ break;
+ default:
+ break;
+ }
+
+ EXIT();
+ return VOS_STATUS_SUCCESS;
+}
+
+VOS_STATUS hdd_stop_all_adapters( hdd_context_t *pHddCtx )
+{
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ VOS_STATUS status;
+ hdd_adapter_t *pAdapter;
+
+ ENTER();
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+ netif_tx_disable(pAdapter->dev);
+ netif_carrier_off(pAdapter->dev);
+
+ hdd_stop_adapter( pHddCtx, pAdapter );
+
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+
+ EXIT();
+
+ return VOS_STATUS_SUCCESS;
+}
+
+VOS_STATUS hdd_reset_all_adapters( hdd_context_t *pHddCtx )
+{
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ VOS_STATUS status;
+ hdd_adapter_t *pAdapter;
+
+ ENTER();
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+ netif_tx_disable(pAdapter->dev);
+ netif_carrier_off(pAdapter->dev);
+
+ //Record whether STA is associated
+ pAdapter->sessionCtx.station.bSendDisconnect =
+ hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR( pAdapter )) ?
+ VOS_TRUE : VOS_FALSE;
+
+ hdd_deinit_tx_rx(pAdapter);
+ hdd_wmm_adapter_close(pAdapter);
+
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+
+ EXIT();
+
+ return VOS_STATUS_SUCCESS;
+}
+
+VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx )
+{
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ VOS_STATUS status;
+ hdd_adapter_t *pAdapter;
+ v_MACADDR_t bcastMac = VOS_MAC_ADDR_BROADCAST_INITIALIZER;
+
+ ENTER();
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+
+ switch(pAdapter->device_mode)
+ {
+ case WLAN_HDD_INFRA_STATION:
+ case WLAN_HDD_P2P_CLIENT:
+ hdd_init_station_mode(pAdapter);
+ /* Open the gates for HDD to receive Wext commands */
+ pAdapter->isLinkUpSvcNeeded = FALSE;
+ pAdapter->scan_info.mScanPending = FALSE;
+ pAdapter->scan_info.waitScanResult = FALSE;
+
+ //Trigger the initial scan
+ hdd_wlan_initial_scan(pAdapter);
+
+ //Indicate disconnect event to supplicant if associated previously
+ if(pAdapter->sessionCtx.station.bSendDisconnect)
+ {
+ union iwreq_data wrqu;
+ memset(&wrqu, '\0', sizeof(wrqu));
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+ memset(wrqu.ap_addr.sa_data,'\0',ETH_ALEN);
+ wireless_send_event(pAdapter->dev, SIOCGIWAP, &wrqu, NULL);
+ pAdapter->sessionCtx.station.bSendDisconnect = VOS_FALSE;
+
+#ifdef CONFIG_CFG80211
+ /* indicate disconnected event to nl80211 */
+ cfg80211_disconnected(pAdapter->dev, WLAN_REASON_UNSPECIFIED,
+ NULL, 0, GFP_KERNEL);
+#endif
+ }
+ break;
+
+ case WLAN_HDD_SOFTAP:
+ /* softAP can handle SSR */
+ break;
+
+ case WLAN_HDD_P2P_GO:
+#ifdef CONFIG_CFG80211
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s [SSR] send restart supplicant",
+ __func__);
+ /* event supplicant to restart */
+ cfg80211_del_sta(pAdapter->dev,
+ (const u8 *)&bcastMac.bytes[0], GFP_KERNEL);
+#endif
+ break;
+
+ case WLAN_HDD_MONITOR:
+ /* monitor interface start */
+ break;
+ default:
+ break;
+ }
+
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+
+ EXIT();
+
+ return VOS_STATUS_SUCCESS;
+}
+
+VOS_STATUS hdd_reconnect_all_adapters( hdd_context_t *pHddCtx )
+{
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ hdd_adapter_t *pAdapter;
+ VOS_STATUS status;
+ v_U32_t roamId;
+
+ ENTER();
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+
+ if( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
+ (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) )
+ {
+ hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
+ hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
+
+ pHddStaCtx->conn_info.connState = eConnectionState_NotConnected;
+ init_completion(&pAdapter->disconnect_comp_var);
+ sme_RoamDisconnect(pHddCtx->hHal, pAdapter->sessionId,
+ eCSR_DISCONNECT_REASON_UNSPECIFIED);
+
+ wait_for_completion_interruptible_timeout(
+ &pAdapter->disconnect_comp_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT));
+
+ pWextState->roamProfile.csrPersona = pAdapter->device_mode;
+ pHddCtx->isAmpAllowed = VOS_FALSE;
+ sme_RoamConnect(pHddCtx->hHal,
+ pAdapter->sessionId, &(pWextState->roamProfile),
+ &roamId);
+ }
+
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+
+ EXIT();
+
+ return VOS_STATUS_SUCCESS;
+}
+
+v_U8_t hdd_is_ssr_required( void)
+{
+ return isSsrRequired;
+}
+
+void hdd_set_ssr_required( v_U8_t value)
+{
+ isSsrRequired = value;
+}
+
+VOS_STATUS hdd_get_front_adapter( hdd_context_t *pHddCtx,
+ hdd_adapter_list_node_t** ppAdapterNode)
+{
+ VOS_STATUS status;
+ spin_lock(&pHddCtx->hddAdapters.lock);
+ status = hdd_list_peek_front ( &pHddCtx->hddAdapters,
+ (hdd_list_node_t**) ppAdapterNode );
+ spin_unlock(&pHddCtx->hddAdapters.lock);
+ return status;
+}
+
+VOS_STATUS hdd_get_next_adapter( hdd_context_t *pHddCtx,
+ hdd_adapter_list_node_t* pAdapterNode,
+ hdd_adapter_list_node_t** pNextAdapterNode)
+{
+ VOS_STATUS status;
+ spin_lock(&pHddCtx->hddAdapters.lock);
+ status = hdd_list_peek_next ( &pHddCtx->hddAdapters,
+ (hdd_list_node_t*) pAdapterNode,
+ (hdd_list_node_t**)pNextAdapterNode );
+
+ spin_unlock(&pHddCtx->hddAdapters.lock);
+ return status;
+}
+
+VOS_STATUS hdd_remove_adapter( hdd_context_t *pHddCtx,
+ hdd_adapter_list_node_t* pAdapterNode)
+{
+ VOS_STATUS status;
+ spin_lock(&pHddCtx->hddAdapters.lock);
+ status = hdd_list_remove_node ( &pHddCtx->hddAdapters,
+ &pAdapterNode->node );
+ spin_unlock(&pHddCtx->hddAdapters.lock);
+ return status;
+}
+
+VOS_STATUS hdd_remove_front_adapter( hdd_context_t *pHddCtx,
+ hdd_adapter_list_node_t** ppAdapterNode)
+{
+ VOS_STATUS status;
+ spin_lock(&pHddCtx->hddAdapters.lock);
+ status = hdd_list_remove_front( &pHddCtx->hddAdapters,
+ (hdd_list_node_t**) ppAdapterNode );
+ spin_unlock(&pHddCtx->hddAdapters.lock);
+ return status;
+}
+
+VOS_STATUS hdd_add_adapter_back( hdd_context_t *pHddCtx,
+ hdd_adapter_list_node_t* pAdapterNode)
+{
+ VOS_STATUS status;
+ spin_lock(&pHddCtx->hddAdapters.lock);
+ status = hdd_list_insert_back ( &pHddCtx->hddAdapters,
+ (hdd_list_node_t*) pAdapterNode );
+ spin_unlock(&pHddCtx->hddAdapters.lock);
+ return status;
+}
+
+VOS_STATUS hdd_add_adapter_front( hdd_context_t *pHddCtx,
+ hdd_adapter_list_node_t* pAdapterNode)
+{
+ VOS_STATUS status;
+ spin_lock(&pHddCtx->hddAdapters.lock);
+ status = hdd_list_insert_front ( &pHddCtx->hddAdapters,
+ (hdd_list_node_t*) pAdapterNode );
+ spin_unlock(&pHddCtx->hddAdapters.lock);
+ return status;
+}
+
+hdd_adapter_t * hdd_get_adapter_by_macaddr( hdd_context_t *pHddCtx,
+ tSirMacAddr macAddr )
+{
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ hdd_adapter_t *pAdapter;
+ VOS_STATUS status;
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+
+ if( pAdapter && vos_mem_compare( pAdapter->macAddressCurrent.bytes,
+ macAddr, sizeof(tSirMacAddr) ) )
+ {
+ return pAdapter;
+ }
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+
+ return NULL;
+
+}
+
+hdd_adapter_t * hdd_get_adapter_by_name( hdd_context_t *pHddCtx, tANI_U8 *name )
+{
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ hdd_adapter_t *pAdapter;
+ VOS_STATUS status;
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+
+ if( pAdapter && !strncmp( pAdapter->dev->name, (const char *)name,
+ IFNAMSIZ ) )
+ {
+ return pAdapter;
+ }
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+
+ return NULL;
+
+}
+
+hdd_adapter_t * hdd_get_adapter( hdd_context_t *pHddCtx, device_mode_t mode )
+{
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ hdd_adapter_t *pAdapter;
+ VOS_STATUS status;
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+
+ if( pAdapter && (mode == pAdapter->device_mode) )
+ {
+ return pAdapter;
+ }
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+
+ return NULL;
+
+}
+
+//Remove this function later
+hdd_adapter_t * hdd_get_mon_adapter( hdd_context_t *pHddCtx )
+{
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ hdd_adapter_t *pAdapter;
+ VOS_STATUS status;
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+
+ if( pAdapter && WLAN_HDD_MONITOR == pAdapter->device_mode )
+ {
+ return pAdapter;
+ }
+
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+
+ return NULL;
+
+}
+
+#ifdef CONFIG_CFG80211
+/**---------------------------------------------------------------------------
+
+ \brief hdd_set_monitor_tx_adapter() -
+
+ This API initializes the adapter to be used while transmitting on monitor
+ adapter.
+
+ \param - pHddCtx - Pointer to the HDD context.
+ pAdapter - Adapter that will used for TX. This can be NULL.
+ \return - None.
+ --------------------------------------------------------------------------*/
+void wlan_hdd_set_monitor_tx_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
+{
+ hdd_adapter_t *pMonAdapter;
+
+ pMonAdapter = hdd_get_adapter( pHddCtx, WLAN_HDD_MONITOR );
+
+ if( NULL != pMonAdapter )
+ {
+ pMonAdapter->sessionCtx.monitor.pAdapterForTx = pAdapter;
+ }
+}
+#endif
+/**---------------------------------------------------------------------------
+
+ \brief hdd_select_queue() -
+
+ This API returns the operating channel of the requested device mode
+
+ \param - pHddCtx - Pointer to the HDD context.
+ - mode - Device mode for which operating channel is required
+ suported modes - WLAN_HDD_INFRA_STATION, WLAN_HDD_P2P_CLIENT
+ WLAN_HDD_SOFTAP, WLAN_HDD_P2P_GO.
+ \return - channel number. "0" id the requested device is not found OR it is not connected.
+ --------------------------------------------------------------------------*/
+v_U8_t hdd_get_operating_channel( hdd_context_t *pHddCtx, device_mode_t mode )
+{
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ VOS_STATUS status;
+ hdd_adapter_t *pAdapter;
+ v_U8_t operatingChannel = 0;
+
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+
+ if( mode == pAdapter->device_mode )
+ {
+ switch(pAdapter->device_mode)
+ {
+ case WLAN_HDD_INFRA_STATION:
+ case WLAN_HDD_P2P_CLIENT:
+ if( hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR( pAdapter )) )
+ operatingChannel = (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.operationChannel;
+ break;
+ case WLAN_HDD_SOFTAP:
+ case WLAN_HDD_P2P_GO:
+ /*softap connection info */
+ if(test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags))
+ operatingChannel = (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->operatingChannel;
+ break;
+ default:
+ break;
+ }
+
+ break; //Found the device of interest. break the loop
+ }
+
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+ return operatingChannel;
+}
+
+#ifdef WLAN_FEATURE_PACKET_FILTERING
+/**---------------------------------------------------------------------------
+
+ \brief hdd_set_multicast_list() -
+
+ This used to set the multicast address list.
+
+ \param - dev - Pointer to the WLAN device.
+ - skb - Pointer to OS packet (sk_buff).
+ \return - success/fail
+
+ --------------------------------------------------------------------------*/
+static void hdd_set_multicast_list(struct net_device *dev)
+{
+ hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
+ hdd_context_t *pHddCtx;
+ int mc_count;
+ int i = 0;
+ struct netdev_hw_addr *ha;
+ pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
+ if (NULL == pHddCtx)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: HDD context is Null", __FUNCTION__);
+ return;
+ }
+
+ if (dev->flags & IFF_ALLMULTI)
+ {
+ hddLog(VOS_TRACE_LEVEL_INFO,
+ "%s: allow all multicast frames", __FUNCTION__);
+ pHddCtx->mc_addr_list.mc_cnt = 0;
+ }
+ else
+ {
+ mc_count = netdev_mc_count(dev);
+ hddLog(VOS_TRACE_LEVEL_INFO,
+ "%s: mc_count = %u", __FUNCTION__, mc_count);
+ if (mc_count > WLAN_HDD_MAX_MC_ADDR_LIST)
+ {
+ hddLog(VOS_TRACE_LEVEL_INFO,
+ "%s: No free filter available; allow all multicast frames", __FUNCTION__);
+ pHddCtx->mc_addr_list.mc_cnt = 0;
+ return;
+ }
+
+ pHddCtx->mc_addr_list.mc_cnt = mc_count;
+
+ netdev_for_each_mc_addr(ha, dev) {
+ if (i == mc_count)
+ break;
+ memset(&(pHddCtx->mc_addr_list.addr[i][0]), 0, ETH_ALEN);
+ memcpy(&(pHddCtx->mc_addr_list.addr[i][0]), ha->addr, ETH_ALEN);
+ hddLog(VOS_TRACE_LEVEL_INFO, "\n%s: mlist[%d] = %02x:%02x:%02x:%02x:%02x:%02x",
+ __func__, i,
+ pHddCtx->mc_addr_list.addr[i][0], pHddCtx->mc_addr_list.addr[i][1],
+ pHddCtx->mc_addr_list.addr[i][2], pHddCtx->mc_addr_list.addr[i][3],
+ pHddCtx->mc_addr_list.addr[i][4], pHddCtx->mc_addr_list.addr[i][5]);
+ i++;
+ }
+ }
+ return;
+}
+#endif
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_select_queue() -
+
+ This function is registered with the Linux OS for network
+ core to decide which queue to use first.
+
+ \param - dev - Pointer to the WLAN device.
+ - skb - Pointer to OS packet (sk_buff).
+ \return - ac, Queue Index/access category corresponding to UP in IP header
+
+ --------------------------------------------------------------------------*/
+v_U16_t hdd_select_queue(struct net_device *dev,
+ struct sk_buff *skb)
+{
+ return hdd_wmm_select_queue(dev, skb);
+}
+
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_wlan_initial_scan() -
+
+ This function triggers the initial scan
+
+ \param - pAdapter - Pointer to the HDD adapter.
+
+ --------------------------------------------------------------------------*/
+void hdd_wlan_initial_scan(hdd_adapter_t *pAdapter)
+{
+ tCsrScanRequest scanReq;
+ tCsrChannelInfo channelInfo;
+ eHalStatus halStatus;
+ unsigned long scanId;
+ hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
+
+ vos_mem_zero(&scanReq, sizeof(tCsrScanRequest));
+ vos_mem_set(&scanReq.bssid, sizeof(tCsrBssid), 0xff);
+ scanReq.BSSType = eCSR_BSS_TYPE_ANY;
+
+ if(sme_Is11dSupported(pHddCtx->hHal))
+ {
+ halStatus = sme_ScanGetBaseChannels( pHddCtx->hHal, &channelInfo );
+ if ( HAL_STATUS_SUCCESS( halStatus ) )
+ {
+ scanReq.ChannelInfo.ChannelList = vos_mem_malloc(channelInfo.numOfChannels);
+ if( !scanReq.ChannelInfo.ChannelList )
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s kmalloc failed", __func__);
+ vos_mem_free(channelInfo.ChannelList);
+ return;
+ }
+ vos_mem_copy(scanReq.ChannelInfo.ChannelList, channelInfo.ChannelList,
+ channelInfo.numOfChannels);
+ scanReq.ChannelInfo.numOfChannels = channelInfo.numOfChannels;
+ vos_mem_free(channelInfo.ChannelList);
+ }
+
+ scanReq.scanType = eSIR_PASSIVE_SCAN;
+ scanReq.requestType = eCSR_SCAN_REQUEST_11D_SCAN;
+ scanReq.maxChnTime = pHddCtx->cfg_ini->nPassiveMaxChnTime;
+ scanReq.minChnTime = pHddCtx->cfg_ini->nPassiveMinChnTime;
+ }
+ else
+ {
+ scanReq.scanType = eSIR_ACTIVE_SCAN;
+ scanReq.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
+ scanReq.maxChnTime = pHddCtx->cfg_ini->nActiveMaxChnTime;
+ scanReq.minChnTime = pHddCtx->cfg_ini->nActiveMinChnTime;
+ }
+
+ halStatus = sme_ScanRequest(pHddCtx->hHal, pAdapter->sessionId, &scanReq, &scanId, NULL, NULL);
+ if ( !HAL_STATUS_SUCCESS( halStatus ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: sme_ScanRequest failed status code %d",
+ __func__, halStatus );
+ }
+
+ if(sme_Is11dSupported(pHddCtx->hHal))
+ vos_mem_free(scanReq.ChannelInfo.ChannelList);
+}
+
+struct fullPowerContext
+{
+ struct completion completion;
+ unsigned int magic;
+};
+#define POWER_CONTEXT_MAGIC 0x504F5752 //POWR
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_full_power_callback() - HDD full power callback function
+
+ This is the function invoked by SME to inform the result of a full power
+ request issued by HDD
+
+ \param - callbackcontext - Pointer to cookie
+ \param - status - result of request
+
+ \return - None
+
+ --------------------------------------------------------------------------*/
+static void hdd_full_power_callback(void *callbackContext, eHalStatus status)
+{
+ struct fullPowerContext *pContext = callbackContext;
+
+ hddLog(VOS_TRACE_LEVEL_INFO,
+ "%s: context = %p, status = %d", pContext, status);
+
+ if (NULL == callbackContext)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: Bad param, context [%p]",
+ __FUNCTION__, callbackContext);
+ return;
+ }
+
+ /* there is a race condition that exists between this callback function
+ and the caller since the caller could time out either before or
+ while this code is executing. we'll assume the timeout hasn't
+ occurred, but we'll verify that right before we save our work */
+
+ if (POWER_CONTEXT_MAGIC != pContext->magic)
+ {
+ /* the caller presumably timed out so there is nothing we can do */
+ hddLog(VOS_TRACE_LEVEL_WARN,
+ "%s: Invalid context, magic [%08x]",
+ __FUNCTION__, pContext->magic);
+ return;
+ }
+
+ /* the race is on. caller could have timed out immediately after
+ we verified the magic, but if so, caller will wait a short time
+ for us to notify the caller, so the context will stay valid */
+ complete(&pContext->completion);
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_wlan_exit() - HDD WLAN exit function
+
+ This is the driver exit point (invoked during rmmod)
+
+ \param - pHddCtx - Pointer to the HDD Context
+
+ \return - None
+
+ --------------------------------------------------------------------------*/
+void hdd_wlan_exit(hdd_context_t *pHddCtx)
+{
+ eHalStatus halStatus;
+ v_CONTEXT_t pVosContext = pHddCtx->pvosContext;
+ VOS_STATUS vosStatus;
+#ifdef ANI_BUS_TYPE_SDIO
+ struct sdio_func *sdio_func_dev = NULL;
+#endif // ANI_BUS_TYPE_SDIO
+#ifdef CONFIG_CFG80211
+ struct wiphy *wiphy = pHddCtx->wiphy;
+#endif
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+ hdd_adapter_t* pAdapter;
+#endif
+ struct fullPowerContext powerContext;
+ long lrc;
+
+ ENTER();
+
+#ifdef CONFIG_CFG80211
+#ifdef WLAN_SOFTAP_FEATURE
+ if (VOS_STA_SAP_MODE != hdd_get_conparam())
+#endif
+ {
+#ifdef ANI_MANF_DIAG
+ if (VOS_FTM_MODE != hdd_get_conparam())
+#endif /* ANI_MANF_DIAG */
+ {
+ hdd_adapter_t* pAdapter = hdd_get_adapter(pHddCtx,
+ WLAN_HDD_INFRA_STATION);
+ if (pAdapter == NULL)
+ pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_P2P_CLIENT);
+
+ if (pAdapter != NULL)
+ {
+ wlan_hdd_cfg80211_pre_voss_stop(pAdapter);
+ hdd_UnregisterWext(pAdapter->dev);
+ }
+ }
+ }
+#endif
+
+#ifdef ANI_MANF_DIAG
+ if (VOS_FTM_MODE == hdd_get_conparam())
+ {
+ wlan_hdd_ftm_close(pHddCtx);
+ goto free_hdd_ctx;
+ }
+#endif
+ //Stop the Interface TX queue.
+ //netif_tx_disable(pWlanDev);
+ //netif_carrier_off(pWlanDev);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ // unregister suspend/resume callbacks
+ if(pHddCtx->cfg_ini->nEnableSuspend)
+ {
+ unregister_wlan_suspend();
+ }
+#endif
+
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+#ifdef WLAN_SOFTAP_FEATURE
+ if (VOS_STA_SAP_MODE == hdd_get_conparam())
+ {
+ pAdapter = hdd_get_adapter(pHddCtx,
+ WLAN_HDD_SOFTAP);
+ }
+ else
+ {
+#endif
+#ifdef ANI_MANF_DIAG
+ if (VOS_FTM_MODE != hdd_get_conparam())
+#endif /* ANI_MANF_DIAG */
+ {
+ pAdapter = hdd_get_adapter(pHddCtx,
+ WLAN_HDD_INFRA_STATION);
+ }
+#ifdef WLAN_SOFTAP_FEATURE
+ }
+#endif
+ /* DeRegister with platform driver as client for Suspend/Resume */
+ vosStatus = hddDeregisterPmOps(pHddCtx);
+ if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDeregisterPmOps failed",__func__);
+ VOS_ASSERT(0);
+ }
+
+ vosStatus = hddDevTmUnregisterNotifyCallback(pHddCtx);
+ if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDevTmUnregisterNotifyCallback failed",__func__);
+ }
+#endif //FEATURE_WLAN_INTEGRATED_SOC
+
+ // Cancel any outstanding scan requests. We are about to close all
+ // of our adapters, but an adapter structure is what SME passes back
+ // to our callback function. Hence if there are any outstanding scan
+ // requests then there is a race condition between when the adapter
+ // is closed and when the callback is invoked. We try to resolve that
+ // race condition here by canceling any outstanding scans before we
+ // close the adapters.
+ // Note that the scans may be cancelled in an asynchronous manner, so
+ // ideally there needs to be some kind of synchronization. Rather than
+ // introduce a new synchronization here, we will utilize the fact that
+ // we are about to Request Full Power, and since that is synchronized,
+ // the expectation is that by the time Request Full Power has completed,
+ // all scans will be cancelled.
+ hdd_abort_mac_scan( pHddCtx );
+
+ //Disable IMPS/BMPS as we do not want the device to enter any power
+ //save mode during shutdown
+ sme_DisablePowerSave(pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE);
+ sme_DisablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE);
+ sme_DisablePowerSave(pHddCtx->hHal, ePMC_UAPSD_MODE_POWER_SAVE);
+
+ //Ensure that device is in full power as we will touch H/W during vos_Stop
+ init_completion(&powerContext.completion);
+ powerContext.magic = POWER_CONTEXT_MAGIC;
+
+ halStatus = sme_RequestFullPower(pHddCtx->hHal, hdd_full_power_callback,
+ &powerContext, eSME_FULL_PWR_NEEDED_BY_HDD);
+
+ if (eHAL_STATUS_SUCCESS != halStatus)
+ {
+ if (eHAL_STATUS_PMC_PENDING == halStatus)
+ {
+ /* request was sent -- wait for the response */
+ lrc = wait_for_completion_interruptible_timeout(
+ &powerContext.completion,
+ msecs_to_jiffies(WLAN_WAIT_TIME_POWER));
+ /* either we have a response or we timed out
+ either way, first invalidate our magic */
+ powerContext.magic = 0;
+ if (lrc <= 0)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: %s while requesting full power",
+ __FUNCTION__, (0 == lrc) ? "timeout" : "interrupt");
+ /* there is a race condition such that the callback
+ function could be executing at the same time we are. of
+ primary concern is if the callback function had already
+ verified the "magic" but hasn't yet set the completion
+ variable. Since the completion variable is on our
+ stack, we'll delay just a bit to make sure the data is
+ still valid if that is the case */
+ msleep(50);
+ }
+ }
+ else
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: Request for Full Power failed, status %d",
+ __FUNCTION__, halStatus);
+ VOS_ASSERT(0);
+ /* continue -- need to clean up as much as possible */
+ }
+ }
+
+ // Unregister the Net Device Notifier
+ unregister_netdevice_notifier(&hdd_netdev_notifier);
+
+#ifdef WLAN_FEATURE_P2P
+ if (pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated)
+ {
+ hdd_adapter_t* pAdapter = hdd_get_adapter(pHddCtx,
+ WLAN_HDD_INFRA_STATION);
+ if (pAdapter != NULL)
+ {
+ INIT_COMPLETION(pAdapter->session_close_comp_var);
+ if( eHAL_STATUS_SUCCESS == sme_CloseSession( pHddCtx->hHal,
+ pAdapter->p2pSessionId,
+ hdd_smeCloseSessionCallback, pAdapter ) )
+ {
+ //Block on a completion variable. Can't wait forever though.
+ wait_for_completion_interruptible_timeout(
+ &pAdapter->session_close_comp_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
+ }
+ }
+ }
+#endif
+ hdd_stop_all_adapters( pHddCtx );
+
+#ifdef ANI_BUS_TYPE_SDIO
+ sdio_func_dev = libra_getsdio_funcdev();
+
+ if(sdio_func_dev == NULL)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: sdio_func_dev is NULL!",__func__);
+ VOS_ASSERT(0);
+ return;
+ }
+
+ sd_claim_host(sdio_func_dev);
+
+ /* Disable SDIO IRQ since we are exiting */
+ libra_enable_sdio_irq(sdio_func_dev, 0);
+
+ sd_release_host(sdio_func_dev);
+#endif // ANI_BUS_TYPE_SDIO
+
+#ifdef WLAN_BTAMP_FEATURE
+ vosStatus = WLANBAP_Stop(pVosContext);
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to stop BAP",__func__);
+ }
+#endif //WLAN_BTAMP_FEATURE
+
+ //Stop all the modules
+ vosStatus = vos_stop( pVosContext );
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: Failed to stop VOSS",__func__);
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
+ }
+
+#ifdef ANI_BUS_TYPE_SDIO
+ vosStatus = WLANBAL_Stop( pVosContext );
+
+ hddLog(VOS_TRACE_LEVEL_ERROR,"WLAN BAL STOP\n");
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: Failed to stop BAL",__func__);
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
+ }
+
+ msleep(50);
+ //Put the chip is standby before asserting deep sleep
+ vosStatus = WLANBAL_SuspendChip( pVosContext );
+
+ hddLog(VOS_TRACE_LEVEL_ERROR,"WLAN Suspend Chip\n");
+
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: Failed to suspend chip ",__func__);
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
+ }
+ //Invoke SAL stop
+ vosStatus = WLANSAL_Stop( pVosContext );
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: Failed to stop SAL",__func__);
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
+ }
+
+#endif // ANI_BUS_TYPE_SDIO
+
+ //Assert Deep sleep signal now to put Libra HW in lowest power state
+ vosStatus = vos_chipAssertDeepSleep( NULL, NULL, NULL );
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
+
+ //Vote off any PMIC voltage supplies
+ vos_chipPowerDown(NULL, NULL, NULL);
+
+ vos_chipVoteOffXOBuffer(NULL, NULL, NULL);
+
+ //Clean up HDD Nlink Service
+ send_btc_nlink_msg(WLAN_MODULE_DOWN_IND, 0);
+ nl_srv_exit();
+
+ //This requires pMac access, Call this before vos_close().
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ hdd_unregister_mcast_bcast_filter(pHddCtx);
+#endif
+
+ //Close the scheduler before calling vos_close to make sure no thread is
+ // scheduled after the each module close is called i.e after all the data
+ // structures are freed.
+ vosStatus = vos_sched_close( pVosContext );
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus)) {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: Failed to close VOSS Scheduler",__func__);
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
+ }
+
+
+ //Close VOSS
+ //This frees pMac(HAL) context. There should not be any call that requires pMac access after this.
+ vos_close(pVosContext);
+
+#ifdef ANI_BUS_TYPE_SDIO
+ vosStatus = WLANBAL_Close(pVosContext);
+ if (!VOS_IS_STATUS_SUCCESS(vosStatus))
+ {
+ VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
+ "%s: Failed to close BAL",__func__);
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
+ }
+ hddLog(VOS_TRACE_LEVEL_ERROR,"Returned WLAN BAL CLOSE\n\n\n\n");
+#endif // ANI_BUS_TYPE_SDIO
+
+ //Close Watchdog
+ if(pHddCtx->cfg_ini->fIsLogpEnabled)
+ vos_watchdog_close(pVosContext);
+
+ /* Cancel the vote for XO Core ON.
+ * This is done here to ensure there is no race condition since MC, TX and WD threads have
+ * exited at this point
+ */
+ hddLog(VOS_TRACE_LEVEL_WARN, "In module exit: Cancel the vote for XO Core ON"
+ " when WLAN is turned OFF\n");
+ if (vos_chipVoteXOCore(NULL, NULL, NULL, VOS_FALSE) != VOS_STATUS_SUCCESS)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, "Could not cancel the vote for XO Core ON."
+ " Not returning failure."
+ " Power consumed will be high\n");
+ }
+
+ hdd_close_all_adapters( pHddCtx );
+
+
+ //Free up dynamically allocated members inside HDD Adapter
+ kfree(pHddCtx->cfg_ini);
+ pHddCtx->cfg_ini= NULL;
+
+ /* free the power on lock from platform driver */
+ if (free_riva_power_on_lock("wlan"))
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, "%s: failed to free power on lock",
+ __func__);
+ }
+
+#ifdef ANI_MANF_DIAG
+free_hdd_ctx:
+#endif
+#ifdef CONFIG_CFG80211
+ wiphy_unregister(wiphy) ;
+ wiphy_free(wiphy) ;
+#else
+ vos_mem_free( pHddCtx );
+#endif
+ if (hdd_is_ssr_required())
+ {
+ /* WDI timeout had happened during unload, so SSR is needed here */
+ subsystem_restart("riva");
+ msleep(5000);
+ }
+ hdd_set_ssr_required (VOS_FALSE);
+}
+
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_update_config_from_nv() - Function to update the contents of
+ the running configuration with parameters taken from NV storage
+
+ \param - pHddCtx - Pointer to the HDD global context
+
+ \return - VOS_STATUS_SUCCESS if successful
+
+ --------------------------------------------------------------------------*/
+static VOS_STATUS hdd_update_config_from_nv(hdd_context_t* pHddCtx)
+{
+#ifndef FEATURE_WLAN_INTEGRATED_SOC
+ eHalStatus halStatus;
+#endif
+
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+ v_BOOL_t itemIsValid = VOS_FALSE;
+ VOS_STATUS status;
+ v_MACADDR_t macFromNV[VOS_MAX_CONCURRENCY_PERSONA];
+ v_U8_t macLoop;
+
+ /*If the NV is valid then get the macaddress from nv else get it from qcom_cfg.ini*/
+ status = vos_nv_getValidity(VNV_FIELD_IMAGE, &itemIsValid);
+ if(status != VOS_STATUS_SUCCESS)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR," vos_nv_getValidity() failed\n ");
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ if (itemIsValid == VOS_TRUE)
+ {
+ hddLog(VOS_TRACE_LEVEL_INFO_HIGH," Reading the Macaddress from NV\n ");
+ status = vos_nv_readMultiMacAddress((v_U8_t *)&macFromNV[0].bytes[0],
+ VOS_MAX_CONCURRENCY_PERSONA);
+ if(status != VOS_STATUS_SUCCESS)
+ {
+ /* Get MAC from NV fail, not update CFG info
+ * INI MAC value will be used for MAC setting */
+ hddLog(VOS_TRACE_LEVEL_ERROR," vos_nv_readMacAddress() failed\n ");
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ /* If first MAC is not valid, treat all others are not valid
+ * Then all MACs will be got from ini file */
+ if(vos_is_macaddr_zero(&macFromNV[0]))
+ {
+ /* MAC address in NV file is not configured yet */
+ hddLog(VOS_TRACE_LEVEL_WARN, "Invalid MAC in NV file");
+ return VOS_STATUS_E_INVAL;
+ }
+
+ /* Get MAC address from NV, update CFG info */
+ for(macLoop = 0; macLoop < VOS_MAX_CONCURRENCY_PERSONA; macLoop++)
+ {
+ if(vos_is_macaddr_zero(&macFromNV[macLoop]))
+ {
+ printk(KERN_ERR "not valid MAC from NV for %d", macLoop);
+ /* This MAC is not valid, skip it
+ * This MAC will be got from ini file */
+ }
+ else
+ {
+ vos_mem_copy((v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[macLoop].bytes[0],
+ (v_U8_t *)&macFromNV[macLoop].bytes[0],
+ VOS_MAC_ADDR_SIZE);
+ }
+ }
+ }
+ else
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, "NV ITEM, MAC Not valid");
+ return VOS_STATUS_E_FAILURE;
+ }
+#endif /* FEATURE_WLAN_INTEGRATED_SOC */
+
+#ifndef FEATURE_WLAN_INTEGRATED_SOC
+#if 1 /* need to fix for concurrency */
+ // Set the MAC Address
+ // Currently this is used by HAL to add self sta. Remove this once self sta is added as part of session open.
+ halStatus = ccmCfgSetStr( pHddCtx->hHal, WNI_CFG_STA_ID,
+ (v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[0],
+ sizeof( pHddCtx->cfg_ini->intfMacAddr[0]),
+ hdd_set_mac_addr_cb, VOS_FALSE );
+
+ if (!HAL_STATUS_SUCCESS( halStatus ))
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed to set MAC Address. "
+ "HALStatus is %08d [x%08x]",__func__, halStatus, halStatus );
+ return VOS_STATUS_E_FAILURE;
+ }
+#endif
+#endif
+
+ return VOS_STATUS_SUCCESS;
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_post_voss_start_config() - HDD post voss start config helper
+
+ \param - pAdapter - Pointer to the HDD
+
+ \return - None
+
+ --------------------------------------------------------------------------*/
+VOS_STATUS hdd_post_voss_start_config(hdd_context_t* pHddCtx)
+{
+ eHalStatus halStatus;
+ v_U32_t listenInterval;
+
+#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
+ /* In the non-integrated architecture we update the configuration from
+ the INI file and from NV after vOSS has been started
+ */
+
+ // Apply the cfg.ini to cfg.dat
+ if (FALSE == hdd_update_config_dat(pHddCtx))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: config update failed",__func__ );
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ // Apply the NV to cfg.dat
+ if (VOS_STATUS_SUCCESS != hdd_update_config_from_nv(pHddCtx))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: config update from NV failed", __func__ );
+ return VOS_STATUS_E_FAILURE;
+ }
+#endif // FEATURE_WLAN_NON_INTEGRATED_SOC
+
+ // Send ready indication to the HDD. This will kick off the MAC
+ // into a 'running' state and should kick off an initial scan.
+ halStatus = sme_HDDReadyInd( pHddCtx->hHal );
+ if ( !HAL_STATUS_SUCCESS( halStatus ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%S: sme_HDDReadyInd() failed with status "
+ "code %08d [x%08x]",__func__, halStatus, halStatus );
+ return VOS_STATUS_E_FAILURE;
+ }
+
+ // Set default LI into HDD context,
+ // otherwise under some race condition, HDD will set 0 LI value into RIVA,
+ // And RIVA will crash
+ wlan_cfgGetInt(pHddCtx->hHal, WNI_CFG_LISTEN_INTERVAL, &listenInterval);
+ pHddCtx->hdd_actual_LI_value = listenInterval;
+
+ return VOS_STATUS_SUCCESS;
+}
+
+#ifdef ANI_BUS_TYPE_SDIO
+
+#ifndef ANI_MANF_DIAG
+// Routine to initialize the PMU
+void wlan_hdd_enable_deepsleep(v_VOID_t * pVosContext)
+{
+/*-------------- Need to fix this correctly while doing Deepsleep testing
+ tANI_U32 regValue = 0;
+
+ regValue = QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_DEEP_SLEEP_EN_MASK |
+ QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_1P23_LPM_AON_MASK_MASK |
+ QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_1P23_LPM_SW_MASK_MASK |
+ QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_2P3_LPM_MASK_MASK;
+
+ WLANBAL_WriteRegister(pVosContext, QWLAN_PMU_LDO_CTRL_REG_REG, regValue);
+---------------------*/
+
+ return;
+}
+#endif
+#endif
+
+/* wake lock APIs for HDD */
+void hdd_prevent_suspend(void)
+{
+ wake_lock(&wlan_wake_lock);
+}
+
+void hdd_allow_suspend(void)
+{
+ wake_unlock(&wlan_wake_lock);
+}
+
+/**---------------------------------------------------------------------------
+
+ \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 -1 for failure
+
+ --------------------------------------------------------------------------*/
+
+int hdd_wlan_startup(struct device *dev )
+{
+ VOS_STATUS status;
+ hdd_adapter_t *pAdapter = NULL;
+ 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
+ int ret;
+#ifdef CONFIG_CFG80211
+ struct wiphy *wiphy;
+#endif
+#ifdef ANI_BUS_TYPE_SDIO
+ struct sdio_func *sdio_func_dev = dev_to_sdio_func(dev);
+#endif //ANI_BUS_TYPE_SDIO
+
+ ENTER();
+#ifdef CONFIG_CFG80211
+ /*
+ * cfg80211: wiphy allocation
+ */
+ wiphy = wlan_hdd_cfg80211_init(sizeof(hdd_context_t)) ;
+
+ if(wiphy == NULL)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
+ return -1;
+ }
+
+ pHddCtx = wiphy_priv(wiphy);
+
+#else
+
+ pHddCtx = vos_mem_malloc ( sizeof( hdd_context_t ) );
+ if(pHddCtx == NULL)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
+ return -1;
+ }
+
+#endif
+ //Initialize the adapter context to zeros.
+ vos_mem_zero(pHddCtx, sizeof( hdd_context_t ));
+
+#ifdef CONFIG_CFG80211
+ pHddCtx->wiphy = wiphy;
+#endif
+ hdd_prevent_suspend();
+ pHddCtx->isLoadUnloadInProgress = TRUE;
+
+ vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE);
+
+ /*Get vos context here bcoz vos_open requires it*/
+ pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+
+ //Save the Global VOSS context in adapter context for future.
+ pHddCtx->pvosContext = pVosContext;
+
+ //Save the adapter context in global context for future.
+ ((VosContextType*)(pVosContext))->pHDDContext = (v_VOID_t*)pHddCtx;
+
+#ifdef ANI_BUS_TYPE_SDIO
+ // Set the private data for the device to our adapter.
+ libra_sdio_setprivdata (sdio_func_dev, pHddCtx);
+ atomic_set(&pHddCtx->sdio_claim_count, 0);
+#endif // ANI_BUS_TYPE_SDIO
+
+ pHddCtx->parent_dev = dev;
+
+ init_completion(&pHddCtx->full_pwr_comp_var);
+ init_completion(&pHddCtx->standby_comp_var);
+ init_completion(&pHddCtx->req_bmps_comp_var);
+
+
+ hdd_list_init( &pHddCtx->hddAdapters, MAX_NUMBER_OF_ADAPTERS );
+
+ // Load all config first as TL config is needed during vos_open
+ pHddCtx->cfg_ini = (hdd_config_t*) kmalloc(sizeof(hdd_config_t), GFP_KERNEL);
+ if(pHddCtx->cfg_ini == NULL)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed kmalloc hdd_config_t",__func__);
+ goto err_free_hdd_context;
+ }
+
+ vos_mem_zero(pHddCtx->cfg_ini, sizeof( hdd_config_t ));
+
+ // Read and parse the qcom_cfg.ini file
+ status = hdd_parse_config_ini( pHddCtx );
+ if ( VOS_STATUS_SUCCESS != status )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: error parsing %s",
+ __func__, WLAN_INI_FILE);
+ goto err_config;
+ }
+
+#ifdef CONFIG_CFG80211
+ /*
+ * cfg80211: Initialization and registration ...
+ */
+ if (0 < wlan_hdd_cfg80211_register(dev, wiphy, pHddCtx->cfg_ini))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: wlan_hdd_cfg80211_register return failure", __func__);
+ goto err_wiphy_reg;
+ }
+#endif
+
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+ // Update WDI trace levels based upon the cfg.ini
+ hdd_wdi_trace_enable(eWLAN_MODULE_DAL,
+ pHddCtx->cfg_ini->wdiTraceEnableDAL);
+ hdd_wdi_trace_enable(eWLAN_MODULE_DAL_CTRL,
+ pHddCtx->cfg_ini->wdiTraceEnableCTL);
+ hdd_wdi_trace_enable(eWLAN_MODULE_DAL_DATA,
+ pHddCtx->cfg_ini->wdiTraceEnableDAT);
+ hdd_wdi_trace_enable(eWLAN_MODULE_PAL,
+ pHddCtx->cfg_ini->wdiTraceEnablePAL);
+#endif /* FEATURE_WLAN_INTEGRATED_SOC */
+
+#ifdef ANI_MANF_DIAG
+ if(VOS_FTM_MODE == hdd_get_conparam())
+ {
+ if ( VOS_STATUS_SUCCESS != wlan_hdd_ftm_open(pHddCtx) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: wlan_hdd_ftm_open Failed",__func__);
+ goto err_free_hdd_context;
+ }
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: FTM driver loaded success fully",__func__);
+ return VOS_STATUS_SUCCESS;
+ }
+#endif
+
+ //Open watchdog module
+ if(pHddCtx->cfg_ini->fIsLogpEnabled)
+ {
+ status = vos_watchdog_open(pVosContext,
+ &((VosContextType*)pVosContext)->vosWatchdog, sizeof(VosWatchdogContext));
+
+ if(!VOS_IS_STATUS_SUCCESS( status ))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_watchdog_open failed",__func__);
+#ifdef CONFIG_CFG80211
+ goto err_wiphy_reg;
+#else
+ goto err_config;
+#endif
+ }
+ }
+
+ pHddCtx->isLogpInProgress = FALSE;
+ vos_set_logp_in_progress(VOS_MODULE_ID_VOSS, FALSE);
+
+#ifdef ANI_BUS_TYPE_SDIO
+ status = WLANBAL_Open(pHddCtx->pvosContext);
+ if(!VOS_IS_STATUS_SUCCESS(status))
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to open BAL",__func__);
+ goto err_wdclose;
+ }
+#endif // ANI_BUS_TYPE_SDIO
+
+ status = vos_chipVoteOnXOBuffer(NULL, NULL, NULL);
+ if(!VOS_IS_STATUS_SUCCESS(status))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Failed to configure 19.2 MHz Clock", __func__);
+#ifdef ANI_BUS_TYPE_SDIO
+ goto err_balclose;
+#else
+ goto err_wdclose;
+#endif
+ }
+
+
+#ifdef ANI_BUS_TYPE_SDIO
+ status = WLANSAL_Start(pHddCtx->pvosContext);
+ if (!VOS_IS_STATUS_SUCCESS(status))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Failed to start SAL",__func__);
+ goto err_clkvote;
+ }
+
+ /* Start BAL */
+ status = WLANBAL_Start(pHddCtx->pvosContext);
+
+ if (!VOS_IS_STATUS_SUCCESS(status))
+ {
+ VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to start BAL",__func__);
+ goto err_salstop;
+ }
+#endif // ANI_BUS_TYPE_SDIO
+
+#ifdef MSM_PLATFORM_7x30
+ /* FIXME: Volans 2.0 configuration. Reconfigure 1.3v SW supply to 1.3v. It will be configured to
+ * 1.4v in vos_ChipPowerup() routine above
+ */
+#endif
+
+ status = vos_open( &pVosContext, 0);
+ if ( !VOS_IS_STATUS_SUCCESS( status ))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_open failed",__func__);
+ goto err_balstop;
+ }
+
+ /* Save the hal context in Adapter */
+ pHddCtx->hHal = (tHalHandle)vos_get_context( VOS_MODULE_ID_SME, pVosContext );
+
+ if ( NULL == pHddCtx->hHal )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: HAL context is null",__func__);
+ goto err_vosclose;
+ }
+
+ // Set the SME configuration parameters...
+ status = hdd_set_sme_config( pHddCtx );
+
+ if ( VOS_STATUS_SUCCESS != status )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed hdd_set_sme_config",__func__);
+ goto err_vosclose;
+ }
+
+ //Initialize the WMM module
+ status = hdd_wmm_init(pHddCtx);
+ if (!VOS_IS_STATUS_SUCCESS(status))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: hdd_wmm_init failed", __FUNCTION__);
+ goto err_vosclose;
+ }
+
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+ /* Vos preStart is calling */
+ status = vos_preStart( pHddCtx->pvosContext );
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_preStart failed",__func__);
+ goto err_vosclose;
+ }
+#endif
+
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+ /* In the integrated architecture we update the configuration from
+ the INI file and from NV before vOSS has been started so that
+ the final contents are available to send down to the cCPU */
+
+ // Apply the cfg.ini to cfg.dat
+ if (FALSE == hdd_update_config_dat(pHddCtx))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: config update failed",__func__ );
+ goto err_vosclose;
+ }
+
+ // Apply the NV to cfg.dat
+ /* Prima Update MAC address only at here */
+ if (VOS_STATUS_SUCCESS != hdd_update_config_from_nv(pHddCtx))
+ {
+#ifdef WLAN_AUTOGEN_MACADDR_FEATURE
+ /* There was not a valid set of MAC Addresses in NV. See if the
+ default addresses were modified by the cfg.ini settings. If so,
+ we'll use them, but if not, we'll autogenerate a set of MAC
+ addresses based upon the device serial number */
+
+ static const v_MACADDR_t default_address =
+ {{0x00, 0x0A, 0xF5, 0x89, 0x89, 0xFF}};
+ unsigned int serialno;
+ int i;
+
+ serialno = wcnss_get_serial_number();
+ if ((0 != serialno) &&
+ (0 == memcmp(&default_address, &pHddCtx->cfg_ini->intfMacAddr[0],
+ sizeof(default_address))))
+ {
+ /* cfg.ini has the default address, invoke autogen logic */
+
+ /* MAC address has 3 bytes of OUI so we have a maximum of 3
+ bytes of the serial number that can be used to generate
+ the other 3 bytes of the MAC address. Mask off all but
+ the lower 3 bytes (this will also make sure we don't
+ overflow in the next step) */
+ serialno &= 0x00FFFFFF;
+
+ /* we need a unique address for each session */
+ serialno *= VOS_MAX_CONCURRENCY_PERSONA;
+
+ /* autogen all addresses */
+ for (i = 0; i < VOS_MAX_CONCURRENCY_PERSONA; i++)
+ {
+ /* start with the entire default address */
+ pHddCtx->cfg_ini->intfMacAddr[i] = default_address;
+ /* then replace the lower 3 bytes */
+ pHddCtx->cfg_ini->intfMacAddr[i].bytes[3] = (serialno >> 16) & 0xFF;
+ pHddCtx->cfg_ini->intfMacAddr[i].bytes[4] = (serialno >> 8) & 0xFF;
+ pHddCtx->cfg_ini->intfMacAddr[i].bytes[5] = serialno & 0xFF;
+
+ serialno++;
+ }
+
+ pr_info("wlan: Invalid MAC addresses in NV, autogenerated "
+ MAC_ADDRESS_STR,
+ MAC_ADDR_ARRAY(pHddCtx->cfg_ini->intfMacAddr[0].bytes));
+ }
+ else
+#endif //WLAN_AUTOGEN_MACADDR_FEATURE
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,
+ "%s: Invalid MAC address in NV, using MAC from ini file "
+ MAC_ADDRESS_STR, __func__,
+ MAC_ADDR_ARRAY(pHddCtx->cfg_ini->intfMacAddr[0].bytes));
+ }
+ }
+ {
+ eHalStatus halStatus;
+ // Set the MAC Address
+ // Currently this is used by HAL to add self sta. Remove this once self sta is added as part of session open.
+ halStatus = cfgSetStr( pHddCtx->hHal, WNI_CFG_STA_ID,
+ (v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[0],
+ sizeof( pHddCtx->cfg_ini->intfMacAddr[0]) );
+
+ if (!HAL_STATUS_SUCCESS( halStatus ))
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed to set MAC Address. "
+ "HALStatus is %08d [x%08x]",__func__, halStatus, halStatus );
+ return VOS_STATUS_E_FAILURE;
+ }
+ }
+#endif // FEATURE_WLAN_INTEGRATED_SOC
+
+ /*Start VOSS which starts up the SME/MAC/HAL modules and everything else
+ Note: Firmware image will be read and downloaded inside vos_start API */
+ status = vos_start( pHddCtx->pvosContext );
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_start failed",__func__);
+ goto err_vosclose;
+ }
+
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+ /* retrieve and display WCNSS version information */
+ do {
+ tSirVersionType versionCompiled;
+ tSirVersionType versionReported;
+ tSirVersionString versionString;
+ tANI_U8 fwFeatCapsMsgSupported = 0;
+ VOS_STATUS vstatus;
+
+ vstatus = sme_GetWcnssWlanCompiledVersion(pHddCtx->hHal,
+ &versionCompiled);
+ if (!VOS_IS_STATUS_SUCCESS(vstatus))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: unable to retrieve WCNSS WLAN compiled version",
+ __FUNCTION__);
+ break;
+ }
+
+ vstatus = sme_GetWcnssWlanReportedVersion(pHddCtx->hHal,
+ &versionReported);
+ if (!VOS_IS_STATUS_SUCCESS(vstatus))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: unable to retrieve WCNSS WLAN reported version",
+ __FUNCTION__);
+ break;
+ }
+
+ if ((versionCompiled.major != versionReported.major) ||
+ (versionCompiled.minor != versionReported.minor) ||
+ (versionCompiled.version != versionReported.version) ||
+ (versionCompiled.revision != versionReported.revision))
+ {
+ pr_err("%s: WCNSS WlAN Version %u.%u.%u.%u, "
+ "Host expected %u.%u.%u.%u\n",
+ WLAN_MODULE_NAME,
+ (int)versionReported.major,
+ (int)versionReported.minor,
+ (int)versionReported.version,
+ (int)versionReported.revision,
+ (int)versionCompiled.major,
+ (int)versionCompiled.minor,
+ (int)versionCompiled.version,
+ (int)versionCompiled.revision);
+ }
+ else
+ {
+ pr_info("%s: WCNSS WLAN version %u.%u.%u.%u\n",
+ WLAN_MODULE_NAME,
+ (int)versionReported.major,
+ (int)versionReported.minor,
+ (int)versionReported.version,
+ (int)versionReported.revision);
+ }
+
+ vstatus = sme_GetWcnssSoftwareVersion(pHddCtx->hHal,
+ versionString,
+ sizeof(versionString));
+ if (!VOS_IS_STATUS_SUCCESS(vstatus))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: unable to retrieve WCNSS software version string",
+ __FUNCTION__);
+ break;
+ }
+
+ pr_info("%s: WCNSS software version %s\n",
+ WLAN_MODULE_NAME, versionString);
+
+ vstatus = sme_GetWcnssHardwareVersion(pHddCtx->hHal,
+ versionString,
+ sizeof(versionString));
+ if (!VOS_IS_STATUS_SUCCESS(vstatus))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: unable to retrieve WCNSS hardware version string",
+ __FUNCTION__);
+ break;
+ }
+
+ pr_info("%s: WCNSS hardware version %s\n",
+ WLAN_MODULE_NAME, versionString);
+
+ /* Check if FW version is greater than 0.1.1.0. Only then send host-FW capability exchange message */
+ if ((versionReported.major>0) || (versionReported.minor>1) || ((versionReported.minor>=1) && (versionReported.version>=1)))
+ fwFeatCapsMsgSupported = 1;
+ if (fwFeatCapsMsgSupported)
+ sme_featureCapsExchange(pHddCtx->hHal);
+ } while (0);
+
+#endif // FEATURE_WLAN_INTEGRATED_SOC
+
+ status = hdd_post_voss_start_config( pHddCtx );
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hdd_post_voss_start_config failed",
+ __func__);
+ goto err_vosstop;
+ }
+
+#ifdef WLAN_SOFTAP_FEATURE
+ if (VOS_STA_SAP_MODE == hdd_get_conparam())
+ {
+ pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_SOFTAP, "softap.%d",
+ wlan_hdd_get_intf_addr(pHddCtx), FALSE );
+ }
+ else
+ {
+#endif
+ pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_INFRA_STATION, "wlan%d",
+ wlan_hdd_get_intf_addr(pHddCtx), FALSE );
+ if (pAdapter != NULL)
+ {
+#ifdef WLAN_FEATURE_P2P
+ vos_mem_copy( pHddCtx->p2pDeviceAddress.bytes,
+ pHddCtx->cfg_ini->intfMacAddr[0].bytes,
+ sizeof(tSirMacAddr));
+ if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
+ {
+ /* Generate the P2P Device Address. This consists of the device's
+ * primary MAC address with the locally administered bit set.
+ */
+ pHddCtx->p2pDeviceAddress.bytes[0] |= 0x02;
+ status = hdd_init_p2p_device_mode(pAdapter);
+ if ( VOS_STATUS_SUCCESS != status )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,
+ "%s: Init Session fail for P2P Device Address Mode ",
+ __FUNCTION__);
+ goto err_close_adapter;
+ }
+ }
+#endif
+ }
+#ifdef WLAN_SOFTAP_FEATURE
+ }
+#endif
+
+ if( pAdapter == NULL )
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
+#ifdef ANI_BUS_TYPE_SDIO
+ goto err_balstop;
+#else
+ goto err_clkvote;
+#endif
+ }
+
+
+#ifdef WLAN_BTAMP_FEATURE
+ vStatus = WLANBAP_Open(pVosContext);
+ if(!VOS_IS_STATUS_SUCCESS(vStatus))
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to open BAP",__func__);
+ goto err_p2psession_close;
+ }
+
+ vStatus = BSL_Init(pVosContext);
+ if(!VOS_IS_STATUS_SUCCESS(vStatus))
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to Init BSL",__func__);
+ goto err_bap_close;
+ }
+ vStatus = WLANBAP_Start(pVosContext);
+ if (!VOS_IS_STATUS_SUCCESS(vStatus))
+ {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
+ "%s: Failed to start TL",__func__);
+ goto err_bap_close;
+ }
+
+ pConfig = pHddCtx->cfg_ini;
+ btAmpConfig.ucPreferredChannel = pConfig->preferredChannel;
+ status = WLANBAP_SetConfig(&btAmpConfig);
+
+#endif //WLAN_BTAMP_FEATURE
+
+#ifdef FEATURE_WLAN_SCAN_PNO
+ /*SME must send channel update configuration to RIVA*/
+ sme_UpdateChannelConfig(pHddCtx->hHal);
+#endif
+
+#ifdef FEATURE_WLAN_INTEGRATED_SOC
+ /* Register with platform driver as client for Suspend/Resume */
+ status = hddRegisterPmOps(pHddCtx);
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddRegisterPmOps failed",__func__);
+#ifdef WLAN_BTAMP_FEATURE
+ goto err_bap_stop;
+#else
+ goto err_p2psession_close;
+#endif //WLAN_BTAMP_FEATURE
+ }
+
+ /* Register TM level change handler function to the platform */
+ status = hddDevTmRegisterNotifyCallback(pHddCtx);
+ if ( !VOS_IS_STATUS_SUCCESS( status ) )
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDevTmRegisterNotifyCallback failed",__func__);
+ goto err_unregister_pmops;
+ }
+#endif
+
+ /* register for riva power on lock to platform driver */
+ if (req_riva_power_on_lock("wlan"))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: req riva power on lock failed",
+ __func__);
+ goto err_unregister_pmops;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ // Register suspend/resume callbacks
+ if(pHddCtx->cfg_ini->nEnableSuspend)
+ {
+ register_wlan_suspend();
+ }
+#endif
+
+ // register net device notifier for device change notification
+ ret = register_netdevice_notifier(&hdd_netdev_notifier);
+
+ if(ret < 0)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR,"%s: register_netdevice_notifier failed",__func__);
+ goto err_free_power_on_lock;
+ }
+
+ //Initialize the nlink service
+ if(nl_srv_init() != 0)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%S: nl_srv_init failed",__func__);
+ goto err_reg_netdev;
+ }
+
+ //Initialize the BTC service
+ if(btc_activate_service(pHddCtx) != 0)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: btc_activate_service failed",__func__);
+ goto err_nl_srv;
+ }
+
+#ifdef PTT_SOCK_SVC_ENABLE
+ //Initialize the PTT service
+ if(ptt_sock_activate_svc(pHddCtx) != 0)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: ptt_sock_activate_svc failed",__func__);
+ goto err_nl_srv;
+ }
+#endif
+
+ //Initialize the WoWL service
+ if(!hdd_init_wowl(pHddCtx))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hdd_init_wowl failed",__func__);
+ goto err_nl_srv;
+ }
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ hdd_register_mcast_bcast_filter(pHddCtx);
+#endif
+#ifdef CONFIG_CFG80211
+#ifdef WLAN_SOFTAP_FEATURE
+ if (VOS_STA_SAP_MODE != hdd_get_conparam())
+#endif
+ {
+ wlan_hdd_cfg80211_post_voss_start(pAdapter);
+ }
+#endif
+
+ mutex_init(&pHddCtx->sap_lock);
+
+ pHddCtx->isLoadUnloadInProgress = FALSE;
+
+ vos_event_init(&pAdapter->scan_info.scan_finished_event);
+ pAdapter->scan_info.scan_pending_option = WEXT_SCAN_PENDING_GIVEUP;
+
+ vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, FALSE);
+ hdd_allow_suspend();
+
+ goto success;
+
+err_nl_srv:
+ nl_srv_exit();
+
+err_reg_netdev:
+ unregister_netdevice_notifier(&hdd_netdev_notifier);
+
+err_free_power_on_lock:
+ free_riva_power_on_lock("wlan");
+
+err_unregister_pmops:
+ hddDevTmUnregisterNotifyCallback(pHddCtx);
+ hddDeregisterPmOps(pHddCtx);
+
+#ifdef WLAN_BTAMP_FEATURE
+err_bap_stop:
+ WLANBAP_Stop(pVosContext);
+#endif
+
+#ifdef WLAN_BTAMP_FEATURE
+err_bap_close:
+ WLANBAP_Close(pVosContext);
+#endif
+
+err_p2psession_close:
+#ifdef WLAN_FEATURE_P2P
+ if (pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated)
+ {
+ hdd_adapter_t* pAdapter = hdd_get_adapter(pHddCtx,
+ WLAN_HDD_INFRA_STATION);
+
+ if (pAdapter != NULL)
+ {
+ INIT_COMPLETION(pAdapter->session_close_comp_var);
+ if( eHAL_STATUS_SUCCESS == sme_CloseSession( pHddCtx->hHal,
+ pAdapter->p2pSessionId,
+ hdd_smeCloseSessionCallback, pAdapter ) )
+ {
+ //Block on a completion variable. Can't wait forever though.
+ wait_for_completion_interruptible_timeout(
+ &pAdapter->session_close_comp_var,
+ msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
+ }
+ }
+ }
+#endif
+
+err_close_adapter:
+ hdd_close_all_adapters( pHddCtx );
+
+err_vosstop:
+ vos_stop(pVosContext);
+
+err_vosclose:
+ status = vos_sched_close( pVosContext );
+ if (!VOS_IS_STATUS_SUCCESS(status)) {
+ VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
+ "%s: Failed to close VOSS Scheduler", __func__);
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status ) );
+ }
+ vos_close(pVosContext );
+
+err_balstop:
+#ifdef ANI_BUS_TYPE_SDIO
+#ifndef ANI_MANF_DIAG
+ wlan_hdd_enable_deepsleep(pHddCtx->pvosContext);
+#endif
+
+ WLANBAL_Stop(pHddCtx->pvosContext);
+ WLANBAL_SuspendChip(pHddCtx->pvosContext);
+#endif
+
+#ifdef ANI_BUS_TYPE_SDIO
+err_salstop:
+ WLANSAL_Stop(pHddCtx->pvosContext);
+
+#endif
+err_clkvote:
+ vos_chipVoteOffXOBuffer(NULL, NULL, NULL);
+
+#ifdef ANI_BUS_TYPE_SDIO
+err_balclose:
+ WLANBAL_Close(pHddCtx->pvosContext);
+#endif // ANI_BUS_TYPE_SDIO
+
+err_wdclose:
+ if(pHddCtx->cfg_ini->fIsLogpEnabled)
+ vos_watchdog_close(pVosContext);
+
+#ifdef CONFIG_CFG80211
+err_wiphy_reg:
+ wiphy_unregister(wiphy) ;
+#endif
+
+err_config:
+ kfree(pHddCtx->cfg_ini);
+ pHddCtx->cfg_ini= NULL;
+
+err_free_hdd_context:
+ hdd_allow_suspend();
+#ifdef CONFIG_CFG80211
+ wiphy_free(wiphy) ;
+ //kfree(wdev) ;
+#else
+ vos_mem_free( pHddCtx );
+#endif
+ VOS_BUG(1);
+
+ return -1;
+
+success:
+ EXIT();
+ return 0;
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_module_init() - Init Function
+
+ This is the driver entry point (invoked when module is loaded using insmod)
+
+ \param - None
+
+ \return - 0 for success, non zero for failure
+
+ --------------------------------------------------------------------------*/
+
+static int __init hdd_module_init ( void)
+{
+ VOS_STATUS status;
+ v_CONTEXT_t pVosContext = NULL;
+#ifdef ANI_BUS_TYPE_SDIO
+ struct sdio_func *sdio_func_dev = NULL;
+ unsigned int attempts = 0;
+#endif // ANI_BUS_TYPE_SDIO
+ struct device *dev = NULL;
+ int ret_status = 0;
+
+ ENTER();
+
+ wake_lock_init(&wlan_wake_lock, WAKE_LOCK_SUSPEND, "wlan");
+
+ pr_info("%s: loading driver v%s\n", WLAN_MODULE_NAME,
+ QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR);
+
+ //Power Up Libra WLAN card first if not already powered up
+ status = vos_chipPowerUp(NULL,NULL,NULL);
+ if (!VOS_IS_STATUS_SUCCESS(status))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN not Powered Up. "
+ "exiting", __func__);
+ return -1;
+ }
+
+#ifdef ANI_BUS_TYPE_SDIO
+ //SDIO Polling should be turned on for card detection. When using Android Wi-Fi GUI
+ //users need not trigger SDIO polling explicitly. However when loading drivers via
+ //command line (Adb shell), users must turn on SDIO polling prior to loading WLAN.
+ do {
+ sdio_func_dev = libra_getsdio_funcdev();
+ if (NULL == sdio_func_dev) {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN not detected yet.",__func__);
+ attempts++;
+ }
+ else {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN detecton succeeded",__func__);
+ dev = &sdio_func_dev->dev;
+ break;
+ }
+
+ if(attempts == 7)
+ break;
+
+ msleep(250);
+
+ }while (attempts < 7);
+
+ //Retry to detect the card again by Powering Down the chip and Power up the chip
+ //again. This retry is done to recover from CRC Error
+ if (NULL == sdio_func_dev) {
+
+ attempts = 0;
+
+ //Vote off any PMIC voltage supplies
+ vos_chipPowerDown(NULL, NULL, NULL);
+
+ msleep(1000);
+
+ //Power Up Libra WLAN card first if not already powered up
+ status = vos_chipPowerUp(NULL,NULL,NULL);
+ if (!VOS_IS_STATUS_SUCCESS(status))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN not Powered Up. "
+ "exiting", __func__);
+ return -1;
+ }
+
+ do {
+ sdio_func_dev = libra_getsdio_funcdev();
+ if (NULL == sdio_func_dev) {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN not detected yet.",__func__);
+ attempts++;
+ }
+ else {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN detecton succeeded",__func__);
+ dev = &sdio_func_dev->dev;
+ break;
+ }
+
+ if(attempts == 2)
+ break;
+
+ msleep(1000);
+
+ }while (attempts < 3);
+ }
+
+#endif // ANI_BUS_TYPE_SDIO
+
+#ifdef ANI_BUS_TYPE_PCI
+
+ dev = wcnss_wlan_get_device();
+
+#endif // ANI_BUS_TYPE_PCI
+
+#ifdef ANI_BUS_TYPE_PLATFORM
+ dev = wcnss_wlan_get_device();
+#endif // ANI_BUS_TYPE_PLATFORM
+
+
+ do {
+ if (NULL == dev) {
+ hddLog(VOS_TRACE_LEVEL_FATAL, "%s: WLAN device not found!!",__func__);
+ ret_status = -1;
+ break;
+ }
+
+#ifdef MEMORY_DEBUG
+ vos_mem_init();
+#endif
+
+#ifdef TIMER_MANAGER
+ vos_timer_manager_init();
+#endif
+
+ /* Preopen VOSS so that it is ready to start at least SAL */
+ status = vos_preOpen(&pVosContext);
+
+ if (!VOS_IS_STATUS_SUCCESS(status))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed to preOpen VOSS", __func__);
+ ret_status = -1;
+ break;
+ }
+
+#ifdef ANI_BUS_TYPE_SDIO
+ /* Now Open SAL */
+ status = WLANSAL_Open(pVosContext, 0);
+
+ if(!VOS_IS_STATUS_SUCCESS(status))
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed to open SAL", __func__);
+
+ /* If unable to open, cleanup and return failure */
+ vos_preClose( &pVosContext );
+ ret_status = -1;
+ break;
+ }
+#endif // ANI_BUS_TYPE_SDIO
+
+#if defined(FEATURE_WLAN_INTEGRATED_SOC) && defined(ANI_MANF_DIAG)
+ if(5 == con_mode)
+ {
+ hdd_set_conparam(VOS_FTM_MODE);
+ }
+#endif /* FEATURE_WLAN_INTEGRATED_SOC && ANI_MANF_DIAG */
+
+ // Call our main init function
+ if(hdd_wlan_startup(dev)) {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: WLAN Driver Initialization failed",
+ __func__);
+#ifdef ANI_BUS_TYPE_SDIO
+ WLANSAL_Close(pVosContext);
+#endif // ANI_BUS_TYPE_SDIO
+ vos_preClose( &pVosContext );
+ ret_status = -1;
+ break;
+ }
+
+ /* Cancel the vote for XO Core ON
+ * This is done here for safety purposes in case we re-initialize without turning
+ * it OFF in any error scenario.
+ */
+ hddLog(VOS_TRACE_LEVEL_ERROR, "In module init: Ensure Force XO Core is OFF"
+ " when WLAN is turned ON so Core toggles"
+ " unless we enter PS\n");
+ if (vos_chipVoteXOCore(NULL, NULL, NULL, VOS_FALSE) != VOS_STATUS_SUCCESS)
+ {
+ hddLog(VOS_TRACE_LEVEL_ERROR, "Could not cancel XO Core ON vote. Not returning failure."
+ " Power consumed will be high\n");
+ }
+ } while (0);
+
+ if (0 != ret_status)
+ {
+ //Assert Deep sleep signal now to put Libra HW in lowest power state
+ status = vos_chipAssertDeepSleep( NULL, NULL, NULL );
+ VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status) );
+
+ //Vote off any PMIC voltage supplies
+ vos_chipPowerDown(NULL, NULL, NULL);
+#ifdef TIMER_MANAGER
+ vos_timer_exit();
+#endif
+#ifdef MEMORY_DEBUG
+ vos_mem_exit();
+#endif
+
+ wake_lock_destroy(&wlan_wake_lock);
+ pr_err("%s: driver load failure\n", WLAN_MODULE_NAME);
+ }
+ else
+ {
+ //Send WLAN UP indication to Nlink Service
+ send_btc_nlink_msg(WLAN_MODULE_UP_IND, 0);
+
+ pr_info("%s: driver loaded\n", WLAN_MODULE_NAME);
+
+ }
+
+ EXIT();
+
+ return ret_status;
+}
+
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_module_exit() - Exit function
+
+ This is the driver exit point (invoked when module is unloaded using rmmod)
+
+ \param - None
+
+ \return - None
+
+ --------------------------------------------------------------------------*/
+static void __exit hdd_module_exit(void)
+{
+ hdd_context_t *pHddCtx = NULL;
+ v_CONTEXT_t pVosContext = NULL;
+ int attempts = 0;
+
+ pr_info("%s: unloading driver v%s\n", WLAN_MODULE_NAME, QWLAN_VERSIONSTR);
+
+ //Get the global vos context
+ pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
+
+ if(!pVosContext)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
+ goto done;
+ }
+
+ //Get the HDD context.
+ pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
+
+ if(!pHddCtx)
+ {
+ hddLog(VOS_TRACE_LEVEL_FATAL,"%s: module exit called before probe",__func__);
+ }
+ else
+ {
+ while(isWDresetInProgress()){
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:Reset in Progress by LOGP. Block rmmod for 500ms!!!",__func__);
+ VOS_ASSERT(0);
+ msleep(500);
+ attempts++;
+ if(attempts==MAX_EXIT_ATTEMPTS_DURING_LOGP)
+ break;
+ }
+
+ pHddCtx->isLoadUnloadInProgress = TRUE;
+ vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE);
+
+ //Do all the cleanup before deregistering the driver
+ hdd_wlan_exit(pHddCtx);
+ }
+
+#ifdef ANI_BUS_TYPE_SDIO
+ WLANSAL_Close(pVosContext);
+#endif // ANI_BUS_TYPE_SDIO
+
+ vos_preClose( &pVosContext );
+
+#ifdef TIMER_MANAGER
+ vos_timer_exit();
+#endif
+#ifdef MEMORY_DEBUG
+ vos_mem_exit();
+#endif
+
+done:
+ wake_lock_destroy(&wlan_wake_lock);
+ pr_info("%s: driver unloaded\n", WLAN_MODULE_NAME);
+}
+
+#if defined(WLAN_SOFTAP_FEATURE) || defined(ANI_MANF_DIAG)
+/**---------------------------------------------------------------------------
+
+ \brief hdd_get_conparam() -
+
+ This is the driver exit point (invoked when module is unloaded using rmmod)
+
+ \param - None
+
+ \return - tVOS_CON_MODE
+
+ --------------------------------------------------------------------------*/
+tVOS_CON_MODE hdd_get_conparam ( void )
+{
+ return (tVOS_CON_MODE)con_mode;
+
+}
+void hdd_set_conparam ( v_UINT_t newParam )
+{
+ con_mode = newParam;
+}
+/**---------------------------------------------------------------------------
+
+ \brief hdd_softap_sta_deauth() - function
+
+ This to take counter measure to handle deauth req from HDD
+
+ \param - pAdapter - Pointer to the HDD
+
+ \param - enable - boolean value
+
+ \return - None
+
+ --------------------------------------------------------------------------*/
+
+void hdd_softap_sta_deauth(hdd_adapter_t *pAdapter, v_U8_t *pDestMacAddress)
+{
+ v_U8_t STAId;
+ v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
+#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
+ tHalHandle hHalHandle;
+#endif
+
+ ENTER();
+
+ hddLog( LOGE, "hdd_softap_sta_deauth:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
+
+ //Ignore request to deauth bcmc station
+ if( pDestMacAddress[0] & 0x1 )
+ return;
+
+ WLANSAP_DeauthSta(pVosContext,pDestMacAddress);
+
+ /*Get the Station ID*/
+#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
+ hHalHandle = (tHalHandle ) vos_get_context(VOS_MODULE_ID_HAL, pVosContext);
+ if (eHAL_STATUS_SUCCESS ==
+ halTable_FindStaidByAddr(hHalHandle, (tANI_U8 *)pDestMacAddress,
+ &STAId))
+ {
+ hdd_softap_DeregisterSTA(pAdapter, STAId);
+ }
+#else
+ if (VOS_STATUS_SUCCESS ==
+ hdd_softap_GetStaId(pAdapter, (v_MACADDR_t *)pDestMacAddress,
+ &STAId))
+ {
+ hdd_softap_DeregisterSTA(pAdapter, STAId);
+ }
+#endif
+
+ EXIT();
+}
+
+/**---------------------------------------------------------------------------
+
+ \brief hdd_softap_sta_disassoc() - function
+
+ This to take counter measure to handle deauth req from HDD
+
+ \param - pAdapter - Pointer to the HDD
+
+ \param - enable - boolean value
+
+ \return - None
+
+ --------------------------------------------------------------------------*/
+
+void hdd_softap_sta_disassoc(hdd_adapter_t *pAdapter,v_U8_t *pDestMacAddress)
+{
+ v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
+
+ ENTER();
+
+ hddLog( LOGE, "hdd_softap_sta_disassoc:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
+
+ //Ignore request to disassoc bcmc station
+ if( pDestMacAddress[0] & 0x1 )
+ return;
+
+ WLANSAP_DisassocSta(pVosContext,pDestMacAddress);
+}
+
+void hdd_softap_tkip_mic_fail_counter_measure(hdd_adapter_t *pAdapter,v_BOOL_t enable)
+{
+ v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
+
+ ENTER();
+
+ hddLog( LOGE, "hdd_softap_tkip_mic_fail_counter_measure:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
+
+ WLANSAP_SetCounterMeasure(pVosContext, (v_BOOL_t)enable);
+}
+
+#endif /* WLAN_SOFTAP_FEATURE */
+/**---------------------------------------------------------------------------
+ *
+ * \brief hdd_get__concurrency_mode() -
+ *
+ *
+ * \param - None
+ *
+ * \return - CONCURRENCY MODE
+ *
+ * --------------------------------------------------------------------------*/
+tVOS_CONCURRENCY_MODE hdd_get_concurrency_mode ( void )
+{
+ v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL );
+ hdd_context_t *pHddCtx;
+
+ if (NULL != pVosContext)
+ {
+ pHddCtx = vos_get_context( VOS_MODULE_ID_HDD, pVosContext);
+ if (NULL != pHddCtx)
+ {
+ return (tVOS_CONCURRENCY_MODE)pHddCtx->concurrency_mode;
+ }
+ }
+
+ /* we are in an invalid state :( */
+ hddLog(LOGE, "%s: Invalid context", __FUNCTION__);
+ return VOS_STA;
+}
+
+/* Decide whether to allow/not the apps power collapse.
+ * Allow apps power collapse if we are in connected state.
+ * if not, allow only if we are in IMPS */
+v_BOOL_t hdd_is_apps_power_collapse_allowed(hdd_context_t* pHddCtx)
+{
+ tPmcState pmcState = pmcGetPmcState(pHddCtx->hHal);
+ hdd_config_t *pConfig = pHddCtx->cfg_ini;
+ hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
+ hdd_adapter_t *pAdapter = NULL;
+ VOS_STATUS status;
+
+#ifdef WLAN_SOFTAP_FEATURE
+ if (VOS_STA_SAP_MODE == hdd_get_conparam())
+ return TRUE;
+#endif
+
+ /*loop through all adapters. TBD fix for Concurrency */
+ status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
+ while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
+ {
+ pAdapter = pAdapterNode->pAdapter;
+ if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode)
+ || (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) )
+ {
+ if ((pConfig->fIsImpsEnabled || pConfig->fIsBmpsEnabled)
+ && (pmcState != IMPS && pmcState != BMPS
+ && pmcState != STOPPED && pmcState != STANDBY))
+ {
+ return FALSE;
+ }
+ }
+ status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
+ pAdapterNode = pNext;
+ }
+ return TRUE;
+}
+
+void wlan_hdd_set_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
+{
+ switch(mode)
+ {
+ case WLAN_HDD_INFRA_STATION:
+#ifdef WLAN_FEATURE_P2P
+ case WLAN_HDD_P2P_CLIENT:
+ case WLAN_HDD_P2P_GO:
+#endif
+ case WLAN_HDD_SOFTAP:
+ pHddCtx->concurrency_mode |= (1 << mode);
+ pHddCtx->no_of_sessions[mode]++;
+ break;
+ default:
+ break;
+
+ }
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
+ __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
+}
+
+
+void wlan_hdd_clear_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
+{
+ switch(mode)
+ {
+ case WLAN_HDD_INFRA_STATION:
+#ifdef WLAN_FEATURE_P2P
+ case WLAN_HDD_P2P_CLIENT:
+ case WLAN_HDD_P2P_GO:
+#endif
+ case WLAN_HDD_SOFTAP:
+ pHddCtx->no_of_sessions[mode]--;
+ if (!(pHddCtx->no_of_sessions[mode]))
+ pHddCtx->concurrency_mode &= (~(1 << mode));
+ break;
+ default:
+ break;
+ }
+ VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
+ __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
+}
+
+//Register the module init/exit functions
+module_init(hdd_module_init);
+module_exit(hdd_module_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Qualcomm Atheros, Inc.");
+MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER");
+
+#if defined(WLAN_SOFTAP_FEATURE) || defined(ANI_MANF_DIAG)
+module_param(con_mode, int, 0);
+#endif