blob: 52d4e34792f8b76bac0b88293ddb8e6500859d21 [file] [log] [blame]
Jeff Johnson295189b2012-06-20 16:38:30 -07001/*
Jeff Johnson32d95a32012-09-10 13:15:23 -07002 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
Jeff Johnson295189b2012-06-20 16:38:30 -07003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*========================================================================
23
24 \file wlan_hdd_main.c
25
26 \brief WLAN Host Device Driver implementation
27
28 Copyright 2008 (c) Qualcomm, Incorporated. All Rights Reserved.
29
30 Qualcomm Confidential and Proprietary.
31
32 ========================================================================*/
33
34/**=========================================================================
35
36 EDIT HISTORY FOR FILE
37
38
39 This section contains comments describing changes made to the module.
40 Notice that changes are listed in reverse chronological order.
41
42
43 $Header:$ $DateTime: $ $Author: $
44
45
46 when who what, where, why
47 -------- --- --------------------------------------------------------
48 04/5/09 Shailender Created module.
49 02/24/10 Sudhir.S.Kohalli Added to support param for SoftAP module
50 06/03/10 js - Added support to hostapd driven deauth/disassoc/mic failure
51 ==========================================================================*/
52
53/*--------------------------------------------------------------------------
54 Include Files
55 ------------------------------------------------------------------------*/
56//#include <wlan_qct_driver.h>
57#include <wlan_hdd_includes.h>
58#ifdef ANI_BUS_TYPE_SDIO
59#include <wlan_sal_misc.h>
60#endif // ANI_BUS_TYPE_SDIO
61#include <vos_api.h>
62#include <vos_sched.h>
63#include <vos_power.h>
64#include <linux/etherdevice.h>
65#include <linux/firmware.h>
66#ifdef ANI_BUS_TYPE_SDIO
67#include <linux/mmc/sdio_func.h>
68#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32))
69// added in 2.6.32, need to define locally if using an earlier kernel
70#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev)
71#endif
72#endif // ANI_BUS_TYPE_SDIO
73#ifdef ANI_BUS_TYPE_PLATFORM
74#include <linux/wcnss_wlan.h>
75#endif //ANI_BUS_TYPE_PLATFORM
76#ifdef ANI_BUS_TYPE_PCI
77#include "wcnss_wlan.h"
78#endif /* ANI_BUS_TYPE_PCI */
79#include <wlan_hdd_tx_rx.h>
80#include <palTimer.h>
81#include <wniApi.h>
82#include <wlan_nlink_srv.h>
83#include <wlan_btc_svc.h>
84#include <wlan_hdd_cfg.h>
85#include <wlan_ptt_sock_svc.h>
86#include <wlan_hdd_wowl.h>
87#include <wlan_hdd_misc.h>
88#include <wlan_hdd_wext.h>
89#ifdef WLAN_BTAMP_FEATURE
90#include <bap_hdd_main.h>
91#include <bapInternal.h>
92#endif // WLAN_BTAMP_FEATURE
93
94#ifdef CONFIG_CFG80211
95#include <linux/wireless.h>
96#include <net/cfg80211.h>
97#include "wlan_hdd_cfg80211.h"
98#include "wlan_hdd_p2p.h"
99#endif
100#include <linux/rtnetlink.h>
101#ifdef ANI_MANF_DIAG
102int wlan_hdd_ftm_start(hdd_context_t *pAdapter);
103#endif
104#ifdef WLAN_SOFTAP_FEATURE
105#include "sapApi.h"
106#include <linux/semaphore.h>
107#include <mach/subsystem_restart.h>
108#include <wlan_hdd_hostapd.h>
109#include <wlan_hdd_softap_tx_rx.h>
110#endif
111#ifdef FEATURE_WLAN_INTEGRATED_SOC
112#include "cfgApi.h"
113#endif
114#include "wlan_hdd_dev_pwr.h"
115#ifdef WLAN_BTAMP_FEATURE
116#include "bap_hdd_misc.h"
117#endif
118#ifdef FEATURE_WLAN_INTEGRATED_SOC
119#include "wlan_qct_pal_trace.h"
120#endif /* FEATURE_WLAN_INTEGRATED_SOC */
121#include "qwlan_version.h"
Yathish9f22e662012-12-10 14:21:35 -0800122#include "wlan_qct_wda.h"
Jeff Johnson295189b2012-06-20 16:38:30 -0700123
124#ifdef MODULE
125#define WLAN_MODULE_NAME module_name(THIS_MODULE)
126#else
127#define WLAN_MODULE_NAME "wlan"
128#endif
129
130#ifdef TIMER_MANAGER
131#define TIMER_MANAGER_STR " +TIMER_MANAGER"
132#else
133#define TIMER_MANAGER_STR ""
134#endif
135
136#ifdef MEMORY_DEBUG
137#define MEMORY_DEBUG_STR " +MEMORY_DEBUG"
138#else
139#define MEMORY_DEBUG_STR ""
140#endif
141
142/* the Android framework expects this param even though we don't use it */
143#define BUF_LEN 20
144static char fwpath[BUF_LEN];
Madan Mohan Koyyalamudi05f313c2012-09-18 19:19:15 -0700145#ifndef MODULE
Madan Mohan Koyyalamudidfd6aa82012-10-18 20:18:43 -0700146static int wlan_hdd_inited;
Madan Mohan Koyyalamudi05f313c2012-09-18 19:19:15 -0700147#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700148
Jeff Johnsone7245742012-09-05 17:12:55 -0700149/*
150 * The rate at which the driver sends RESTART event to supplicant
151 * once the function 'vos_wlanRestart()' is called
152 *
153 */
154#define WLAN_HDD_RESTART_RETRY_DELAY_MS 5000 /* 5 second */
155#define WLAN_HDD_RESTART_RETRY_MAX_CNT 5 /* 5 retries */
156#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -0700157static struct wake_lock wlan_wake_lock;
Jeff Johnsone7245742012-09-05 17:12:55 -0700158#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700159/* set when SSR is needed after unload */
Madan Mohan Koyyalamudib5da5332012-10-15 17:23:21 -0700160static e_hdd_ssr_required isSsrRequired = HDD_SSR_NOT_REQUIRED;
Jeff Johnson295189b2012-06-20 16:38:30 -0700161
162//internal function declaration
Jeff Johnsone7245742012-09-05 17:12:55 -0700163static VOS_STATUS wlan_hdd_framework_restart(hdd_context_t *pHddCtx);
164static void wlan_hdd_restart_init(hdd_context_t *pHddCtx);
165static void wlan_hdd_restart_deinit(hdd_context_t *pHddCtx);
166void wlan_hdd_restart_timer_cb(v_PVOID_t usrDataForCallback);
167
Jeff Johnson295189b2012-06-20 16:38:30 -0700168v_U16_t hdd_select_queue(struct net_device *dev,
169 struct sk_buff *skb);
170
171#ifdef WLAN_FEATURE_PACKET_FILTERING
172static void hdd_set_multicast_list(struct net_device *dev);
173#endif
174
175void hdd_wlan_initial_scan(hdd_adapter_t *pAdapter);
176
177extern int hdd_setBand_helper(struct net_device *dev, tANI_U8* ptr);
178
179static int hdd_netdev_notifier_call(struct notifier_block * nb,
180 unsigned long state,
181 void *ndev)
182{
183 struct net_device *dev = ndev;
Madan Mohan Koyyalamudi2a1ba772012-10-11 14:59:06 -0700184 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
185 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
Jeff Johnson295189b2012-06-20 16:38:30 -0700186#ifdef WLAN_BTAMP_FEATURE
187 VOS_STATUS status;
188 hdd_context_t *pHddCtx;
189#endif
190
191 //Make sure that this callback corresponds to our device.
192 if((strncmp( dev->name, "wlan", 4 )) &&
Jeff Johnsone7245742012-09-05 17:12:55 -0700193 (strncmp( dev->name, "p2p", 3))
Jeff Johnson295189b2012-06-20 16:38:30 -0700194 )
195 return NOTIFY_DONE;
196
197#ifdef CONFIG_CFG80211
198 if (!dev->ieee80211_ptr)
199 return NOTIFY_DONE;
200#endif
201
Jeff Johnson295189b2012-06-20 16:38:30 -0700202
203 if(NULL == pAdapter)
204 {
Jeff Johnsona8a1a482012-12-12 16:49:33 -0800205 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: HDD Adapter Null Pointer", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700206 VOS_ASSERT(0);
207 return NOTIFY_DONE;
208 }
209
210 hddLog(VOS_TRACE_LEVEL_INFO,"%s: New Net Device State = %lu", __func__, state);
211
212 switch (state) {
213 case NETDEV_REGISTER:
214 break;
215
216 case NETDEV_UNREGISTER:
217 break;
218
219 case NETDEV_UP:
220 break;
221
222 case NETDEV_DOWN:
223 break;
224
225 case NETDEV_CHANGE:
Jeff Johnsone7245742012-09-05 17:12:55 -0700226 if(TRUE == pAdapter->isLinkUpSvcNeeded)
227 complete(&pAdapter->linkup_event_var);
Jeff Johnson295189b2012-06-20 16:38:30 -0700228 break;
229
230 case NETDEV_GOING_DOWN:
Madan Mohan Koyyalamudi2a1ba772012-10-11 14:59:06 -0700231 if( pHddCtx->scan_info.mScanPending != FALSE )
Jeff Johnson295189b2012-06-20 16:38:30 -0700232 {
233 int result;
Madan Mohan Koyyalamudif4e81002012-11-13 10:46:38 -0800234 INIT_COMPLETION(pHddCtx->scan_info.abortscan_event_var);
Jeff Johnson295189b2012-06-20 16:38:30 -0700235 hdd_abort_mac_scan(pAdapter->pHddCtx);
236 result = wait_for_completion_interruptible_timeout(
Madan Mohan Koyyalamudif4e81002012-11-13 10:46:38 -0800237 &pHddCtx->scan_info.abortscan_event_var,
Jeff Johnson295189b2012-06-20 16:38:30 -0700238 msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN));
239 if(!result)
240 {
241 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
Jeff Johnson902c9832012-12-10 14:28:09 -0800242 "%s: Timeout occurred while waiting for abortscan" ,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700243 __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700244 }
245 }
246 else
247 {
248 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700249 "%s: Scan is not Pending from user" , __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700250 }
251#ifdef WLAN_BTAMP_FEATURE
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700252 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s: disabling AMP", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700253 status = WLANBAP_StopAmp();
254 if(VOS_STATUS_SUCCESS != status )
255 {
256 pHddCtx->isAmpAllowed = VOS_TRUE;
257 hddLog(VOS_TRACE_LEVEL_FATAL,
258 "%s: Failed to stop AMP", __func__);
259 }
260 else
261 {
262 //a state m/c implementation in PAL is TBD to avoid this delay
263 msleep(500);
Jeff Johnson04dd8a82012-06-29 20:41:40 -0700264 if ( pHddCtx->isAmpAllowed )
265 {
266 WLANBAP_DeregisterFromHCI();
267 pHddCtx->isAmpAllowed = VOS_FALSE;
268 }
Jeff Johnson295189b2012-06-20 16:38:30 -0700269 }
270#endif //WLAN_BTAMP_FEATURE
271 break;
272
273 default:
274 break;
275 }
276
277 return NOTIFY_DONE;
278}
279
280struct notifier_block hdd_netdev_notifier = {
281 .notifier_call = hdd_netdev_notifier_call,
282};
283
284/*---------------------------------------------------------------------------
285 * Function definitions
286 *-------------------------------------------------------------------------*/
287extern int isWDresetInProgress(void);
288#ifdef CONFIG_HAS_EARLYSUSPEND
289extern void register_wlan_suspend(void);
290extern void unregister_wlan_suspend(void);
291void hdd_unregister_mcast_bcast_filter(hdd_context_t *pHddCtx);
292void hdd_register_mcast_bcast_filter(hdd_context_t *pHddCtx);
293#endif
Jeff Johnson295189b2012-06-20 16:38:30 -0700294//variable to hold the insmod parameters
Madan Mohan Koyyalamudidfd6aa82012-10-18 20:18:43 -0700295static int con_mode;
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -0700296#ifndef MODULE
297/* current con_mode - used only for statically linked driver
298 * con_mode is changed by userspace to indicate a mode change which will
299 * result in calling the module exit and init functions. The module
300 * exit function will clean up based on the value of con_mode prior to it
301 * being changed by userspace. So curr_con_mode records the current con_mode
302 * for exit when con_mode becomes the next mode for init
303 */
Madan Mohan Koyyalamudidfd6aa82012-10-18 20:18:43 -0700304static int curr_con_mode;
Jeff Johnson295189b2012-06-20 16:38:30 -0700305#endif
306
307#ifdef FEATURE_WLAN_INTEGRATED_SOC
308/**---------------------------------------------------------------------------
309
310 \brief hdd_wdi_trace_enable() - Configure initial WDI Trace enable
311
312 Called immediately after the cfg.ini is read in order to configure
313 the desired trace levels in the WDI.
314
315 \param - moduleId - module whose trace level is being configured
316 \param - bitmask - bitmask of log levels to be enabled
317
318 \return - void
319
320 --------------------------------------------------------------------------*/
321static void hdd_wdi_trace_enable(wpt_moduleid moduleId, v_U32_t bitmask)
322{
323 wpt_tracelevel level;
324
325 /* if the bitmask is the default value, then a bitmask was not
326 specified in cfg.ini, so leave the logging level alone (it
327 will remain at the "compiled in" default value) */
328 if (CFG_WDI_TRACE_ENABLE_DEFAULT == bitmask)
329 {
330 return;
331 }
332
333 /* a mask was specified. start by disabling all logging */
334 wpalTraceSetLevel(moduleId, eWLAN_PAL_TRACE_LEVEL_NONE, 0);
335
336 /* now cycle through the bitmask until all "set" bits are serviced */
337 level = eWLAN_PAL_TRACE_LEVEL_FATAL;
338 while (0 != bitmask)
339 {
340 if (bitmask & 1)
341 {
342 wpalTraceSetLevel(moduleId, level, 1);
343 }
344 level++;
345 bitmask >>= 1;
346 }
347}
348#endif /* FEATURE_WLAN_INTEGRATED_SOC */
349
350int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
351{
352 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
353 hdd_priv_data_t priv_data;
354 tANI_U8 *command = NULL;
355 int ret = 0;
356
357 if (NULL == pAdapter)
358 {
359 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700360 "%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700361 ret = -ENODEV;
362 goto exit;
363 }
364
Jeff Johnsone7245742012-09-05 17:12:55 -0700365 if ((!ifr) || (!ifr->ifr_data))
Jeff Johnson295189b2012-06-20 16:38:30 -0700366 {
367 ret = -EINVAL;
368 goto exit;
369 }
370
371 if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(hdd_priv_data_t)))
372 {
373 ret = -EFAULT;
374 goto exit;
375 }
376
377 command = kmalloc(priv_data.total_len, GFP_KERNEL);
378 if (!command)
379 {
380 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700381 "%s: failed to allocate memory\n", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700382 ret = -ENOMEM;
383 goto exit;
384 }
385
386 if (copy_from_user(command, priv_data.buf, priv_data.total_len))
387 {
388 ret = -EFAULT;
389 goto exit;
390 }
391
392 if ((SIOCDEVPRIVATE + 1) == cmd)
393 {
394 hdd_context_t *pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
395
396 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudif9bdd4e2012-10-30 18:05:03 -0700397 "%s: Received %s cmd from Wi-Fi GUI***", __func__, command);
Jeff Johnson295189b2012-06-20 16:38:30 -0700398
399 if (strncmp(command, "P2P_DEV_ADDR", 12) == 0 )
400 {
401 if (copy_to_user(priv_data.buf, pHddCtx->p2pDeviceAddress.bytes,
402 sizeof(tSirMacAddr)))
403 {
404 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700405 "%s: failed to copy data to user buffer\n", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700406 ret = -EFAULT;
407 }
408 }
Jeff Johnson32d95a32012-09-10 13:15:23 -0700409 else if(strncmp(priv_data.buf, "SETBAND", 7) == 0)
Jeff Johnson295189b2012-06-20 16:38:30 -0700410 {
411 tANI_U8 *ptr = (tANI_U8*)priv_data.buf ;
412 int ret = 0 ;
413
414 /* Change band request received */
415
416 /* First 8 bytes will have "SETBAND " and
417 * 9 byte will have band setting value */
Madan Mohan Koyyalamudi8bdd3112012-09-24 13:55:14 -0700418 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700419 "%s: SetBandCommand Info comm %s UL %d, TL %d", __func__, priv_data.buf, priv_data.used_len, priv_data.total_len);
Jeff Johnson295189b2012-06-20 16:38:30 -0700420
421 /* Change band request received */
422 ret = hdd_setBand_helper(dev, ptr);
423 }
Jeff Johnson32d95a32012-09-10 13:15:23 -0700424 else if ( strncasecmp(command, "COUNTRY", 7) == 0 )
425 {
426 char *country_code;
427
428 country_code = command + 8;
429 ret = (int)sme_ChangeCountryCode(pHddCtx->hHal, NULL, country_code,
430 pAdapter, pHddCtx->pvosContext);
431 if( 0 != ret )
432 {
433 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
434 "%s: SME Change Country code fail ret=%d\n",__func__, ret);
435
436 }
Madan Mohan Koyyalamudi1bed5982012-10-22 14:38:06 -0700437 }
438 /*
439 command should be a string having format
440 SET_SAP_CHANNEL_LIST <num of channels> <the channels seperated by spaces>
441 */
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -0700442 else if(strncmp(priv_data.buf, "SET_SAP_CHANNEL_LIST", 20) == 0)
Madan Mohan Koyyalamudi1bed5982012-10-22 14:38:06 -0700443 {
444 tANI_U8 *ptr = (tANI_U8*)priv_data.buf;
445
446 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700447 " Received Command to Set Preferred Channels for SAP in %s", __func__);
Madan Mohan Koyyalamudi1bed5982012-10-22 14:38:06 -0700448
449 ret = sapSetPreferredChannel(dev, ptr);
Jeff Johnson32d95a32012-09-10 13:15:23 -0700450 }
Madan Mohan Koyyalamudif9bdd4e2012-10-30 18:05:03 -0700451 else {
452 hddLog( VOS_TRACE_LEVEL_WARN, "%s: Unsupported GUI command %s",
453 __func__, command);
454 }
455
Jeff Johnson295189b2012-06-20 16:38:30 -0700456 }
457exit:
458 if (command)
459 {
460 kfree(command);
461 }
462 return ret;
463}
464
465/**---------------------------------------------------------------------------
466
467 \brief hdd_open() - HDD Open function
468
469 This is called in response to ifconfig up
470
471 \param - dev Pointer to net_device structure
472
473 \return - 0 for success non-zero for failure
474
475 --------------------------------------------------------------------------*/
476int hdd_open (struct net_device *dev)
477{
478 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
479 hdd_context_t *pHddCtx;
480 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
481 VOS_STATUS status;
482 v_BOOL_t in_standby = TRUE;
483
484 if (NULL == pAdapter)
485 {
486 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700487 "%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700488 return -ENODEV;
489 }
490
491 pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
492 if (NULL == pHddCtx)
493 {
494 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700495 "%s: HDD context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700496 return -ENODEV;
497 }
498
499 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
500 while ( (NULL != pAdapterNode) && (VOS_STATUS_SUCCESS == status) )
501 {
502 if( pAdapterNode->pAdapter->event_flags & DEVICE_IFACE_OPENED)
503 {
504 hddLog(VOS_TRACE_LEVEL_INFO, "%s: chip already out of "
505 "standby", __func__, pAdapter->device_mode);
506 in_standby = FALSE;
507 break;
508 }
509 else
510 {
511 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
512 pAdapterNode = pNext;
513 }
514 }
515
516 if (TRUE == in_standby)
517 {
518 if (VOS_STATUS_SUCCESS != wlan_hdd_exit_lowpower(pHddCtx, pAdapter))
519 {
520 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Failed to bring "
521 "wlan out of power save", __func__);
522 return -EINVAL;
523 }
524 }
525
526 pAdapter->event_flags |= DEVICE_IFACE_OPENED;
527 if (hdd_connIsConnected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
528 {
529 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700530 "%s: Enabling Tx Queues", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700531 /* Enable TX queues only when we are connected */
532 netif_tx_start_all_queues(dev);
533 }
534
535 return 0;
536}
537
538int hdd_mon_open (struct net_device *dev)
539{
540 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
541
542 if(pAdapter == NULL) {
543 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700544 "%s: HDD adapter context is Null", __func__);
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -0800545 return -EINVAL;
Jeff Johnson295189b2012-06-20 16:38:30 -0700546 }
547
548 netif_start_queue(dev);
549
550 return 0;
551}
552/**---------------------------------------------------------------------------
553
554 \brief hdd_stop() - HDD stop function
555
556 This is called in response to ifconfig down
557
558 \param - dev Pointer to net_device structure
559
560 \return - 0 for success non-zero for failure
561
562 --------------------------------------------------------------------------*/
563
564int hdd_stop (struct net_device *dev)
565{
566 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
567 hdd_context_t *pHddCtx;
568 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
569 VOS_STATUS status;
570 v_BOOL_t enter_standby = TRUE;
571
572 ENTER();
573
574 if (NULL == pAdapter)
575 {
576 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700577 "%s: HDD adapter context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700578 return -ENODEV;
579 }
580
581 pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
582 if (NULL == pHddCtx)
583 {
584 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -0700585 "%s: HDD context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700586 return -ENODEV;
587 }
588
589 pAdapter->event_flags &= ~(DEVICE_IFACE_OPENED);
590 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Disabling OS Tx queues", __func__);
591 netif_tx_disable(pAdapter->dev);
592 netif_carrier_off(pAdapter->dev);
593
594
595 /* SoftAP ifaces should never go in power save mode
596 making sure same here. */
597 if ( (WLAN_HDD_SOFTAP == pAdapter->device_mode )
598 || (WLAN_HDD_MONITOR == pAdapter->device_mode )
599#ifdef WLAN_FEATURE_P2P
600 || (WLAN_HDD_P2P_GO == pAdapter->device_mode )
601#endif
602 )
603 {
604 /* SoftAP mode, so return from here */
605 EXIT();
606 return 0;
607 }
608
609 /* Find if any iface is up then
610 if any iface is up then can't put device to sleep/ power save mode. */
611 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
612 while ( (NULL != pAdapterNode) && (VOS_STATUS_SUCCESS == status) )
613 {
614 if ( pAdapterNode->pAdapter->event_flags & DEVICE_IFACE_OPENED)
615 {
616 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Still other ifaces are up cannot "
617 "put device to sleep", __func__, pAdapter->device_mode);
618 enter_standby = FALSE;
619 break;
620 }
621 else
622 {
623 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
624 pAdapterNode = pNext;
625 }
626 }
627
628 if (TRUE == enter_standby)
629 {
630 hddLog(VOS_TRACE_LEVEL_INFO, "%s: All Interfaces are Down "
631 "entering standby", __func__);
632 if (VOS_STATUS_SUCCESS != wlan_hdd_enter_lowpower(pHddCtx))
633 {
634 /*log and return success*/
635 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Failed to put "
636 "wlan in power save", __func__);
637 }
638 }
639
640 EXIT();
641 return 0;
642}
643
644/**---------------------------------------------------------------------------
645
646 \brief hdd_uninit() - HDD uninit function
647
648 This is called during the netdev unregister to uninitialize all data
649associated with the device
650
651 \param - dev Pointer to net_device structure
652
653 \return - void
654
655 --------------------------------------------------------------------------*/
656static void hdd_uninit (struct net_device *dev)
657{
658 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
659
660 ENTER();
661
662 do
663 {
664 if (NULL == pAdapter)
665 {
666 hddLog(VOS_TRACE_LEVEL_FATAL,
667 "%s: NULL pAdapter", __func__);
668 break;
669 }
670
671 if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
672 {
673 hddLog(VOS_TRACE_LEVEL_FATAL,
674 "%s: Invalid magic", __func__);
675 break;
676 }
677
678 if (NULL == pAdapter->pHddCtx)
679 {
680 hddLog(VOS_TRACE_LEVEL_FATAL,
681 "%s: NULL pHddCtx", __func__);
682 break;
683 }
684
685 if (dev != pAdapter->dev)
686 {
687 hddLog(VOS_TRACE_LEVEL_FATAL,
688 "%s: Invalid device reference", __func__);
689 /* we haven't validated all cases so let this go for now */
690 }
691
692 hdd_deinit_adapter(pAdapter->pHddCtx, pAdapter);
693
694 /* after uninit our adapter structure will no longer be valid */
695 pAdapter->dev = NULL;
696 pAdapter->magic = 0;
697 } while (0);
698
699 EXIT();
700}
701
702/**---------------------------------------------------------------------------
703
704 \brief hdd_release_firmware() -
705
706 This function calls the release firmware API to free the firmware buffer.
707
708 \param - pFileName Pointer to the File Name.
709 pCtx - Pointer to the adapter .
710
711
712 \return - 0 for success, non zero for failure
713
714 --------------------------------------------------------------------------*/
715
716VOS_STATUS hdd_release_firmware(char *pFileName,v_VOID_t *pCtx)
717{
718 VOS_STATUS status = VOS_STATUS_SUCCESS;
719 hdd_context_t *pHddCtx = (hdd_context_t*)pCtx;
720 ENTER();
721
722
723 if (!strcmp(WLAN_FW_FILE, pFileName)) {
724
725 hddLog(VOS_TRACE_LEVEL_INFO_HIGH,"%s: Loaded firmware file is %s",__func__,pFileName);
726
727 if(pHddCtx->fw) {
728 release_firmware(pHddCtx->fw);
729 pHddCtx->fw = NULL;
730 }
731 else
732 status = VOS_STATUS_E_FAILURE;
733 }
734 else if (!strcmp(WLAN_NV_FILE,pFileName)) {
735 if(pHddCtx->nv) {
736 release_firmware(pHddCtx->nv);
737 pHddCtx->nv = NULL;
738 }
739 else
740 status = VOS_STATUS_E_FAILURE;
741
742 }
743
744 EXIT();
745 return status;
746}
747
748/**---------------------------------------------------------------------------
749
750 \brief hdd_request_firmware() -
751
752 This function reads the firmware file using the request firmware
753 API and returns the the firmware data and the firmware file size.
754
755 \param - pfileName - Pointer to the file name.
756 - pCtx - Pointer to the adapter .
757 - ppfw_data - Pointer to the pointer of the firmware data.
758 - pSize - Pointer to the file size.
759
760 \return - VOS_STATUS_SUCCESS for success, VOS_STATUS_E_FAILURE for failure
761
762 --------------------------------------------------------------------------*/
763
764
765VOS_STATUS hdd_request_firmware(char *pfileName,v_VOID_t *pCtx,v_VOID_t **ppfw_data, v_SIZE_t *pSize)
766{
767 int status;
768 VOS_STATUS retval = VOS_STATUS_SUCCESS;
769 hdd_context_t *pHddCtx = (hdd_context_t*)pCtx;
770 ENTER();
771
772 if( (!strcmp(WLAN_FW_FILE, pfileName)) ) {
773
774 status = request_firmware(&pHddCtx->fw, pfileName, pHddCtx->parent_dev);
775
776 if(status || !pHddCtx->fw || !pHddCtx->fw->data) {
777 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Firmware %s download failed",
778 __func__, pfileName);
779 retval = VOS_STATUS_E_FAILURE;
780 }
781
782 else {
783 *ppfw_data = (v_VOID_t *)pHddCtx->fw->data;
784 *pSize = pHddCtx->fw->size;
785 hddLog(VOS_TRACE_LEVEL_INFO, "%s: Firmware size = %d",
786 __func__, *pSize);
787 }
788 }
789 else if(!strcmp(WLAN_NV_FILE, pfileName)) {
790
791 status = request_firmware(&pHddCtx->nv, pfileName, pHddCtx->parent_dev);
792
793 if(status || !pHddCtx->nv || !pHddCtx->nv->data) {
794 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: nv %s download failed",
795 __func__, pfileName);
796 retval = VOS_STATUS_E_FAILURE;
797 }
798
799 else {
800 *ppfw_data = (v_VOID_t *)pHddCtx->nv->data;
801 *pSize = pHddCtx->nv->size;
802 hddLog(VOS_TRACE_LEVEL_INFO, "%s: nv file size = %d",
803 __func__, *pSize);
804 }
805 }
806
807 EXIT();
808 return retval;
809}
810/**---------------------------------------------------------------------------
811 \brief hdd_full_pwr_cbk() - HDD full power callbackfunction
812
813 This is the function invoked by SME to inform the result of a full power
814 request issued by HDD
815
816 \param - callbackcontext - Pointer to cookie
817 status - result of request
818
819 \return - None
820
821--------------------------------------------------------------------------*/
822void hdd_full_pwr_cbk(void *callbackContext, eHalStatus status)
823{
824 hdd_context_t *pHddCtx = (hdd_context_t*)callbackContext;
825
Madan Mohan Koyyalamudi8bdd3112012-09-24 13:55:14 -0700826 hddLog(VOS_TRACE_LEVEL_INFO_HIGH,"HDD full Power callback status = %d", status);
Jeff Johnson295189b2012-06-20 16:38:30 -0700827 if(&pHddCtx->full_pwr_comp_var)
828 {
829 complete(&pHddCtx->full_pwr_comp_var);
830 }
831}
832
833/**---------------------------------------------------------------------------
834
835 \brief hdd_req_bmps_cbk() - HDD Request BMPS callback function
836
837 This is the function invoked by SME to inform the result of BMPS
838 request issued by HDD
839
840 \param - callbackcontext - Pointer to cookie
841 status - result of request
842
843 \return - None
844
845--------------------------------------------------------------------------*/
846void hdd_req_bmps_cbk(void *callbackContext, eHalStatus status)
847{
848
849 struct completion *completion_var = (struct completion*) callbackContext;
850
851 hddLog(VOS_TRACE_LEVEL_ERROR, "HDD BMPS request Callback, status = %d\n", status);
852 if(completion_var != NULL)
853 {
854 complete(completion_var);
855 }
856}
857
858/**---------------------------------------------------------------------------
859
860 \brief hdd_get_cfg_file_size() -
861
862 This function reads the configuration file using the request firmware
863 API and returns the configuration file size.
864
865 \param - pCtx - Pointer to the adapter .
866 - pFileName - Pointer to the file name.
867 - pBufSize - Pointer to the buffer size.
868
869 \return - 0 for success, non zero for failure
870
871 --------------------------------------------------------------------------*/
872
873VOS_STATUS hdd_get_cfg_file_size(v_VOID_t *pCtx, char *pFileName, v_SIZE_t *pBufSize)
874{
875 int status;
876 hdd_context_t *pHddCtx = (hdd_context_t*)pCtx;
877
878 ENTER();
879
880 status = request_firmware(&pHddCtx->fw, pFileName, pHddCtx->parent_dev);
881
882 if(status || !pHddCtx->fw || !pHddCtx->fw->data) {
883 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: CFG download failed",__func__);
884 status = VOS_STATUS_E_FAILURE;
885 }
886 else {
887 *pBufSize = pHddCtx->fw->size;
888 hddLog(VOS_TRACE_LEVEL_INFO, "%s: CFG size = %d", __func__, *pBufSize);
889 release_firmware(pHddCtx->fw);
890 pHddCtx->fw = NULL;
891 }
892
893 EXIT();
894 return VOS_STATUS_SUCCESS;
895}
896
897/**---------------------------------------------------------------------------
898
899 \brief hdd_read_cfg_file() -
900
901 This function reads the configuration file using the request firmware
902 API and returns the cfg data and the buffer size of the configuration file.
903
904 \param - pCtx - Pointer to the adapter .
905 - pFileName - Pointer to the file name.
906 - pBuffer - Pointer to the data buffer.
907 - pBufSize - Pointer to the buffer size.
908
909 \return - 0 for success, non zero for failure
910
911 --------------------------------------------------------------------------*/
912
913VOS_STATUS hdd_read_cfg_file(v_VOID_t *pCtx, char *pFileName,
914 v_VOID_t *pBuffer, v_SIZE_t *pBufSize)
915{
916 int status;
917 hdd_context_t *pHddCtx = (hdd_context_t*)pCtx;
918
919 ENTER();
920
921 status = request_firmware(&pHddCtx->fw, pFileName, pHddCtx->parent_dev);
922
923 if(status || !pHddCtx->fw || !pHddCtx->fw->data) {
924 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: CFG download failed",__func__);
925 return VOS_STATUS_E_FAILURE;
926 }
927 else {
928 if(*pBufSize != pHddCtx->fw->size) {
929 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Caller sets invalid CFG "
930 "file size", __func__);
931 release_firmware(pHddCtx->fw);
932 pHddCtx->fw = NULL;
933 return VOS_STATUS_E_FAILURE;
934 }
935 else {
936 if(pBuffer) {
937 vos_mem_copy(pBuffer,pHddCtx->fw->data,*pBufSize);
938 }
939 release_firmware(pHddCtx->fw);
940 pHddCtx->fw = NULL;
941 }
942 }
943
944 EXIT();
945
946 return VOS_STATUS_SUCCESS;
947}
948
949/**---------------------------------------------------------------------------
950
951 \brief hdd_set_mac_addr_cb() -
952
953 This function is the call back function for setting the station
954 mac adrress called by ccm module to indicate the
955 success/failure result.
956
957 \param - hHal - Pointer to the hal module.
958 - result - returns the result of the set mac address.
959
960 \return - void
961
962 --------------------------------------------------------------------------*/
963#ifndef FEATURE_WLAN_INTEGRATED_SOC
964static void hdd_set_mac_addr_cb( tHalHandle hHal, tANI_S32 result )
965{
966 // ignore the STA_ID response for now.
967
968 VOS_ASSERT( CCM_IS_RESULT_SUCCESS( result ) );
969}
970#endif
971
972
973/**---------------------------------------------------------------------------
974
975 \brief hdd_set_mac_address() -
976
977 This function sets the user specified mac address using
978 the command ifconfig wlanX hw ether <mac adress>.
979
980 \param - dev - Pointer to the net device.
981 - addr - Pointer to the sockaddr.
982 \return - 0 for success, non zero for failure
983
984 --------------------------------------------------------------------------*/
985
986static int hdd_set_mac_address(struct net_device *dev, void *addr)
987{
988 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
989 struct sockaddr *psta_mac_addr = addr;
990 eHalStatus halStatus = eHAL_STATUS_SUCCESS;
991
992 ENTER();
993
994 memcpy(&pAdapter->macAddressCurrent, psta_mac_addr->sa_data, ETH_ALEN);
995
996#ifdef HDD_SESSIONIZE
997 // set the MAC address though the STA ID CFG.
998 halStatus = ccmCfgSetStr( pAdapter->hHal, WNI_CFG_STA_ID,
999 (v_U8_t *)&pAdapter->macAddressCurrent,
1000 sizeof( pAdapter->macAddressCurrent ),
1001 hdd_set_mac_addr_cb, VOS_FALSE );
1002#endif
1003
1004 memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN);
1005
1006 EXIT();
1007 return halStatus;
1008}
1009
1010tANI_U8* wlan_hdd_get_intf_addr(hdd_context_t* pHddCtx)
1011{
1012 int i;
1013 for ( i = 0; i < VOS_MAX_CONCURRENCY_PERSONA; i++)
1014 {
1015 if( 0 == (pHddCtx->cfg_ini->intfAddrMask >> i))
1016 break;
1017 }
1018
1019 if( VOS_MAX_CONCURRENCY_PERSONA == i)
1020 return NULL;
1021
1022 pHddCtx->cfg_ini->intfAddrMask |= (1 << i);
1023 return &pHddCtx->cfg_ini->intfMacAddr[i].bytes[0];
1024}
1025
1026void wlan_hdd_release_intf_addr(hdd_context_t* pHddCtx, tANI_U8* releaseAddr)
1027{
1028 int i;
1029 for ( i = 0; i < VOS_MAX_CONCURRENCY_PERSONA; i++)
1030 {
1031 if ( !memcmp(releaseAddr, &pHddCtx->cfg_ini->intfMacAddr[i].bytes[0], 6) )
1032 {
1033 pHddCtx->cfg_ini->intfAddrMask &= ~(1 << i);
1034 break;
1035 }
1036 }
1037 return;
1038}
1039
1040#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
1041 static struct net_device_ops wlan_drv_ops = {
1042 .ndo_open = hdd_open,
1043 .ndo_stop = hdd_stop,
1044 .ndo_uninit = hdd_uninit,
1045 .ndo_start_xmit = hdd_hard_start_xmit,
1046 .ndo_tx_timeout = hdd_tx_timeout,
1047 .ndo_get_stats = hdd_stats,
1048 .ndo_do_ioctl = hdd_ioctl,
1049 .ndo_set_mac_address = hdd_set_mac_address,
1050 .ndo_select_queue = hdd_select_queue,
1051#ifdef WLAN_FEATURE_PACKET_FILTERING
1052#if (LINUX_VERSION_CODE > KERNEL_VERSION(3,1,0))
1053 .ndo_set_rx_mode = hdd_set_multicast_list,
1054#else
1055 .ndo_set_multicast_list = hdd_set_multicast_list,
1056#endif //LINUX_VERSION_CODE
1057#endif
1058 };
1059#ifdef CONFIG_CFG80211
1060 static struct net_device_ops wlan_mon_drv_ops = {
1061 .ndo_open = hdd_mon_open,
1062 .ndo_stop = hdd_stop,
1063 .ndo_uninit = hdd_uninit,
1064 .ndo_start_xmit = hdd_mon_hard_start_xmit,
1065 .ndo_tx_timeout = hdd_tx_timeout,
1066 .ndo_get_stats = hdd_stats,
1067 .ndo_do_ioctl = hdd_ioctl,
1068 .ndo_set_mac_address = hdd_set_mac_address,
1069 };
1070#endif
1071
1072#endif
1073
1074void hdd_set_station_ops( struct net_device *pWlanDev )
1075{
1076#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
1077 pWlanDev->tx_queue_len = NET_DEV_TX_QUEUE_LEN,
1078 pWlanDev->netdev_ops = &wlan_drv_ops;
1079#else
1080 pWlanDev->open = hdd_open;
1081 pWlanDev->stop = hdd_stop;
1082 pWlanDev->uninit = hdd_uninit;
1083 pWlanDev->hard_start_xmit = NULL;
1084 pWlanDev->tx_timeout = hdd_tx_timeout;
1085 pWlanDev->get_stats = hdd_stats;
1086 pWlanDev->do_ioctl = hdd_ioctl;
1087 pWlanDev->tx_queue_len = NET_DEV_TX_QUEUE_LEN;
1088 pWlanDev->set_mac_address = hdd_set_mac_address;
1089#endif
1090}
1091
1092hdd_adapter_t* hdd_alloc_station_adapter( hdd_context_t *pHddCtx, tSirMacAddr macAddr, char* name )
1093{
1094 struct net_device *pWlanDev = NULL;
1095 hdd_adapter_t *pAdapter = NULL;
1096#ifdef CONFIG_CFG80211
1097 /*
1098 * cfg80211 initialization and registration....
1099 */
1100 pWlanDev = alloc_netdev_mq(sizeof( hdd_adapter_t ), name, ether_setup, NUM_TX_QUEUES);
1101
1102#else
1103 //Allocate the net_device and private data (station ctx)
1104 pWlanDev = alloc_etherdev_mq(sizeof( hdd_adapter_t ), NUM_TX_QUEUES);
1105
1106#endif
1107
1108 if(pWlanDev != NULL)
1109 {
1110
1111 //Save the pointer to the net_device in the HDD adapter
1112 pAdapter = (hdd_adapter_t*) netdev_priv( pWlanDev );
1113
1114#ifndef CONFIG_CFG80211
1115 //Init the net_device structure
1116 ether_setup(pWlanDev);
1117#endif
1118
1119 vos_mem_zero( pAdapter, sizeof( hdd_adapter_t ) );
1120
1121 pAdapter->dev = pWlanDev;
1122 pAdapter->pHddCtx = pHddCtx;
1123 pAdapter->magic = WLAN_HDD_ADAPTER_MAGIC;
1124
1125 init_completion(&pAdapter->session_open_comp_var);
1126 init_completion(&pAdapter->session_close_comp_var);
1127 init_completion(&pAdapter->disconnect_comp_var);
1128 init_completion(&pAdapter->linkup_event_var);
1129 init_completion(&pAdapter->cancel_rem_on_chan_var);
1130 init_completion(&pAdapter->rem_on_chan_ready_event);
Jeff Johnson295189b2012-06-20 16:38:30 -07001131#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1132 init_completion(&pAdapter->offchannel_tx_event);
1133#endif
1134#ifdef CONFIG_CFG80211
1135 init_completion(&pAdapter->tx_action_cnf_event);
1136#endif
1137 init_completion(&pHddCtx->mc_sus_event_var);
1138 init_completion(&pHddCtx->tx_sus_event_var);
1139
Jeff Johnson295189b2012-06-20 16:38:30 -07001140 pAdapter->isLinkUpSvcNeeded = FALSE;
1141 pAdapter->higherDtimTransition = eANI_BOOLEAN_TRUE;
1142 //Init the net_device structure
1143 strlcpy(pWlanDev->name, name, IFNAMSIZ);
1144
1145 vos_mem_copy(pWlanDev->dev_addr, (void *)macAddr, sizeof(tSirMacAddr));
1146 vos_mem_copy( pAdapter->macAddressCurrent.bytes, macAddr, sizeof(tSirMacAddr));
1147 pWlanDev->watchdog_timeo = HDD_TX_TIMEOUT;
1148 pWlanDev->hard_header_len += LIBRA_HW_NEEDED_HEADROOM;
1149
1150 hdd_set_station_ops( pAdapter->dev );
1151
1152 pWlanDev->destructor = free_netdev;
1153#ifdef CONFIG_CFG80211
1154 pWlanDev->ieee80211_ptr = &pAdapter->wdev ;
1155 pAdapter->wdev.wiphy = pHddCtx->wiphy;
1156 pAdapter->wdev.netdev = pWlanDev;
1157#endif
1158 /* set pWlanDev's parent to underlying device */
1159 SET_NETDEV_DEV(pWlanDev, pHddCtx->parent_dev);
1160 }
1161
1162 return pAdapter;
1163}
1164
1165VOS_STATUS hdd_register_interface( hdd_adapter_t *pAdapter, tANI_U8 rtnl_lock_held )
1166{
1167 struct net_device *pWlanDev = pAdapter->dev;
1168 //hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
1169 //hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
1170 //eHalStatus halStatus = eHAL_STATUS_SUCCESS;
1171
1172 if( rtnl_lock_held )
1173 {
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -08001174 if (strnchr(pWlanDev->name, strlen(pWlanDev->name), '%')) {
Jeff Johnson295189b2012-06-20 16:38:30 -07001175 if( dev_alloc_name(pWlanDev, pWlanDev->name) < 0 )
1176 {
1177 hddLog(VOS_TRACE_LEVEL_ERROR,"%s:Failed:dev_alloc_name",__func__);
1178 return VOS_STATUS_E_FAILURE;
1179 }
1180 }
1181 if (register_netdevice(pWlanDev))
1182 {
1183 hddLog(VOS_TRACE_LEVEL_ERROR,"%s:Failed:register_netdev",__func__);
1184 return VOS_STATUS_E_FAILURE;
1185 }
1186 }
1187 else
1188 {
1189 if(register_netdev(pWlanDev))
1190 {
1191 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed:register_netdev",__func__);
1192 return VOS_STATUS_E_FAILURE;
1193 }
1194 }
1195 set_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags);
1196
1197 return VOS_STATUS_SUCCESS;
1198}
1199
1200eHalStatus hdd_smeCloseSessionCallback(void *pContext)
1201{
1202 if(pContext != NULL)
1203 {
1204 clear_bit(SME_SESSION_OPENED, &((hdd_adapter_t*)pContext)->event_flags);
1205
1206 /* need to make sure all of our scheduled work has completed.
1207 * This callback is called from MC thread context, so it is safe to
1208 * to call below flush workqueue API from here.
1209 */
1210 flush_scheduled_work();
1211 complete(&((hdd_adapter_t*)pContext)->session_close_comp_var);
1212 }
1213 return eHAL_STATUS_SUCCESS;
1214}
1215
1216VOS_STATUS hdd_init_station_mode( hdd_adapter_t *pAdapter )
1217{
1218 struct net_device *pWlanDev = pAdapter->dev;
1219 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
1220 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
1221 eHalStatus halStatus = eHAL_STATUS_SUCCESS;
1222 VOS_STATUS status = VOS_STATUS_E_FAILURE;
1223 int rc = 0;
1224
1225 INIT_COMPLETION(pAdapter->session_open_comp_var);
1226 //Open a SME session for future operation
1227 halStatus = sme_OpenSession( pHddCtx->hHal, hdd_smeRoamCallback, pAdapter,
1228 (tANI_U8 *)&pAdapter->macAddressCurrent, &pAdapter->sessionId );
1229 if ( !HAL_STATUS_SUCCESS( halStatus ) )
1230 {
1231 hddLog(VOS_TRACE_LEVEL_FATAL,
1232 "sme_OpenSession() failed with status code %08d [x%08lx]",
1233 halStatus, halStatus );
1234 status = VOS_STATUS_E_FAILURE;
1235 goto error_sme_open;
1236 }
1237
1238 //Block on a completion variable. Can't wait forever though.
1239 rc = wait_for_completion_interruptible_timeout(
1240 &pAdapter->session_open_comp_var,
1241 msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
1242 if (!rc)
1243 {
1244 hddLog(VOS_TRACE_LEVEL_FATAL,
1245 "Session is not opened within timeout period code %08d", rc );
1246 status = VOS_STATUS_E_FAILURE;
1247 goto error_sme_open;
1248 }
1249
1250 // Register wireless extensions
1251 if( eHAL_STATUS_SUCCESS != (halStatus = hdd_register_wext(pWlanDev)))
1252 {
1253 hddLog(VOS_TRACE_LEVEL_FATAL,
1254 "hdd_register_wext() failed with status code %08d [x%08lx]",
1255 halStatus, halStatus );
1256 status = VOS_STATUS_E_FAILURE;
1257 goto error_register_wext;
1258 }
1259 //Safe to register the hard_start_xmit function again
1260#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
1261 wlan_drv_ops.ndo_start_xmit = hdd_hard_start_xmit;
1262#else
1263 pWlanDev->hard_start_xmit = hdd_hard_start_xmit;
1264#endif
1265
1266 //Set the Connection State to Not Connected
1267 pHddStaCtx->conn_info.connState = eConnectionState_NotConnected;
1268
1269 //Set the default operation channel
1270 pHddStaCtx->conn_info.operationChannel = pHddCtx->cfg_ini->OperatingChannel;
1271
1272 /* Make the default Auth Type as OPEN*/
1273 pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM;
1274
1275 if( VOS_STATUS_SUCCESS != ( status = hdd_init_tx_rx( pAdapter ) ) )
1276 {
1277 hddLog(VOS_TRACE_LEVEL_FATAL,
1278 "hdd_init_tx_rx() failed with status code %08d [x%08lx]",
1279 status, status );
1280 goto error_init_txrx;
1281 }
1282
1283 set_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1284
1285 if( VOS_STATUS_SUCCESS != ( status = hdd_wmm_adapter_init( pAdapter ) ) )
1286 {
1287 hddLog(VOS_TRACE_LEVEL_FATAL,
1288 "hdd_wmm_adapter_init() failed with status code %08d [x%08lx]",
1289 status, status );
1290 goto error_wmm_init;
1291 }
1292
1293 set_bit(WMM_INIT_DONE, &pAdapter->event_flags);
1294
1295 return VOS_STATUS_SUCCESS;
1296
1297error_wmm_init:
1298 clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1299 hdd_deinit_tx_rx(pAdapter);
1300error_init_txrx:
1301 hdd_UnregisterWext(pWlanDev);
1302error_register_wext:
1303 if(test_bit(SME_SESSION_OPENED, &pAdapter->event_flags))
1304 {
1305 INIT_COMPLETION(pAdapter->session_close_comp_var);
1306 if( eHAL_STATUS_SUCCESS == sme_CloseSession( pHddCtx->hHal,
1307 pAdapter->sessionId,
1308 hdd_smeCloseSessionCallback, pAdapter ) )
1309 {
1310 //Block on a completion variable. Can't wait forever though.
1311 wait_for_completion_interruptible_timeout(
1312 &pAdapter->session_close_comp_var,
1313 msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
1314 }
1315}
1316error_sme_open:
1317 return status;
1318}
1319
Jeff Johnson295189b2012-06-20 16:38:30 -07001320#ifdef CONFIG_CFG80211
1321void hdd_cleanup_actionframe( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
1322{
1323 hdd_cfg80211_state_t *cfgState;
1324
1325 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
1326
1327 if( NULL != cfgState->buf )
1328 {
1329 int rc;
1330 INIT_COMPLETION(pAdapter->tx_action_cnf_event);
1331 rc = wait_for_completion_interruptible_timeout(
1332 &pAdapter->tx_action_cnf_event,
1333 msecs_to_jiffies(ACTION_FRAME_TX_TIMEOUT));
1334 if(!rc)
1335 {
1336 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1337 ("ERROR: HDD Wait for Action Confirmation Failed!!\n"));
1338 }
1339 }
1340 return;
1341}
1342#endif
1343
1344void hdd_deinit_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
1345{
1346 ENTER();
1347 switch ( pAdapter->device_mode )
1348 {
1349 case WLAN_HDD_INFRA_STATION:
1350 case WLAN_HDD_P2P_CLIENT:
Jeff Johnsone7245742012-09-05 17:12:55 -07001351 case WLAN_HDD_P2P_DEVICE:
Jeff Johnson295189b2012-06-20 16:38:30 -07001352 {
1353 if(test_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags))
1354 {
1355 hdd_deinit_tx_rx( pAdapter );
1356 clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1357 }
1358
1359 if(test_bit(WMM_INIT_DONE, &pAdapter->event_flags))
1360 {
1361 hdd_wmm_adapter_close( pAdapter );
1362 clear_bit(WMM_INIT_DONE, &pAdapter->event_flags);
1363 }
1364
1365#ifdef CONFIG_CFG80211
1366 hdd_cleanup_actionframe(pHddCtx, pAdapter);
1367#endif
1368
1369 break;
1370 }
1371
1372 case WLAN_HDD_SOFTAP:
1373 case WLAN_HDD_P2P_GO:
1374#ifdef WLAN_SOFTAP_FEATURE
1375 {
1376#ifdef CONFIG_CFG80211
1377 hdd_cleanup_actionframe(pHddCtx, pAdapter);
1378#endif
1379
1380 hdd_unregister_hostapd(pAdapter);
1381 hdd_set_conparam( 0 );
1382#ifdef CONFIG_CFG80211
1383 wlan_hdd_set_monitor_tx_adapter( WLAN_HDD_GET_CTX(pAdapter), NULL );
1384#endif
1385 break;
1386 }
1387
1388 case WLAN_HDD_MONITOR:
1389 {
1390#ifdef CONFIG_CFG80211
1391 hdd_adapter_t* pAdapterforTx = pAdapter->sessionCtx.monitor.pAdapterForTx;
1392#endif
1393 if(test_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags))
1394 {
1395 hdd_deinit_tx_rx( pAdapter );
1396 clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1397 }
1398#ifdef CONFIG_CFG80211
1399 if(NULL != pAdapterforTx)
1400 {
1401 hdd_cleanup_actionframe(pHddCtx, pAdapterforTx);
1402 }
1403#endif
1404#endif //WLAN_SOFTAP_FEATURE
1405 break;
1406 }
1407
1408
1409 default:
1410 break;
1411 }
1412
1413 EXIT();
1414}
1415
1416void hdd_cleanup_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, tANI_U8 rtnl_held )
1417{
1418 struct net_device *pWlanDev = pAdapter->dev;
1419
1420 if(test_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags)) {
1421 if( rtnl_held )
1422 {
1423 unregister_netdevice(pWlanDev);
1424 }
1425 else
1426 {
1427 unregister_netdev(pWlanDev);
1428 }
1429 // note that the pAdapter is no longer valid at this point
1430 // since the memory has been reclaimed
1431 }
1432
1433}
1434
1435VOS_STATUS hdd_enable_bmps_imps(hdd_context_t *pHddCtx)
1436{
1437 VOS_STATUS status = VOS_STATUS_SUCCESS;
1438
1439 if(pHddCtx->cfg_ini->fIsBmpsEnabled)
1440 {
1441 sme_EnablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE);
1442 }
1443
1444 if(pHddCtx->cfg_ini->fIsAutoBmpsTimerEnabled)
1445 {
1446 sme_StartAutoBmpsTimer(pHddCtx->hHal);
1447 }
1448
1449 if (pHddCtx->cfg_ini->fIsImpsEnabled)
1450 {
1451 sme_EnablePowerSave (pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE);
1452 }
1453
1454 return status;
1455}
1456
1457VOS_STATUS hdd_disable_bmps_imps(hdd_context_t *pHddCtx, tANI_U8 session_type)
1458{
1459 hdd_adapter_t *pAdapter = NULL;
1460 eHalStatus halStatus;
1461 VOS_STATUS status = VOS_STATUS_E_INVAL;
1462 v_BOOL_t disableBmps = FALSE;
1463 v_BOOL_t disableImps = FALSE;
1464
1465 switch(session_type)
1466 {
1467 case WLAN_HDD_INFRA_STATION:
1468 case WLAN_HDD_SOFTAP:
1469#ifdef WLAN_FEATURE_P2P
1470 case WLAN_HDD_P2P_CLIENT:
1471 case WLAN_HDD_P2P_GO:
1472#endif
1473 //Exit BMPS -> Is Sta/P2P Client is already connected
1474 pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION);
1475 if((NULL != pAdapter)&&
1476 hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
1477 {
1478 disableBmps = TRUE;
1479 }
1480
1481 pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_P2P_CLIENT);
1482 if((NULL != pAdapter)&&
1483 hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
1484 {
1485 disableBmps = TRUE;
1486 }
1487
1488 //Exit both Bmps and Imps incase of Go/SAP Mode
1489 if((WLAN_HDD_SOFTAP == session_type) ||
1490 (WLAN_HDD_P2P_GO == session_type))
1491 {
1492 disableBmps = TRUE;
1493 disableImps = TRUE;
1494 }
1495
1496 if(TRUE == disableImps)
1497 {
1498 if (pHddCtx->cfg_ini->fIsImpsEnabled)
1499 {
1500 sme_DisablePowerSave (pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE);
1501 }
1502 }
1503
1504 if(TRUE == disableBmps)
1505 {
1506 if(pHddCtx->cfg_ini->fIsBmpsEnabled)
1507 {
1508 halStatus = sme_DisablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE);
1509
1510 if(eHAL_STATUS_SUCCESS != halStatus)
1511 {
1512 status = VOS_STATUS_E_FAILURE;
1513 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Fail to Disable Power Save\n", __func__);
1514 VOS_ASSERT(0);
1515 return status;
1516 }
1517 }
1518
1519 if(pHddCtx->cfg_ini->fIsAutoBmpsTimerEnabled)
1520 {
1521 halStatus = sme_StopAutoBmpsTimer(pHddCtx->hHal);
1522
1523 if(eHAL_STATUS_SUCCESS != halStatus)
1524 {
1525 status = VOS_STATUS_E_FAILURE;
1526 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Fail to Stop Auto Bmps Timer\n", __func__);
1527 VOS_ASSERT(0);
1528 return status;
1529 }
1530 }
1531 }
1532
1533 if((TRUE == disableBmps) ||
1534 (TRUE == disableImps))
1535 {
1536 /* Now, get the chip into Full Power now */
1537 INIT_COMPLETION(pHddCtx->full_pwr_comp_var);
1538 halStatus = sme_RequestFullPower(pHddCtx->hHal, hdd_full_pwr_cbk,
1539 pHddCtx, eSME_FULL_PWR_NEEDED_BY_HDD);
1540
1541 if(halStatus != eHAL_STATUS_SUCCESS)
1542 {
1543 if(halStatus == eHAL_STATUS_PMC_PENDING)
1544 {
1545 //Block on a completion variable. Can't wait forever though
1546 wait_for_completion_interruptible_timeout(
1547 &pHddCtx->full_pwr_comp_var, msecs_to_jiffies(1000));
1548 }
1549 else
1550 {
1551 status = VOS_STATUS_E_FAILURE;
1552 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Request for Full Power failed\n", __func__);
1553 VOS_ASSERT(0);
1554 return status;
1555 }
1556 }
1557
1558 status = VOS_STATUS_SUCCESS;
1559 }
1560
1561 break;
1562 }
1563 return status;
1564}
1565
1566hdd_adapter_t* hdd_open_adapter( hdd_context_t *pHddCtx, tANI_U8 session_type,
1567 char *iface_name, tSirMacAddr macAddr,
1568 tANI_U8 rtnl_held )
1569{
1570 hdd_adapter_t *pAdapter = NULL;
1571 hdd_adapter_list_node_t *pHddAdapterNode = NULL;
1572 VOS_STATUS status = VOS_STATUS_E_FAILURE;
1573 VOS_STATUS exitbmpsStatus;
1574
1575 hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "%s iface =%s type = %d\n",__func__,iface_name,session_type);
1576
1577 //Disable BMPS incase of Concurrency
1578 exitbmpsStatus = hdd_disable_bmps_imps(pHddCtx, session_type);
1579
1580 if(VOS_STATUS_E_FAILURE == exitbmpsStatus)
1581 {
1582 //Fail to Exit BMPS
1583 VOS_ASSERT(0);
1584 return NULL;
1585 }
1586
1587 switch(session_type)
1588 {
1589 case WLAN_HDD_INFRA_STATION:
1590#ifdef WLAN_FEATURE_P2P
1591 case WLAN_HDD_P2P_CLIENT:
Jeff Johnsone7245742012-09-05 17:12:55 -07001592 case WLAN_HDD_P2P_DEVICE:
Jeff Johnson295189b2012-06-20 16:38:30 -07001593#endif
1594 {
1595 pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );
1596
1597 if( NULL == pAdapter )
1598 return NULL;
1599
1600#ifdef CONFIG_CFG80211
Jeff Johnsone7245742012-09-05 17:12:55 -07001601 pAdapter->wdev.iftype = (session_type == WLAN_HDD_P2P_CLIENT) ?
1602 NL80211_IFTYPE_P2P_CLIENT:
1603 NL80211_IFTYPE_STATION;
Jeff Johnson295189b2012-06-20 16:38:30 -07001604#endif
1605
Jeff Johnson295189b2012-06-20 16:38:30 -07001606 pAdapter->device_mode = session_type;
1607
1608 status = hdd_init_station_mode( pAdapter );
1609 if( VOS_STATUS_SUCCESS != status )
1610 goto err_free_netdev;
1611
1612 status = hdd_register_interface( pAdapter, rtnl_held );
1613 if( VOS_STATUS_SUCCESS != status )
1614 {
1615 hdd_deinit_adapter(pHddCtx, pAdapter);
1616 goto err_free_netdev;
1617 }
1618 //Stop the Interface TX queue.
1619 netif_tx_disable(pAdapter->dev);
1620 //netif_tx_disable(pWlanDev);
1621 netif_carrier_off(pAdapter->dev);
1622
1623 break;
1624 }
1625
1626#ifdef WLAN_FEATURE_P2P
1627 case WLAN_HDD_P2P_GO:
1628#endif
1629 case WLAN_HDD_SOFTAP:
1630 {
1631 pAdapter = hdd_wlan_create_ap_dev( pHddCtx, macAddr, (tANI_U8 *)iface_name );
1632 if( NULL == pAdapter )
1633 return NULL;
1634
1635#ifdef CONFIG_CFG80211
1636 pAdapter->wdev.iftype = (session_type == WLAN_HDD_SOFTAP) ?
1637 NL80211_IFTYPE_AP:
1638 NL80211_IFTYPE_P2P_GO;
1639#endif
1640 pAdapter->device_mode = session_type;
1641
1642 status = hdd_init_ap_mode(pAdapter);
1643 if( VOS_STATUS_SUCCESS != status )
1644 goto err_free_netdev;
1645
1646 status = hdd_register_hostapd( pAdapter, rtnl_held );
1647 if( VOS_STATUS_SUCCESS != status )
1648 {
1649 hdd_deinit_adapter(pHddCtx, pAdapter);
1650 goto err_free_netdev;
1651 }
1652
1653 netif_tx_disable(pAdapter->dev);
1654 netif_carrier_off(pAdapter->dev);
1655
1656 hdd_set_conparam( 1 );
1657 break;
1658 }
1659 case WLAN_HDD_MONITOR:
1660 {
1661#ifdef CONFIG_CFG80211
1662 pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );
1663 if( NULL == pAdapter )
1664 return NULL;
1665
1666 pAdapter->wdev.iftype = NL80211_IFTYPE_MONITOR;
1667 pAdapter->device_mode = session_type;
1668 status = hdd_register_interface( pAdapter, rtnl_held );
1669#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)
1670 pAdapter->dev->netdev_ops = &wlan_mon_drv_ops;
1671#else
1672 pAdapter->dev->open = hdd_mon_open;
1673 pAdapter->dev->hard_start_xmit = hdd_mon_hard_start_xmit;
1674#endif
1675 hdd_init_tx_rx( pAdapter );
1676 set_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1677 //Set adapter to be used for data tx. It will use either GO or softap.
1678 pAdapter->sessionCtx.monitor.pAdapterForTx =
1679 hdd_get_adapter(pAdapter->pHddCtx, WLAN_HDD_SOFTAP);
1680#ifdef WLAN_FEATURE_P2P
1681 if (NULL == pAdapter->sessionCtx.monitor.pAdapterForTx)
1682 {
1683 pAdapter->sessionCtx.monitor.pAdapterForTx =
1684 hdd_get_adapter(pAdapter->pHddCtx, WLAN_HDD_P2P_GO);
1685 }
1686#endif
1687 /* This workqueue will be used to transmit management packet over
1688 * monitor interface. */
Madan Mohan Koyyalamudic75be962012-10-18 19:19:03 -07001689 if (NULL == pAdapter->sessionCtx.monitor.pAdapterForTx) {
1690 hddLog(VOS_TRACE_LEVEL_ERROR,"%s:Failed:hdd_get_adapter",__func__);
1691 return NULL;
1692 }
Madan Mohan Koyyalamudi9f40ceb2012-10-18 19:22:56 -07001693
Jeff Johnson295189b2012-06-20 16:38:30 -07001694 INIT_WORK(&pAdapter->sessionCtx.monitor.pAdapterForTx->monTxWorkQueue,
1695 hdd_mon_tx_work_queue);
1696#endif
1697 }
1698 break;
1699#ifdef ANI_MANF_DIAG
1700 case WLAN_HDD_FTM:
1701 {
1702 pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );
1703
1704 if( NULL == pAdapter )
1705 return NULL;
1706 /* Assign NL80211_IFTYPE_STATION as interface type to resolve Kernel Warning
1707 * message while loading driver in FTM mode. */
1708 pAdapter->wdev.iftype = NL80211_IFTYPE_STATION;
1709 pAdapter->device_mode = session_type;
1710 status = hdd_register_interface( pAdapter, rtnl_held );
1711 }
1712 break;
1713#endif
1714 default:
1715 {
1716 VOS_ASSERT(0);
1717 return NULL;
1718 }
1719 }
1720
1721
1722 if( VOS_STATUS_SUCCESS == status )
1723 {
1724 //Add it to the hdd's session list.
1725 pHddAdapterNode = vos_mem_malloc( sizeof( hdd_adapter_list_node_t ) );
1726 if( NULL == pHddAdapterNode )
1727 {
1728 status = VOS_STATUS_E_NOMEM;
1729 }
1730 else
1731 {
1732 pHddAdapterNode->pAdapter = pAdapter;
1733 status = hdd_add_adapter_back ( pHddCtx,
1734 pHddAdapterNode );
1735 }
1736 }
1737
1738 if( VOS_STATUS_SUCCESS != status )
1739 {
1740 if( NULL != pAdapter )
1741 {
1742 hdd_cleanup_adapter( pHddCtx, pAdapter, rtnl_held );
1743 pAdapter = NULL;
1744 }
1745 if( NULL != pHddAdapterNode )
1746 {
1747 vos_mem_free( pHddAdapterNode );
1748 }
1749
1750 goto resume_bmps;
1751 }
1752
1753 if(VOS_STATUS_SUCCESS == status)
1754 {
1755 wlan_hdd_set_concurrency_mode(pHddCtx, session_type);
1756
1757#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
1758 /* If there are concurrent session enable SW frame translation
1759 * for all registered STA
1760 * This is not required in case of PRIMA as HW frame translation
1761 * is disabled in PRIMA*/
1762 if (vos_concurrent_sessions_running())
1763 {
1764 WLANTL_ConfigureSwFrameTXXlationForAll(pHddCtx->pvosContext, TRUE);
1765 }
1766#endif
Madan Mohan Koyyalamudi96dd30d2012-10-05 17:24:51 -07001767 //Initialize the WoWL service
1768 if(!hdd_init_wowl(pAdapter))
1769 {
1770 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hdd_init_wowl failed",__func__);
1771 goto err_free_netdev;
1772 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001773 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001774 return pAdapter;
1775
1776err_free_netdev:
1777 free_netdev(pAdapter->dev);
1778 wlan_hdd_release_intf_addr( pHddCtx,
1779 pAdapter->macAddressCurrent.bytes );
1780
1781resume_bmps:
1782 //If bmps disabled enable it
1783 if(VOS_STATUS_SUCCESS == exitbmpsStatus)
1784 {
1785 hdd_enable_bmps_imps(pHddCtx);
1786 }
1787 return NULL;
1788}
1789
1790VOS_STATUS hdd_close_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter,
1791 tANI_U8 rtnl_held )
1792{
1793 hdd_adapter_list_node_t *pAdapterNode, *pCurrent, *pNext;
1794 VOS_STATUS status;
1795
1796 status = hdd_get_front_adapter ( pHddCtx, &pCurrent );
1797 if( VOS_STATUS_SUCCESS != status )
1798 return status;
1799
1800 while ( pCurrent->pAdapter != pAdapter )
1801 {
1802 status = hdd_get_next_adapter ( pHddCtx, pCurrent, &pNext );
1803 if( VOS_STATUS_SUCCESS != status )
1804 break;
1805
1806 pCurrent = pNext;
1807 }
1808 pAdapterNode = pCurrent;
1809 if( VOS_STATUS_SUCCESS == status )
1810 {
1811 wlan_hdd_clear_concurrency_mode(pHddCtx, pAdapter->device_mode);
1812 hdd_cleanup_adapter( pHddCtx, pAdapterNode->pAdapter, rtnl_held );
1813 hdd_remove_adapter( pHddCtx, pAdapterNode );
1814 vos_mem_free( pAdapterNode );
1815
1816#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
1817 /* If there is no concurrent session disable SW frame translation
1818 * for all registered STA */
1819 /* This is not required in case of PRIMA as HW frame translation
1820 * is disabled in PRIMA*/
1821 if (!vos_concurrent_sessions_running())
1822 {
1823 WLANTL_ConfigureSwFrameTXXlationForAll(pHddCtx->pvosContext, FALSE);
1824 }
1825#endif
1826
1827 /* If there is a single session of STA/P2P client, re-enable BMPS */
1828 if ((!vos_concurrent_sessions_running()) &&
1829 ((pHddCtx->no_of_sessions[VOS_STA_MODE] >= 1) ||
1830 (pHddCtx->no_of_sessions[VOS_P2P_CLIENT_MODE] >= 1)))
1831 {
1832 hdd_enable_bmps_imps(pHddCtx);
1833 }
1834
1835 return VOS_STATUS_SUCCESS;
1836 }
1837
1838 return VOS_STATUS_E_FAILURE;
1839}
1840
1841VOS_STATUS hdd_close_all_adapters( hdd_context_t *pHddCtx )
1842{
1843 hdd_adapter_list_node_t *pHddAdapterNode;
1844 VOS_STATUS status;
1845
1846 ENTER();
1847
1848 do
1849 {
1850 status = hdd_remove_front_adapter( pHddCtx, &pHddAdapterNode );
1851 if( pHddAdapterNode && VOS_STATUS_SUCCESS == status )
1852 {
1853 hdd_cleanup_adapter( pHddCtx, pHddAdapterNode->pAdapter, FALSE );
1854 vos_mem_free( pHddAdapterNode );
1855 }
1856 }while( NULL != pHddAdapterNode && VOS_STATUS_E_EMPTY != status );
1857
1858 EXIT();
1859
1860 return VOS_STATUS_SUCCESS;
1861}
1862
1863void wlan_hdd_reset_prob_rspies(hdd_adapter_t* pHostapdAdapter)
1864{
1865 v_U8_t addIE[1] = {0};
1866
1867 if ( eHAL_STATUS_FAILURE == ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal,
1868 WNI_CFG_PROBE_RSP_ADDNIE_DATA1,(tANI_U8*)addIE, 0, NULL,
1869 eANI_BOOLEAN_FALSE) )
1870 {
1871 hddLog(LOGE,
1872 "Could not pass on WNI_CFG_PROBE_RSP_ADDNIE_DATA1 to CCM\n");
1873 }
1874
1875 if ( eHAL_STATUS_FAILURE == ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal,
1876 WNI_CFG_PROBE_RSP_ADDNIE_DATA2, (tANI_U8*)addIE, 0, NULL,
1877 eANI_BOOLEAN_FALSE) )
1878 {
1879 hddLog(LOGE,
1880 "Could not pass on WNI_CFG_PROBE_RSP_ADDNIE_DATA2 to CCM\n");
1881 }
1882
1883 if ( eHAL_STATUS_FAILURE == ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal,
1884 WNI_CFG_PROBE_RSP_ADDNIE_DATA3, (tANI_U8*)addIE, 0, NULL,
1885 eANI_BOOLEAN_FALSE) )
1886 {
1887 hddLog(LOGE,
1888 "Could not pass on WNI_CFG_PROBE_RSP_ADDNIE_DATA3 to CCM\n");
1889 }
1890}
1891
1892VOS_STATUS hdd_stop_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
1893{
1894 eHalStatus halStatus = eHAL_STATUS_SUCCESS;
1895 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
1896 union iwreq_data wrqu;
1897
1898 ENTER();
1899
1900 switch(pAdapter->device_mode)
1901 {
1902 case WLAN_HDD_INFRA_STATION:
1903 case WLAN_HDD_P2P_CLIENT:
Jeff Johnsone7245742012-09-05 17:12:55 -07001904 case WLAN_HDD_P2P_DEVICE:
Jeff Johnson295189b2012-06-20 16:38:30 -07001905 if( hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR( pAdapter )) )
1906 {
1907 if (pWextState->roamProfile.BSSType == eCSR_BSS_TYPE_START_IBSS)
1908 halStatus = sme_RoamDisconnect(pHddCtx->hHal,
1909 pAdapter->sessionId,
1910 eCSR_DISCONNECT_REASON_IBSS_LEAVE);
1911 else
1912 halStatus = sme_RoamDisconnect(pHddCtx->hHal,
1913 pAdapter->sessionId,
1914 eCSR_DISCONNECT_REASON_UNSPECIFIED);
1915 //success implies disconnect command got queued up successfully
1916 if(halStatus == eHAL_STATUS_SUCCESS)
1917 {
1918 wait_for_completion_interruptible_timeout(&pAdapter->disconnect_comp_var,
1919 msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT));
1920 }
1921 memset(&wrqu, '\0', sizeof(wrqu));
1922 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1923 memset(wrqu.ap_addr.sa_data,'\0',ETH_ALEN);
1924 wireless_send_event(pAdapter->dev, SIOCGIWAP, &wrqu, NULL);
1925 }
1926 else
1927 {
1928 hdd_abort_mac_scan(pHddCtx);
1929 }
1930
1931 if (test_bit(SME_SESSION_OPENED, &pAdapter->event_flags))
1932 {
1933 INIT_COMPLETION(pAdapter->session_close_comp_var);
1934 if (eHAL_STATUS_SUCCESS ==
1935 sme_CloseSession(pHddCtx->hHal, pAdapter->sessionId,
1936 hdd_smeCloseSessionCallback, pAdapter))
1937 {
1938 //Block on a completion variable. Can't wait forever though.
1939 wait_for_completion_interruptible_timeout(
1940 &pAdapter->session_close_comp_var,
1941 msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
1942 }
1943 }
1944
1945 break;
1946
1947 case WLAN_HDD_SOFTAP:
1948 case WLAN_HDD_P2P_GO:
1949 //Any softap specific cleanup here...
1950 mutex_lock(&pHddCtx->sap_lock);
1951 if (test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags))
1952 {
1953 VOS_STATUS status;
1954 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1955
1956 //Stop Bss.
1957 status = WLANSAP_StopBss(pHddCtx->pvosContext);
1958 if (VOS_IS_STATUS_SUCCESS(status))
1959 {
1960 hdd_hostapd_state_t *pHostapdState =
1961 WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter);
1962
1963 status = vos_wait_single_event(&pHostapdState->vosEvent, 10000);
1964
1965 if (!VOS_IS_STATUS_SUCCESS(status))
1966 {
1967 hddLog(LOGE, "%s: failure waiting for WLANSAP_StopBss",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001968 __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001969 }
1970 }
1971 else
1972 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001973 hddLog(LOGE, "%s: failure in WLANSAP_StopBss", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001974 }
1975 clear_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags);
1976
1977 if (eHAL_STATUS_FAILURE ==
1978 ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG,
1979 0, NULL, eANI_BOOLEAN_FALSE))
1980 {
1981 hddLog(LOGE,
1982 "%s: Failed to set WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001983 __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001984 }
1985
1986 if ( eHAL_STATUS_FAILURE == ccmCfgSetInt((WLAN_HDD_GET_CTX(pAdapter))->hHal,
1987 WNI_CFG_ASSOC_RSP_ADDNIE_FLAG, 0, NULL,
1988 eANI_BOOLEAN_FALSE) )
1989 {
1990 hddLog(LOGE,
1991 "Could not pass on WNI_CFG_ASSOC_RSP_ADDNIE_FLAG to CCM");
1992 }
1993
1994 // Reset WNI_CFG_PROBE_RSP Flags
1995 wlan_hdd_reset_prob_rspies(pAdapter);
1996 kfree(pAdapter->sessionCtx.ap.beacon);
1997 pAdapter->sessionCtx.ap.beacon = NULL;
1998 }
1999 mutex_unlock(&pHddCtx->sap_lock);
2000 break;
2001 case WLAN_HDD_MONITOR:
2002 break;
2003 default:
2004 break;
2005 }
2006
2007 EXIT();
2008 return VOS_STATUS_SUCCESS;
2009}
2010
2011VOS_STATUS hdd_stop_all_adapters( hdd_context_t *pHddCtx )
2012{
2013 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2014 VOS_STATUS status;
2015 hdd_adapter_t *pAdapter;
2016
2017 ENTER();
2018
2019 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2020
2021 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2022 {
2023 pAdapter = pAdapterNode->pAdapter;
2024 netif_tx_disable(pAdapter->dev);
2025 netif_carrier_off(pAdapter->dev);
2026
2027 hdd_stop_adapter( pHddCtx, pAdapter );
2028
2029 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2030 pAdapterNode = pNext;
2031 }
2032
2033 EXIT();
2034
2035 return VOS_STATUS_SUCCESS;
2036}
2037
2038VOS_STATUS hdd_reset_all_adapters( hdd_context_t *pHddCtx )
2039{
2040 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2041 VOS_STATUS status;
2042 hdd_adapter_t *pAdapter;
2043
2044 ENTER();
2045
2046 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2047
2048 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2049 {
2050 pAdapter = pAdapterNode->pAdapter;
2051 netif_tx_disable(pAdapter->dev);
2052 netif_carrier_off(pAdapter->dev);
2053
2054 //Record whether STA is associated
2055 pAdapter->sessionCtx.station.bSendDisconnect =
2056 hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR( pAdapter )) ?
2057 VOS_TRUE : VOS_FALSE;
2058
2059 hdd_deinit_tx_rx(pAdapter);
2060 hdd_wmm_adapter_close(pAdapter);
2061
2062 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2063 pAdapterNode = pNext;
2064 }
2065
2066 EXIT();
2067
2068 return VOS_STATUS_SUCCESS;
2069}
2070
2071VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx )
2072{
2073 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2074 VOS_STATUS status;
2075 hdd_adapter_t *pAdapter;
2076 v_MACADDR_t bcastMac = VOS_MAC_ADDR_BROADCAST_INITIALIZER;
2077
2078 ENTER();
2079
2080 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2081
2082 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2083 {
2084 pAdapter = pAdapterNode->pAdapter;
2085
2086 switch(pAdapter->device_mode)
2087 {
2088 case WLAN_HDD_INFRA_STATION:
2089 case WLAN_HDD_P2P_CLIENT:
Jeff Johnsone7245742012-09-05 17:12:55 -07002090 case WLAN_HDD_P2P_DEVICE:
Jeff Johnson295189b2012-06-20 16:38:30 -07002091 hdd_init_station_mode(pAdapter);
2092 /* Open the gates for HDD to receive Wext commands */
2093 pAdapter->isLinkUpSvcNeeded = FALSE;
Madan Mohan Koyyalamudi2a1ba772012-10-11 14:59:06 -07002094 pHddCtx->scan_info.mScanPending = FALSE;
2095 pHddCtx->scan_info.waitScanResult = FALSE;
Jeff Johnson295189b2012-06-20 16:38:30 -07002096
2097 //Trigger the initial scan
2098 hdd_wlan_initial_scan(pAdapter);
2099
2100 //Indicate disconnect event to supplicant if associated previously
2101 if(pAdapter->sessionCtx.station.bSendDisconnect)
2102 {
2103 union iwreq_data wrqu;
2104 memset(&wrqu, '\0', sizeof(wrqu));
2105 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
2106 memset(wrqu.ap_addr.sa_data,'\0',ETH_ALEN);
2107 wireless_send_event(pAdapter->dev, SIOCGIWAP, &wrqu, NULL);
2108 pAdapter->sessionCtx.station.bSendDisconnect = VOS_FALSE;
2109
2110#ifdef CONFIG_CFG80211
2111 /* indicate disconnected event to nl80211 */
2112 cfg80211_disconnected(pAdapter->dev, WLAN_REASON_UNSPECIFIED,
2113 NULL, 0, GFP_KERNEL);
2114#endif
2115 }
2116 break;
2117
2118 case WLAN_HDD_SOFTAP:
2119 /* softAP can handle SSR */
2120 break;
2121
2122 case WLAN_HDD_P2P_GO:
2123#ifdef CONFIG_CFG80211
2124 hddLog(VOS_TRACE_LEVEL_ERROR, "%s [SSR] send restart supplicant",
2125 __func__);
2126 /* event supplicant to restart */
2127 cfg80211_del_sta(pAdapter->dev,
2128 (const u8 *)&bcastMac.bytes[0], GFP_KERNEL);
2129#endif
2130 break;
2131
2132 case WLAN_HDD_MONITOR:
2133 /* monitor interface start */
2134 break;
2135 default:
2136 break;
2137 }
2138
2139 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2140 pAdapterNode = pNext;
2141 }
2142
2143 EXIT();
2144
2145 return VOS_STATUS_SUCCESS;
2146}
2147
2148VOS_STATUS hdd_reconnect_all_adapters( hdd_context_t *pHddCtx )
2149{
2150 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2151 hdd_adapter_t *pAdapter;
2152 VOS_STATUS status;
2153 v_U32_t roamId;
2154
2155 ENTER();
2156
2157 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2158
2159 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2160 {
2161 pAdapter = pAdapterNode->pAdapter;
2162
2163 if( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
2164 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) )
2165 {
2166 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
2167 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
2168
2169 pHddStaCtx->conn_info.connState = eConnectionState_NotConnected;
2170 init_completion(&pAdapter->disconnect_comp_var);
2171 sme_RoamDisconnect(pHddCtx->hHal, pAdapter->sessionId,
2172 eCSR_DISCONNECT_REASON_UNSPECIFIED);
2173
2174 wait_for_completion_interruptible_timeout(
2175 &pAdapter->disconnect_comp_var,
2176 msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT));
2177
2178 pWextState->roamProfile.csrPersona = pAdapter->device_mode;
2179 pHddCtx->isAmpAllowed = VOS_FALSE;
2180 sme_RoamConnect(pHddCtx->hHal,
2181 pAdapter->sessionId, &(pWextState->roamProfile),
2182 &roamId);
2183 }
2184
2185 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2186 pAdapterNode = pNext;
2187 }
2188
2189 EXIT();
2190
2191 return VOS_STATUS_SUCCESS;
2192}
2193
Madan Mohan Koyyalamudib5da5332012-10-15 17:23:21 -07002194bool hdd_is_ssr_required( void)
Jeff Johnson295189b2012-06-20 16:38:30 -07002195{
Madan Mohan Koyyalamudib5da5332012-10-15 17:23:21 -07002196 return (isSsrRequired == HDD_SSR_REQUIRED);
Jeff Johnson295189b2012-06-20 16:38:30 -07002197}
2198
Madan Mohan Koyyalamudib5da5332012-10-15 17:23:21 -07002199/* Once SSR is disabled then it cannot be set. */
2200void hdd_set_ssr_required( e_hdd_ssr_required value)
Jeff Johnson295189b2012-06-20 16:38:30 -07002201{
Madan Mohan Koyyalamudib5da5332012-10-15 17:23:21 -07002202 if (HDD_SSR_DISABLED == isSsrRequired)
2203 return;
2204
Jeff Johnson295189b2012-06-20 16:38:30 -07002205 isSsrRequired = value;
2206}
2207
2208VOS_STATUS hdd_get_front_adapter( hdd_context_t *pHddCtx,
2209 hdd_adapter_list_node_t** ppAdapterNode)
2210{
2211 VOS_STATUS status;
2212 spin_lock(&pHddCtx->hddAdapters.lock);
2213 status = hdd_list_peek_front ( &pHddCtx->hddAdapters,
2214 (hdd_list_node_t**) ppAdapterNode );
2215 spin_unlock(&pHddCtx->hddAdapters.lock);
2216 return status;
2217}
2218
2219VOS_STATUS hdd_get_next_adapter( hdd_context_t *pHddCtx,
2220 hdd_adapter_list_node_t* pAdapterNode,
2221 hdd_adapter_list_node_t** pNextAdapterNode)
2222{
2223 VOS_STATUS status;
2224 spin_lock(&pHddCtx->hddAdapters.lock);
2225 status = hdd_list_peek_next ( &pHddCtx->hddAdapters,
2226 (hdd_list_node_t*) pAdapterNode,
2227 (hdd_list_node_t**)pNextAdapterNode );
2228
2229 spin_unlock(&pHddCtx->hddAdapters.lock);
2230 return status;
2231}
2232
2233VOS_STATUS hdd_remove_adapter( hdd_context_t *pHddCtx,
2234 hdd_adapter_list_node_t* pAdapterNode)
2235{
2236 VOS_STATUS status;
2237 spin_lock(&pHddCtx->hddAdapters.lock);
2238 status = hdd_list_remove_node ( &pHddCtx->hddAdapters,
2239 &pAdapterNode->node );
2240 spin_unlock(&pHddCtx->hddAdapters.lock);
2241 return status;
2242}
2243
2244VOS_STATUS hdd_remove_front_adapter( hdd_context_t *pHddCtx,
2245 hdd_adapter_list_node_t** ppAdapterNode)
2246{
2247 VOS_STATUS status;
2248 spin_lock(&pHddCtx->hddAdapters.lock);
2249 status = hdd_list_remove_front( &pHddCtx->hddAdapters,
2250 (hdd_list_node_t**) ppAdapterNode );
2251 spin_unlock(&pHddCtx->hddAdapters.lock);
2252 return status;
2253}
2254
2255VOS_STATUS hdd_add_adapter_back( hdd_context_t *pHddCtx,
2256 hdd_adapter_list_node_t* pAdapterNode)
2257{
2258 VOS_STATUS status;
2259 spin_lock(&pHddCtx->hddAdapters.lock);
2260 status = hdd_list_insert_back ( &pHddCtx->hddAdapters,
2261 (hdd_list_node_t*) pAdapterNode );
2262 spin_unlock(&pHddCtx->hddAdapters.lock);
2263 return status;
2264}
2265
2266VOS_STATUS hdd_add_adapter_front( hdd_context_t *pHddCtx,
2267 hdd_adapter_list_node_t* pAdapterNode)
2268{
2269 VOS_STATUS status;
2270 spin_lock(&pHddCtx->hddAdapters.lock);
2271 status = hdd_list_insert_front ( &pHddCtx->hddAdapters,
2272 (hdd_list_node_t*) pAdapterNode );
2273 spin_unlock(&pHddCtx->hddAdapters.lock);
2274 return status;
2275}
2276
2277hdd_adapter_t * hdd_get_adapter_by_macaddr( hdd_context_t *pHddCtx,
2278 tSirMacAddr macAddr )
2279{
2280 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2281 hdd_adapter_t *pAdapter;
2282 VOS_STATUS status;
2283
2284 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2285
2286 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2287 {
2288 pAdapter = pAdapterNode->pAdapter;
2289
2290 if( pAdapter && vos_mem_compare( pAdapter->macAddressCurrent.bytes,
2291 macAddr, sizeof(tSirMacAddr) ) )
2292 {
2293 return pAdapter;
2294 }
2295 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2296 pAdapterNode = pNext;
2297 }
2298
2299 return NULL;
2300
2301}
2302
2303hdd_adapter_t * hdd_get_adapter_by_name( hdd_context_t *pHddCtx, tANI_U8 *name )
2304{
2305 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2306 hdd_adapter_t *pAdapter;
2307 VOS_STATUS status;
2308
2309 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2310
2311 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2312 {
2313 pAdapter = pAdapterNode->pAdapter;
2314
2315 if( pAdapter && !strncmp( pAdapter->dev->name, (const char *)name,
2316 IFNAMSIZ ) )
2317 {
2318 return pAdapter;
2319 }
2320 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2321 pAdapterNode = pNext;
2322 }
2323
2324 return NULL;
2325
2326}
2327
2328hdd_adapter_t * hdd_get_adapter( hdd_context_t *pHddCtx, device_mode_t mode )
2329{
2330 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2331 hdd_adapter_t *pAdapter;
2332 VOS_STATUS status;
2333
2334 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2335
2336 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2337 {
2338 pAdapter = pAdapterNode->pAdapter;
2339
2340 if( pAdapter && (mode == pAdapter->device_mode) )
2341 {
2342 return pAdapter;
2343 }
2344 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2345 pAdapterNode = pNext;
2346 }
2347
2348 return NULL;
2349
2350}
2351
2352//Remove this function later
2353hdd_adapter_t * hdd_get_mon_adapter( hdd_context_t *pHddCtx )
2354{
2355 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2356 hdd_adapter_t *pAdapter;
2357 VOS_STATUS status;
2358
2359 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2360
2361 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2362 {
2363 pAdapter = pAdapterNode->pAdapter;
2364
2365 if( pAdapter && WLAN_HDD_MONITOR == pAdapter->device_mode )
2366 {
2367 return pAdapter;
2368 }
2369
2370 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2371 pAdapterNode = pNext;
2372 }
2373
2374 return NULL;
2375
2376}
2377
2378#ifdef CONFIG_CFG80211
2379/**---------------------------------------------------------------------------
2380
2381 \brief hdd_set_monitor_tx_adapter() -
2382
2383 This API initializes the adapter to be used while transmitting on monitor
2384 adapter.
2385
2386 \param - pHddCtx - Pointer to the HDD context.
2387 pAdapter - Adapter that will used for TX. This can be NULL.
2388 \return - None.
2389 --------------------------------------------------------------------------*/
2390void wlan_hdd_set_monitor_tx_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
2391{
2392 hdd_adapter_t *pMonAdapter;
2393
2394 pMonAdapter = hdd_get_adapter( pHddCtx, WLAN_HDD_MONITOR );
2395
2396 if( NULL != pMonAdapter )
2397 {
2398 pMonAdapter->sessionCtx.monitor.pAdapterForTx = pAdapter;
2399 }
2400}
2401#endif
2402/**---------------------------------------------------------------------------
2403
2404 \brief hdd_select_queue() -
2405
2406 This API returns the operating channel of the requested device mode
2407
2408 \param - pHddCtx - Pointer to the HDD context.
2409 - mode - Device mode for which operating channel is required
2410 suported modes - WLAN_HDD_INFRA_STATION, WLAN_HDD_P2P_CLIENT
2411 WLAN_HDD_SOFTAP, WLAN_HDD_P2P_GO.
2412 \return - channel number. "0" id the requested device is not found OR it is not connected.
2413 --------------------------------------------------------------------------*/
2414v_U8_t hdd_get_operating_channel( hdd_context_t *pHddCtx, device_mode_t mode )
2415{
2416 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2417 VOS_STATUS status;
2418 hdd_adapter_t *pAdapter;
2419 v_U8_t operatingChannel = 0;
2420
2421 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2422
2423 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2424 {
2425 pAdapter = pAdapterNode->pAdapter;
2426
2427 if( mode == pAdapter->device_mode )
2428 {
2429 switch(pAdapter->device_mode)
2430 {
2431 case WLAN_HDD_INFRA_STATION:
2432 case WLAN_HDD_P2P_CLIENT:
2433 if( hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR( pAdapter )) )
2434 operatingChannel = (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.operationChannel;
2435 break;
2436 case WLAN_HDD_SOFTAP:
2437 case WLAN_HDD_P2P_GO:
2438 /*softap connection info */
2439 if(test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags))
2440 operatingChannel = (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->operatingChannel;
2441 break;
2442 default:
2443 break;
2444 }
2445
2446 break; //Found the device of interest. break the loop
2447 }
2448
2449 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2450 pAdapterNode = pNext;
2451 }
2452 return operatingChannel;
2453}
2454
2455#ifdef WLAN_FEATURE_PACKET_FILTERING
2456/**---------------------------------------------------------------------------
2457
2458 \brief hdd_set_multicast_list() -
2459
2460 This used to set the multicast address list.
2461
2462 \param - dev - Pointer to the WLAN device.
2463 - skb - Pointer to OS packet (sk_buff).
2464 \return - success/fail
2465
2466 --------------------------------------------------------------------------*/
2467static void hdd_set_multicast_list(struct net_device *dev)
2468{
2469 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2470 hdd_context_t *pHddCtx;
2471 int mc_count;
2472 int i = 0;
2473 struct netdev_hw_addr *ha;
2474 pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
2475 if (NULL == pHddCtx)
2476 {
2477 hddLog(VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002478 "%s: HDD context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07002479 return;
2480 }
2481
2482 if (dev->flags & IFF_ALLMULTI)
2483 {
2484 hddLog(VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002485 "%s: allow all multicast frames", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07002486 pHddCtx->mc_addr_list.mc_cnt = 0;
2487 }
2488 else
2489 {
2490 mc_count = netdev_mc_count(dev);
2491 hddLog(VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002492 "%s: mc_count = %u", __func__, mc_count);
Jeff Johnson295189b2012-06-20 16:38:30 -07002493 if (mc_count > WLAN_HDD_MAX_MC_ADDR_LIST)
2494 {
2495 hddLog(VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002496 "%s: No free filter available; allow all multicast frames", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07002497 pHddCtx->mc_addr_list.mc_cnt = 0;
2498 return;
2499 }
2500
2501 pHddCtx->mc_addr_list.mc_cnt = mc_count;
2502
2503 netdev_for_each_mc_addr(ha, dev) {
2504 if (i == mc_count)
2505 break;
2506 memset(&(pHddCtx->mc_addr_list.addr[i][0]), 0, ETH_ALEN);
2507 memcpy(&(pHddCtx->mc_addr_list.addr[i][0]), ha->addr, ETH_ALEN);
2508 hddLog(VOS_TRACE_LEVEL_INFO, "\n%s: mlist[%d] = %02x:%02x:%02x:%02x:%02x:%02x",
2509 __func__, i,
2510 pHddCtx->mc_addr_list.addr[i][0], pHddCtx->mc_addr_list.addr[i][1],
2511 pHddCtx->mc_addr_list.addr[i][2], pHddCtx->mc_addr_list.addr[i][3],
2512 pHddCtx->mc_addr_list.addr[i][4], pHddCtx->mc_addr_list.addr[i][5]);
2513 i++;
2514 }
2515 }
2516 return;
2517}
2518#endif
2519
2520/**---------------------------------------------------------------------------
2521
2522 \brief hdd_select_queue() -
2523
2524 This function is registered with the Linux OS for network
2525 core to decide which queue to use first.
2526
2527 \param - dev - Pointer to the WLAN device.
2528 - skb - Pointer to OS packet (sk_buff).
2529 \return - ac, Queue Index/access category corresponding to UP in IP header
2530
2531 --------------------------------------------------------------------------*/
2532v_U16_t hdd_select_queue(struct net_device *dev,
2533 struct sk_buff *skb)
2534{
2535 return hdd_wmm_select_queue(dev, skb);
2536}
2537
2538
2539/**---------------------------------------------------------------------------
2540
2541 \brief hdd_wlan_initial_scan() -
2542
2543 This function triggers the initial scan
2544
2545 \param - pAdapter - Pointer to the HDD adapter.
2546
2547 --------------------------------------------------------------------------*/
2548void hdd_wlan_initial_scan(hdd_adapter_t *pAdapter)
2549{
2550 tCsrScanRequest scanReq;
2551 tCsrChannelInfo channelInfo;
2552 eHalStatus halStatus;
2553 unsigned long scanId;
2554 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2555
2556 vos_mem_zero(&scanReq, sizeof(tCsrScanRequest));
2557 vos_mem_set(&scanReq.bssid, sizeof(tCsrBssid), 0xff);
2558 scanReq.BSSType = eCSR_BSS_TYPE_ANY;
2559
2560 if(sme_Is11dSupported(pHddCtx->hHal))
2561 {
2562 halStatus = sme_ScanGetBaseChannels( pHddCtx->hHal, &channelInfo );
2563 if ( HAL_STATUS_SUCCESS( halStatus ) )
2564 {
2565 scanReq.ChannelInfo.ChannelList = vos_mem_malloc(channelInfo.numOfChannels);
2566 if( !scanReq.ChannelInfo.ChannelList )
2567 {
2568 hddLog(VOS_TRACE_LEVEL_ERROR, "%s kmalloc failed", __func__);
2569 vos_mem_free(channelInfo.ChannelList);
2570 return;
2571 }
2572 vos_mem_copy(scanReq.ChannelInfo.ChannelList, channelInfo.ChannelList,
2573 channelInfo.numOfChannels);
2574 scanReq.ChannelInfo.numOfChannels = channelInfo.numOfChannels;
2575 vos_mem_free(channelInfo.ChannelList);
2576 }
2577
2578 scanReq.scanType = eSIR_PASSIVE_SCAN;
2579 scanReq.requestType = eCSR_SCAN_REQUEST_11D_SCAN;
2580 scanReq.maxChnTime = pHddCtx->cfg_ini->nPassiveMaxChnTime;
2581 scanReq.minChnTime = pHddCtx->cfg_ini->nPassiveMinChnTime;
2582 }
2583 else
2584 {
2585 scanReq.scanType = eSIR_ACTIVE_SCAN;
2586 scanReq.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
2587 scanReq.maxChnTime = pHddCtx->cfg_ini->nActiveMaxChnTime;
2588 scanReq.minChnTime = pHddCtx->cfg_ini->nActiveMinChnTime;
2589 }
2590
2591 halStatus = sme_ScanRequest(pHddCtx->hHal, pAdapter->sessionId, &scanReq, &scanId, NULL, NULL);
2592 if ( !HAL_STATUS_SUCCESS( halStatus ) )
2593 {
2594 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: sme_ScanRequest failed status code %d",
2595 __func__, halStatus );
2596 }
2597
2598 if(sme_Is11dSupported(pHddCtx->hHal))
2599 vos_mem_free(scanReq.ChannelInfo.ChannelList);
2600}
2601
2602struct fullPowerContext
2603{
2604 struct completion completion;
2605 unsigned int magic;
2606};
2607#define POWER_CONTEXT_MAGIC 0x504F5752 //POWR
2608
2609/**---------------------------------------------------------------------------
2610
2611 \brief hdd_full_power_callback() - HDD full power callback function
2612
2613 This is the function invoked by SME to inform the result of a full power
2614 request issued by HDD
2615
2616 \param - callbackcontext - Pointer to cookie
2617 \param - status - result of request
2618
2619 \return - None
2620
2621 --------------------------------------------------------------------------*/
2622static void hdd_full_power_callback(void *callbackContext, eHalStatus status)
2623{
2624 struct fullPowerContext *pContext = callbackContext;
2625
2626 hddLog(VOS_TRACE_LEVEL_INFO,
2627 "%s: context = %p, status = %d", pContext, status);
2628
2629 if (NULL == callbackContext)
2630 {
2631 hddLog(VOS_TRACE_LEVEL_ERROR,
2632 "%s: Bad param, context [%p]",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002633 __func__, callbackContext);
Jeff Johnson295189b2012-06-20 16:38:30 -07002634 return;
2635 }
2636
2637 /* there is a race condition that exists between this callback function
2638 and the caller since the caller could time out either before or
2639 while this code is executing. we'll assume the timeout hasn't
2640 occurred, but we'll verify that right before we save our work */
2641
2642 if (POWER_CONTEXT_MAGIC != pContext->magic)
2643 {
2644 /* the caller presumably timed out so there is nothing we can do */
2645 hddLog(VOS_TRACE_LEVEL_WARN,
2646 "%s: Invalid context, magic [%08x]",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002647 __func__, pContext->magic);
Jeff Johnson295189b2012-06-20 16:38:30 -07002648 return;
2649 }
2650
2651 /* the race is on. caller could have timed out immediately after
2652 we verified the magic, but if so, caller will wait a short time
2653 for us to notify the caller, so the context will stay valid */
2654 complete(&pContext->completion);
2655}
2656
2657/**---------------------------------------------------------------------------
2658
2659 \brief hdd_wlan_exit() - HDD WLAN exit function
2660
2661 This is the driver exit point (invoked during rmmod)
2662
2663 \param - pHddCtx - Pointer to the HDD Context
2664
2665 \return - None
2666
2667 --------------------------------------------------------------------------*/
2668void hdd_wlan_exit(hdd_context_t *pHddCtx)
2669{
2670 eHalStatus halStatus;
2671 v_CONTEXT_t pVosContext = pHddCtx->pvosContext;
2672 VOS_STATUS vosStatus;
2673#ifdef ANI_BUS_TYPE_SDIO
2674 struct sdio_func *sdio_func_dev = NULL;
2675#endif // ANI_BUS_TYPE_SDIO
2676#ifdef CONFIG_CFG80211
2677 struct wiphy *wiphy = pHddCtx->wiphy;
2678#endif
2679#ifdef FEATURE_WLAN_INTEGRATED_SOC
2680 hdd_adapter_t* pAdapter;
2681#endif
2682 struct fullPowerContext powerContext;
2683 long lrc;
2684
2685 ENTER();
2686
Jeff Johnsone7245742012-09-05 17:12:55 -07002687 // Unloading, restart logic is no more required.
2688 wlan_hdd_restart_deinit(pHddCtx);
2689
Jeff Johnson295189b2012-06-20 16:38:30 -07002690#ifdef CONFIG_CFG80211
2691#ifdef WLAN_SOFTAP_FEATURE
2692 if (VOS_STA_SAP_MODE != hdd_get_conparam())
2693#endif
2694 {
2695#ifdef ANI_MANF_DIAG
2696 if (VOS_FTM_MODE != hdd_get_conparam())
2697#endif /* ANI_MANF_DIAG */
2698 {
2699 hdd_adapter_t* pAdapter = hdd_get_adapter(pHddCtx,
2700 WLAN_HDD_INFRA_STATION);
2701 if (pAdapter == NULL)
2702 pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_P2P_CLIENT);
2703
2704 if (pAdapter != NULL)
2705 {
2706 wlan_hdd_cfg80211_pre_voss_stop(pAdapter);
2707 hdd_UnregisterWext(pAdapter->dev);
2708 }
2709 }
2710 }
2711#endif
2712
2713#ifdef ANI_MANF_DIAG
2714 if (VOS_FTM_MODE == hdd_get_conparam())
2715 {
2716 wlan_hdd_ftm_close(pHddCtx);
2717 goto free_hdd_ctx;
2718 }
2719#endif
2720 //Stop the Interface TX queue.
2721 //netif_tx_disable(pWlanDev);
2722 //netif_carrier_off(pWlanDev);
2723
2724#ifdef CONFIG_HAS_EARLYSUSPEND
2725 // unregister suspend/resume callbacks
2726 if(pHddCtx->cfg_ini->nEnableSuspend)
2727 {
2728 unregister_wlan_suspend();
2729 }
2730#endif
2731
2732#ifdef FEATURE_WLAN_INTEGRATED_SOC
2733#ifdef WLAN_SOFTAP_FEATURE
2734 if (VOS_STA_SAP_MODE == hdd_get_conparam())
2735 {
2736 pAdapter = hdd_get_adapter(pHddCtx,
2737 WLAN_HDD_SOFTAP);
2738 }
2739 else
2740 {
2741#endif
2742#ifdef ANI_MANF_DIAG
2743 if (VOS_FTM_MODE != hdd_get_conparam())
2744#endif /* ANI_MANF_DIAG */
2745 {
2746 pAdapter = hdd_get_adapter(pHddCtx,
2747 WLAN_HDD_INFRA_STATION);
2748 }
2749#ifdef WLAN_SOFTAP_FEATURE
2750 }
2751#endif
2752 /* DeRegister with platform driver as client for Suspend/Resume */
2753 vosStatus = hddDeregisterPmOps(pHddCtx);
2754 if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) )
2755 {
2756 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDeregisterPmOps failed",__func__);
2757 VOS_ASSERT(0);
2758 }
2759
2760 vosStatus = hddDevTmUnregisterNotifyCallback(pHddCtx);
2761 if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) )
2762 {
2763 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDevTmUnregisterNotifyCallback failed",__func__);
2764 }
2765#endif //FEATURE_WLAN_INTEGRATED_SOC
2766
2767 // Cancel any outstanding scan requests. We are about to close all
2768 // of our adapters, but an adapter structure is what SME passes back
2769 // to our callback function. Hence if there are any outstanding scan
2770 // requests then there is a race condition between when the adapter
2771 // is closed and when the callback is invoked. We try to resolve that
2772 // race condition here by canceling any outstanding scans before we
2773 // close the adapters.
2774 // Note that the scans may be cancelled in an asynchronous manner, so
2775 // ideally there needs to be some kind of synchronization. Rather than
2776 // introduce a new synchronization here, we will utilize the fact that
2777 // we are about to Request Full Power, and since that is synchronized,
2778 // the expectation is that by the time Request Full Power has completed,
2779 // all scans will be cancelled.
2780 hdd_abort_mac_scan( pHddCtx );
2781
2782 //Disable IMPS/BMPS as we do not want the device to enter any power
2783 //save mode during shutdown
2784 sme_DisablePowerSave(pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE);
2785 sme_DisablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE);
2786 sme_DisablePowerSave(pHddCtx->hHal, ePMC_UAPSD_MODE_POWER_SAVE);
2787
2788 //Ensure that device is in full power as we will touch H/W during vos_Stop
2789 init_completion(&powerContext.completion);
2790 powerContext.magic = POWER_CONTEXT_MAGIC;
2791
2792 halStatus = sme_RequestFullPower(pHddCtx->hHal, hdd_full_power_callback,
2793 &powerContext, eSME_FULL_PWR_NEEDED_BY_HDD);
2794
2795 if (eHAL_STATUS_SUCCESS != halStatus)
2796 {
2797 if (eHAL_STATUS_PMC_PENDING == halStatus)
2798 {
2799 /* request was sent -- wait for the response */
2800 lrc = wait_for_completion_interruptible_timeout(
2801 &powerContext.completion,
2802 msecs_to_jiffies(WLAN_WAIT_TIME_POWER));
2803 /* either we have a response or we timed out
2804 either way, first invalidate our magic */
2805 powerContext.magic = 0;
2806 if (lrc <= 0)
2807 {
2808 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: %s while requesting full power",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002809 __func__, (0 == lrc) ? "timeout" : "interrupt");
Jeff Johnson295189b2012-06-20 16:38:30 -07002810 /* there is a race condition such that the callback
2811 function could be executing at the same time we are. of
2812 primary concern is if the callback function had already
2813 verified the "magic" but hasn't yet set the completion
2814 variable. Since the completion variable is on our
2815 stack, we'll delay just a bit to make sure the data is
2816 still valid if that is the case */
2817 msleep(50);
2818 }
2819 }
2820 else
2821 {
2822 hddLog(VOS_TRACE_LEVEL_ERROR,
2823 "%s: Request for Full Power failed, status %d",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002824 __func__, halStatus);
Jeff Johnson295189b2012-06-20 16:38:30 -07002825 VOS_ASSERT(0);
2826 /* continue -- need to clean up as much as possible */
2827 }
2828 }
2829
2830 // Unregister the Net Device Notifier
2831 unregister_netdevice_notifier(&hdd_netdev_notifier);
2832
Jeff Johnson295189b2012-06-20 16:38:30 -07002833 hdd_stop_all_adapters( pHddCtx );
2834
2835#ifdef ANI_BUS_TYPE_SDIO
2836 sdio_func_dev = libra_getsdio_funcdev();
2837
2838 if(sdio_func_dev == NULL)
2839 {
2840 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: sdio_func_dev is NULL!",__func__);
2841 VOS_ASSERT(0);
2842 return;
2843 }
2844
2845 sd_claim_host(sdio_func_dev);
2846
2847 /* Disable SDIO IRQ since we are exiting */
2848 libra_enable_sdio_irq(sdio_func_dev, 0);
2849
2850 sd_release_host(sdio_func_dev);
2851#endif // ANI_BUS_TYPE_SDIO
2852
2853#ifdef WLAN_BTAMP_FEATURE
2854 vosStatus = WLANBAP_Stop(pVosContext);
2855 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2856 {
2857 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
2858 "%s: Failed to stop BAP",__func__);
2859 }
2860#endif //WLAN_BTAMP_FEATURE
2861
2862 //Stop all the modules
2863 vosStatus = vos_stop( pVosContext );
2864 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2865 {
2866 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2867 "%s: Failed to stop VOSS",__func__);
2868 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2869 }
2870
2871#ifdef ANI_BUS_TYPE_SDIO
2872 vosStatus = WLANBAL_Stop( pVosContext );
2873
2874 hddLog(VOS_TRACE_LEVEL_ERROR,"WLAN BAL STOP\n");
2875 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2876 {
2877 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2878 "%s: Failed to stop BAL",__func__);
2879 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2880 }
2881
2882 msleep(50);
2883 //Put the chip is standby before asserting deep sleep
2884 vosStatus = WLANBAL_SuspendChip( pVosContext );
2885
2886 hddLog(VOS_TRACE_LEVEL_ERROR,"WLAN Suspend Chip\n");
2887
2888 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2889 {
2890 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2891 "%s: Failed to suspend chip ",__func__);
2892 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2893 }
2894 //Invoke SAL stop
2895 vosStatus = WLANSAL_Stop( pVosContext );
2896 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2897 {
2898 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2899 "%s: Failed to stop SAL",__func__);
2900 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2901 }
2902
2903#endif // ANI_BUS_TYPE_SDIO
2904
2905 //Assert Deep sleep signal now to put Libra HW in lowest power state
2906 vosStatus = vos_chipAssertDeepSleep( NULL, NULL, NULL );
2907 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2908
2909 //Vote off any PMIC voltage supplies
2910 vos_chipPowerDown(NULL, NULL, NULL);
2911
2912 vos_chipVoteOffXOBuffer(NULL, NULL, NULL);
2913
2914 //Clean up HDD Nlink Service
2915 send_btc_nlink_msg(WLAN_MODULE_DOWN_IND, 0);
2916 nl_srv_exit();
2917
2918 //This requires pMac access, Call this before vos_close().
2919#ifdef CONFIG_HAS_EARLYSUSPEND
2920 hdd_unregister_mcast_bcast_filter(pHddCtx);
2921#endif
2922
2923 //Close the scheduler before calling vos_close to make sure no thread is
2924 // scheduled after the each module close is called i.e after all the data
2925 // structures are freed.
2926 vosStatus = vos_sched_close( pVosContext );
2927 if (!VOS_IS_STATUS_SUCCESS(vosStatus)) {
2928 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
2929 "%s: Failed to close VOSS Scheduler",__func__);
2930 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2931 }
Jeff Johnsone7245742012-09-05 17:12:55 -07002932
2933#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
2934 /* Destroy the wake lock */
2935 wake_lock_destroy(&pHddCtx->rx_wake_lock);
2936#endif
Madan Mohan Koyyalamudi69fc3ad2012-11-28 16:04:56 -08002937 /* Destroy the wake lock */
2938 wake_lock_destroy(&pHddCtx->sap_wake_lock);
Jeff Johnson295189b2012-06-20 16:38:30 -07002939
2940 //Close VOSS
2941 //This frees pMac(HAL) context. There should not be any call that requires pMac access after this.
2942 vos_close(pVosContext);
2943
2944#ifdef ANI_BUS_TYPE_SDIO
2945 vosStatus = WLANBAL_Close(pVosContext);
2946 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2947 {
2948 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2949 "%s: Failed to close BAL",__func__);
2950 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2951 }
2952 hddLog(VOS_TRACE_LEVEL_ERROR,"Returned WLAN BAL CLOSE\n\n\n\n");
2953#endif // ANI_BUS_TYPE_SDIO
2954
2955 //Close Watchdog
2956 if(pHddCtx->cfg_ini->fIsLogpEnabled)
2957 vos_watchdog_close(pVosContext);
2958
2959 /* Cancel the vote for XO Core ON.
2960 * This is done here to ensure there is no race condition since MC, TX and WD threads have
2961 * exited at this point
2962 */
2963 hddLog(VOS_TRACE_LEVEL_WARN, "In module exit: Cancel the vote for XO Core ON"
2964 " when WLAN is turned OFF\n");
2965 if (vos_chipVoteXOCore(NULL, NULL, NULL, VOS_FALSE) != VOS_STATUS_SUCCESS)
2966 {
2967 hddLog(VOS_TRACE_LEVEL_ERROR, "Could not cancel the vote for XO Core ON."
2968 " Not returning failure."
2969 " Power consumed will be high\n");
2970 }
2971
2972 hdd_close_all_adapters( pHddCtx );
2973
2974
2975 //Free up dynamically allocated members inside HDD Adapter
2976 kfree(pHddCtx->cfg_ini);
2977 pHddCtx->cfg_ini= NULL;
2978
2979 /* free the power on lock from platform driver */
2980 if (free_riva_power_on_lock("wlan"))
2981 {
2982 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: failed to free power on lock",
2983 __func__);
2984 }
2985
2986#ifdef ANI_MANF_DIAG
2987free_hdd_ctx:
2988#endif
2989#ifdef CONFIG_CFG80211
2990 wiphy_unregister(wiphy) ;
2991 wiphy_free(wiphy) ;
2992#else
2993 vos_mem_free( pHddCtx );
2994#endif
2995 if (hdd_is_ssr_required())
2996 {
2997 /* WDI timeout had happened during unload, so SSR is needed here */
Madan Mohan Koyyalamudi3246f5b2012-10-15 15:40:02 -07002998 subsystem_restart("wcnss");
Jeff Johnson295189b2012-06-20 16:38:30 -07002999 msleep(5000);
3000 }
3001 hdd_set_ssr_required (VOS_FALSE);
3002}
3003
3004
3005/**---------------------------------------------------------------------------
3006
3007 \brief hdd_update_config_from_nv() - Function to update the contents of
3008 the running configuration with parameters taken from NV storage
3009
3010 \param - pHddCtx - Pointer to the HDD global context
3011
3012 \return - VOS_STATUS_SUCCESS if successful
3013
3014 --------------------------------------------------------------------------*/
3015static VOS_STATUS hdd_update_config_from_nv(hdd_context_t* pHddCtx)
3016{
3017#ifndef FEATURE_WLAN_INTEGRATED_SOC
3018 eHalStatus halStatus;
3019#endif
3020
3021#ifdef FEATURE_WLAN_INTEGRATED_SOC
3022 v_BOOL_t itemIsValid = VOS_FALSE;
3023 VOS_STATUS status;
3024 v_MACADDR_t macFromNV[VOS_MAX_CONCURRENCY_PERSONA];
3025 v_U8_t macLoop;
3026
3027 /*If the NV is valid then get the macaddress from nv else get it from qcom_cfg.ini*/
3028 status = vos_nv_getValidity(VNV_FIELD_IMAGE, &itemIsValid);
3029 if(status != VOS_STATUS_SUCCESS)
3030 {
3031 hddLog(VOS_TRACE_LEVEL_ERROR," vos_nv_getValidity() failed\n ");
3032 return VOS_STATUS_E_FAILURE;
3033 }
3034
3035 if (itemIsValid == VOS_TRUE)
3036 {
3037 hddLog(VOS_TRACE_LEVEL_INFO_HIGH," Reading the Macaddress from NV\n ");
3038 status = vos_nv_readMultiMacAddress((v_U8_t *)&macFromNV[0].bytes[0],
3039 VOS_MAX_CONCURRENCY_PERSONA);
3040 if(status != VOS_STATUS_SUCCESS)
3041 {
3042 /* Get MAC from NV fail, not update CFG info
3043 * INI MAC value will be used for MAC setting */
3044 hddLog(VOS_TRACE_LEVEL_ERROR," vos_nv_readMacAddress() failed\n ");
3045 return VOS_STATUS_E_FAILURE;
3046 }
3047
3048 /* If first MAC is not valid, treat all others are not valid
3049 * Then all MACs will be got from ini file */
3050 if(vos_is_macaddr_zero(&macFromNV[0]))
3051 {
3052 /* MAC address in NV file is not configured yet */
3053 hddLog(VOS_TRACE_LEVEL_WARN, "Invalid MAC in NV file");
3054 return VOS_STATUS_E_INVAL;
3055 }
3056
3057 /* Get MAC address from NV, update CFG info */
3058 for(macLoop = 0; macLoop < VOS_MAX_CONCURRENCY_PERSONA; macLoop++)
3059 {
3060 if(vos_is_macaddr_zero(&macFromNV[macLoop]))
3061 {
3062 printk(KERN_ERR "not valid MAC from NV for %d", macLoop);
3063 /* This MAC is not valid, skip it
3064 * This MAC will be got from ini file */
3065 }
3066 else
3067 {
3068 vos_mem_copy((v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[macLoop].bytes[0],
3069 (v_U8_t *)&macFromNV[macLoop].bytes[0],
3070 VOS_MAC_ADDR_SIZE);
3071 }
3072 }
3073 }
3074 else
3075 {
3076 hddLog(VOS_TRACE_LEVEL_ERROR, "NV ITEM, MAC Not valid");
3077 return VOS_STATUS_E_FAILURE;
3078 }
3079#endif /* FEATURE_WLAN_INTEGRATED_SOC */
3080
3081#ifndef FEATURE_WLAN_INTEGRATED_SOC
3082#if 1 /* need to fix for concurrency */
3083 // Set the MAC Address
3084 // Currently this is used by HAL to add self sta. Remove this once self sta is added as part of session open.
3085 halStatus = ccmCfgSetStr( pHddCtx->hHal, WNI_CFG_STA_ID,
3086 (v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[0],
3087 sizeof( pHddCtx->cfg_ini->intfMacAddr[0]),
3088 hdd_set_mac_addr_cb, VOS_FALSE );
3089
3090 if (!HAL_STATUS_SUCCESS( halStatus ))
3091 {
3092 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed to set MAC Address. "
3093 "HALStatus is %08d [x%08x]",__func__, halStatus, halStatus );
3094 return VOS_STATUS_E_FAILURE;
3095 }
3096#endif
3097#endif
3098
3099 return VOS_STATUS_SUCCESS;
3100}
3101
3102/**---------------------------------------------------------------------------
3103
3104 \brief hdd_post_voss_start_config() - HDD post voss start config helper
3105
3106 \param - pAdapter - Pointer to the HDD
3107
3108 \return - None
3109
3110 --------------------------------------------------------------------------*/
3111VOS_STATUS hdd_post_voss_start_config(hdd_context_t* pHddCtx)
3112{
3113 eHalStatus halStatus;
3114 v_U32_t listenInterval;
3115
3116#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
3117 /* In the non-integrated architecture we update the configuration from
3118 the INI file and from NV after vOSS has been started
3119 */
3120
3121 // Apply the cfg.ini to cfg.dat
3122 if (FALSE == hdd_update_config_dat(pHddCtx))
3123 {
3124 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: config update failed",__func__ );
3125 return VOS_STATUS_E_FAILURE;
3126 }
3127
3128 // Apply the NV to cfg.dat
3129 if (VOS_STATUS_SUCCESS != hdd_update_config_from_nv(pHddCtx))
3130 {
3131 hddLog(VOS_TRACE_LEVEL_FATAL,
3132 "%s: config update from NV failed", __func__ );
3133 return VOS_STATUS_E_FAILURE;
3134 }
3135#endif // FEATURE_WLAN_NON_INTEGRATED_SOC
3136
3137 // Send ready indication to the HDD. This will kick off the MAC
3138 // into a 'running' state and should kick off an initial scan.
3139 halStatus = sme_HDDReadyInd( pHddCtx->hHal );
3140 if ( !HAL_STATUS_SUCCESS( halStatus ) )
3141 {
3142 hddLog(VOS_TRACE_LEVEL_ERROR,"%S: sme_HDDReadyInd() failed with status "
3143 "code %08d [x%08x]",__func__, halStatus, halStatus );
3144 return VOS_STATUS_E_FAILURE;
3145 }
3146
3147 // Set default LI into HDD context,
3148 // otherwise under some race condition, HDD will set 0 LI value into RIVA,
3149 // And RIVA will crash
3150 wlan_cfgGetInt(pHddCtx->hHal, WNI_CFG_LISTEN_INTERVAL, &listenInterval);
3151 pHddCtx->hdd_actual_LI_value = listenInterval;
3152
3153 return VOS_STATUS_SUCCESS;
3154}
3155
3156#ifdef ANI_BUS_TYPE_SDIO
3157
3158#ifndef ANI_MANF_DIAG
3159// Routine to initialize the PMU
3160void wlan_hdd_enable_deepsleep(v_VOID_t * pVosContext)
3161{
3162/*-------------- Need to fix this correctly while doing Deepsleep testing
3163 tANI_U32 regValue = 0;
3164
3165 regValue = QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_DEEP_SLEEP_EN_MASK |
3166 QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_1P23_LPM_AON_MASK_MASK |
3167 QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_1P23_LPM_SW_MASK_MASK |
3168 QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_2P3_LPM_MASK_MASK;
3169
3170 WLANBAL_WriteRegister(pVosContext, QWLAN_PMU_LDO_CTRL_REG_REG, regValue);
3171---------------------*/
3172
3173 return;
3174}
3175#endif
3176#endif
3177
3178/* wake lock APIs for HDD */
3179void hdd_prevent_suspend(void)
3180{
Jeff Johnsone7245742012-09-05 17:12:55 -07003181#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07003182 wake_lock(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07003183#else
3184 wcnss_prevent_suspend();
3185#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07003186}
3187
3188void hdd_allow_suspend(void)
3189{
Jeff Johnsone7245742012-09-05 17:12:55 -07003190#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07003191 wake_unlock(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07003192#else
3193 wcnss_allow_suspend();
3194#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07003195}
3196
Madan Mohan Koyyalamudi10d83a92012-09-28 15:47:05 -07003197void hdd_allow_suspend_timeout(v_U32_t timeout)
3198{
3199#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
3200 wake_lock_timeout(&wlan_wake_lock, timeout);
3201#else
3202 /* Do nothing as there is no API in wcnss for timeout*/
3203#endif
3204}
3205
Jeff Johnson295189b2012-06-20 16:38:30 -07003206/**---------------------------------------------------------------------------
3207
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003208 \brief hdd_exchange_version_and_caps() - HDD function to exchange version and capability
3209 information between Host and Riva
3210
3211 This function gets reported version of FW
3212 It also finds the version of Riva headers used to compile the host
3213 It compares the above two and prints a warning if they are different
3214 It gets the SW and HW version string
3215 Finally, it exchanges capabilities between host and Riva i.e. host and riva exchange a msg
3216 indicating the features they support through a bitmap
3217
3218 \param - pHddCtx - Pointer to HDD context
3219
3220 \return - void
3221
3222 --------------------------------------------------------------------------*/
3223
3224void hdd_exchange_version_and_caps(hdd_context_t *pHddCtx)
3225{
3226
3227 tSirVersionType versionCompiled;
3228 tSirVersionType versionReported;
3229 tSirVersionString versionString;
3230 tANI_U8 fwFeatCapsMsgSupported = 0;
3231 VOS_STATUS vstatus;
3232
3233 /* retrieve and display WCNSS version information */
3234 do {
3235
3236 vstatus = sme_GetWcnssWlanCompiledVersion(pHddCtx->hHal,
3237 &versionCompiled);
3238 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3239 {
3240 hddLog(VOS_TRACE_LEVEL_FATAL,
3241 "%s: unable to retrieve WCNSS WLAN compiled version",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003242 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003243 break;
3244 }
3245
3246 vstatus = sme_GetWcnssWlanReportedVersion(pHddCtx->hHal,
3247 &versionReported);
3248 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3249 {
3250 hddLog(VOS_TRACE_LEVEL_FATAL,
3251 "%s: unable to retrieve WCNSS WLAN reported version",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003252 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003253 break;
3254 }
3255
3256 if ((versionCompiled.major != versionReported.major) ||
3257 (versionCompiled.minor != versionReported.minor) ||
3258 (versionCompiled.version != versionReported.version) ||
3259 (versionCompiled.revision != versionReported.revision))
3260 {
3261 pr_err("%s: WCNSS WLAN Version %u.%u.%u.%u, "
3262 "Host expected %u.%u.%u.%u\n",
3263 WLAN_MODULE_NAME,
3264 (int)versionReported.major,
3265 (int)versionReported.minor,
3266 (int)versionReported.version,
3267 (int)versionReported.revision,
3268 (int)versionCompiled.major,
3269 (int)versionCompiled.minor,
3270 (int)versionCompiled.version,
3271 (int)versionCompiled.revision);
3272 }
3273 else
3274 {
3275 pr_info("%s: WCNSS WLAN version %u.%u.%u.%u\n",
3276 WLAN_MODULE_NAME,
3277 (int)versionReported.major,
3278 (int)versionReported.minor,
3279 (int)versionReported.version,
3280 (int)versionReported.revision);
3281 }
3282
3283 vstatus = sme_GetWcnssSoftwareVersion(pHddCtx->hHal,
3284 versionString,
3285 sizeof(versionString));
3286 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3287 {
3288 hddLog(VOS_TRACE_LEVEL_FATAL,
3289 "%s: unable to retrieve WCNSS software version string",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003290 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003291 break;
3292 }
3293
3294 pr_info("%s: WCNSS software version %s\n",
3295 WLAN_MODULE_NAME, versionString);
3296
3297 vstatus = sme_GetWcnssHardwareVersion(pHddCtx->hHal,
3298 versionString,
3299 sizeof(versionString));
3300 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3301 {
3302 hddLog(VOS_TRACE_LEVEL_FATAL,
3303 "%s: unable to retrieve WCNSS hardware version string",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003304 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003305 break;
3306 }
3307
3308 pr_info("%s: WCNSS hardware version %s\n",
3309 WLAN_MODULE_NAME, versionString);
3310
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07003311 /* 1.Check if FW version is greater than 0.1.1.0. Only then send host-FW capability exchange message
3312 2.Host-FW capability exchange message is only present on riva 1.1 so
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003313 send the message only if it the riva is 1.1
3314 minor numbers for different riva branches:
3315 0 -> (1.0)Mainline Build
3316 1 -> (1.1)Mainline Build
3317 2->(1.04) Stability Build
3318 */
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07003319 if (((versionReported.major>0) || (versionReported.minor>1) ||
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003320 ((versionReported.minor>=1) && (versionReported.version>=1)))
3321 && ((versionReported.major == 1) && (versionReported.minor >= 1)))
3322 fwFeatCapsMsgSupported = 1;
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07003323
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003324 if (fwFeatCapsMsgSupported)
Yathish9f22e662012-12-10 14:21:35 -08003325 {
3326#ifdef WLAN_ACTIVEMODE_OFFLOAD_FEATURE
3327 if(!pHddCtx->cfg_ini->fEnableActiveModeOffload)
3328 sme_disableFeatureCapablity(WLANACTIVE_OFFLOAD);
3329#endif
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003330 sme_featureCapsExchange(pHddCtx->hHal);
Yathish9f22e662012-12-10 14:21:35 -08003331 }
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003332
3333 } while (0);
3334
3335}
3336
3337/**---------------------------------------------------------------------------
3338
Jeff Johnson295189b2012-06-20 16:38:30 -07003339 \brief hdd_wlan_startup() - HDD init function
3340
3341 This is the driver startup code executed once a WLAN device has been detected
3342
3343 \param - dev - Pointer to the underlying device
3344
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08003345 \return - 0 for success, < 0 for failure
Jeff Johnson295189b2012-06-20 16:38:30 -07003346
3347 --------------------------------------------------------------------------*/
3348
3349int hdd_wlan_startup(struct device *dev )
3350{
3351 VOS_STATUS status;
3352 hdd_adapter_t *pAdapter = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -07003353 hdd_adapter_t *pP2pAdapter = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07003354 hdd_context_t *pHddCtx = NULL;
3355 v_CONTEXT_t pVosContext= NULL;
3356#ifdef WLAN_BTAMP_FEATURE
3357 VOS_STATUS vStatus = VOS_STATUS_SUCCESS;
3358 WLANBAP_ConfigType btAmpConfig;
3359 hdd_config_t *pConfig;
3360#endif
3361 int ret;
3362#ifdef CONFIG_CFG80211
3363 struct wiphy *wiphy;
3364#endif
3365#ifdef ANI_BUS_TYPE_SDIO
3366 struct sdio_func *sdio_func_dev = dev_to_sdio_func(dev);
3367#endif //ANI_BUS_TYPE_SDIO
3368
3369 ENTER();
3370#ifdef CONFIG_CFG80211
3371 /*
3372 * cfg80211: wiphy allocation
3373 */
3374 wiphy = wlan_hdd_cfg80211_init(sizeof(hdd_context_t)) ;
3375
3376 if(wiphy == NULL)
3377 {
3378 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08003379 return -EIO;
Jeff Johnson295189b2012-06-20 16:38:30 -07003380 }
3381
3382 pHddCtx = wiphy_priv(wiphy);
3383
3384#else
3385
3386 pHddCtx = vos_mem_malloc ( sizeof( hdd_context_t ) );
3387 if(pHddCtx == NULL)
3388 {
3389 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08003390 return -ENOMEM;
Jeff Johnson295189b2012-06-20 16:38:30 -07003391 }
3392
3393#endif
3394 //Initialize the adapter context to zeros.
3395 vos_mem_zero(pHddCtx, sizeof( hdd_context_t ));
3396
3397#ifdef CONFIG_CFG80211
3398 pHddCtx->wiphy = wiphy;
3399#endif
3400 hdd_prevent_suspend();
3401 pHddCtx->isLoadUnloadInProgress = TRUE;
3402
3403 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE);
3404
3405 /*Get vos context here bcoz vos_open requires it*/
3406 pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
3407
Madan Mohan Koyyalamudi0b78e152012-11-28 15:46:51 -08003408 if(pVosContext == NULL)
3409 {
3410 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed vos_get_global_context",__func__);
3411 goto err_free_hdd_context;
3412 }
3413
Jeff Johnson295189b2012-06-20 16:38:30 -07003414 //Save the Global VOSS context in adapter context for future.
3415 pHddCtx->pvosContext = pVosContext;
3416
3417 //Save the adapter context in global context for future.
3418 ((VosContextType*)(pVosContext))->pHDDContext = (v_VOID_t*)pHddCtx;
3419
3420#ifdef ANI_BUS_TYPE_SDIO
3421 // Set the private data for the device to our adapter.
3422 libra_sdio_setprivdata (sdio_func_dev, pHddCtx);
3423 atomic_set(&pHddCtx->sdio_claim_count, 0);
3424#endif // ANI_BUS_TYPE_SDIO
3425
3426 pHddCtx->parent_dev = dev;
3427
3428 init_completion(&pHddCtx->full_pwr_comp_var);
3429 init_completion(&pHddCtx->standby_comp_var);
3430 init_completion(&pHddCtx->req_bmps_comp_var);
Madan Mohan Koyyalamudi2a1ba772012-10-11 14:59:06 -07003431 init_completion(&pHddCtx->scan_info.scan_req_completion_event);
Madan Mohan Koyyalamudif4e81002012-11-13 10:46:38 -08003432 init_completion(&pHddCtx->scan_info.abortscan_event_var);
Jeff Johnson295189b2012-06-20 16:38:30 -07003433
3434 hdd_list_init( &pHddCtx->hddAdapters, MAX_NUMBER_OF_ADAPTERS );
3435
3436 // Load all config first as TL config is needed during vos_open
3437 pHddCtx->cfg_ini = (hdd_config_t*) kmalloc(sizeof(hdd_config_t), GFP_KERNEL);
3438 if(pHddCtx->cfg_ini == NULL)
3439 {
3440 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed kmalloc hdd_config_t",__func__);
3441 goto err_free_hdd_context;
3442 }
3443
3444 vos_mem_zero(pHddCtx->cfg_ini, sizeof( hdd_config_t ));
3445
3446 // Read and parse the qcom_cfg.ini file
3447 status = hdd_parse_config_ini( pHddCtx );
3448 if ( VOS_STATUS_SUCCESS != status )
3449 {
3450 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: error parsing %s",
3451 __func__, WLAN_INI_FILE);
3452 goto err_config;
3453 }
3454
3455#ifdef CONFIG_CFG80211
3456 /*
3457 * cfg80211: Initialization and registration ...
3458 */
3459 if (0 < wlan_hdd_cfg80211_register(dev, wiphy, pHddCtx->cfg_ini))
3460 {
3461 hddLog(VOS_TRACE_LEVEL_FATAL,
3462 "%s: wlan_hdd_cfg80211_register return failure", __func__);
3463 goto err_wiphy_reg;
3464 }
3465#endif
3466
3467#ifdef FEATURE_WLAN_INTEGRATED_SOC
3468 // Update WDI trace levels based upon the cfg.ini
3469 hdd_wdi_trace_enable(eWLAN_MODULE_DAL,
3470 pHddCtx->cfg_ini->wdiTraceEnableDAL);
3471 hdd_wdi_trace_enable(eWLAN_MODULE_DAL_CTRL,
3472 pHddCtx->cfg_ini->wdiTraceEnableCTL);
3473 hdd_wdi_trace_enable(eWLAN_MODULE_DAL_DATA,
3474 pHddCtx->cfg_ini->wdiTraceEnableDAT);
3475 hdd_wdi_trace_enable(eWLAN_MODULE_PAL,
3476 pHddCtx->cfg_ini->wdiTraceEnablePAL);
3477#endif /* FEATURE_WLAN_INTEGRATED_SOC */
3478
3479#ifdef ANI_MANF_DIAG
3480 if(VOS_FTM_MODE == hdd_get_conparam())
3481 {
3482 if ( VOS_STATUS_SUCCESS != wlan_hdd_ftm_open(pHddCtx) )
3483 {
3484 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: wlan_hdd_ftm_open Failed",__func__);
3485 goto err_free_hdd_context;
3486 }
3487 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: FTM driver loaded success fully",__func__);
3488 return VOS_STATUS_SUCCESS;
3489 }
3490#endif
3491
3492 //Open watchdog module
3493 if(pHddCtx->cfg_ini->fIsLogpEnabled)
3494 {
3495 status = vos_watchdog_open(pVosContext,
3496 &((VosContextType*)pVosContext)->vosWatchdog, sizeof(VosWatchdogContext));
3497
3498 if(!VOS_IS_STATUS_SUCCESS( status ))
3499 {
3500 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_watchdog_open failed",__func__);
3501#ifdef CONFIG_CFG80211
3502 goto err_wiphy_reg;
3503#else
3504 goto err_config;
3505#endif
3506 }
3507 }
3508
3509 pHddCtx->isLogpInProgress = FALSE;
3510 vos_set_logp_in_progress(VOS_MODULE_ID_VOSS, FALSE);
3511
3512#ifdef ANI_BUS_TYPE_SDIO
3513 status = WLANBAL_Open(pHddCtx->pvosContext);
3514 if(!VOS_IS_STATUS_SUCCESS(status))
3515 {
3516 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3517 "%s: Failed to open BAL",__func__);
3518 goto err_wdclose;
3519 }
3520#endif // ANI_BUS_TYPE_SDIO
3521
3522 status = vos_chipVoteOnXOBuffer(NULL, NULL, NULL);
3523 if(!VOS_IS_STATUS_SUCCESS(status))
3524 {
3525 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Failed to configure 19.2 MHz Clock", __func__);
3526#ifdef ANI_BUS_TYPE_SDIO
3527 goto err_balclose;
3528#else
3529 goto err_wdclose;
3530#endif
3531 }
3532
3533
3534#ifdef ANI_BUS_TYPE_SDIO
3535 status = WLANSAL_Start(pHddCtx->pvosContext);
3536 if (!VOS_IS_STATUS_SUCCESS(status))
3537 {
3538 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Failed to start SAL",__func__);
3539 goto err_clkvote;
3540 }
3541
3542 /* Start BAL */
3543 status = WLANBAL_Start(pHddCtx->pvosContext);
3544
3545 if (!VOS_IS_STATUS_SUCCESS(status))
3546 {
3547 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3548 "%s: Failed to start BAL",__func__);
3549 goto err_salstop;
3550 }
3551#endif // ANI_BUS_TYPE_SDIO
3552
3553#ifdef MSM_PLATFORM_7x30
3554 /* FIXME: Volans 2.0 configuration. Reconfigure 1.3v SW supply to 1.3v. It will be configured to
3555 * 1.4v in vos_ChipPowerup() routine above
3556 */
3557#endif
3558
3559 status = vos_open( &pVosContext, 0);
3560 if ( !VOS_IS_STATUS_SUCCESS( status ))
3561 {
3562 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_open failed",__func__);
3563 goto err_balstop;
3564 }
3565
3566 /* Save the hal context in Adapter */
3567 pHddCtx->hHal = (tHalHandle)vos_get_context( VOS_MODULE_ID_SME, pVosContext );
3568
3569 if ( NULL == pHddCtx->hHal )
3570 {
3571 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: HAL context is null",__func__);
3572 goto err_vosclose;
3573 }
3574
Jeff Johnsone7245742012-09-05 17:12:55 -07003575#ifdef FEATURE_WLAN_INTEGRATED_SOC
3576 /* Vos preStart is calling */
3577 /* vos preStart which does cfg download should be called before set sme config which accesses/sets some cfgs */
3578 status = vos_preStart( pHddCtx->pvosContext );
3579 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3580 {
3581 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_preStart failed",__func__);
3582 goto err_vosclose;
3583 }
3584#endif
3585
Jeff Johnson295189b2012-06-20 16:38:30 -07003586 // Set the SME configuration parameters...
3587 status = hdd_set_sme_config( pHddCtx );
3588
3589 if ( VOS_STATUS_SUCCESS != status )
3590 {
3591 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed hdd_set_sme_config",__func__);
3592 goto err_vosclose;
3593 }
3594
3595 //Initialize the WMM module
3596 status = hdd_wmm_init(pHddCtx);
3597 if (!VOS_IS_STATUS_SUCCESS(status))
3598 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003599 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: hdd_wmm_init failed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07003600 goto err_vosclose;
3601 }
3602
3603#ifdef FEATURE_WLAN_INTEGRATED_SOC
Jeff Johnson295189b2012-06-20 16:38:30 -07003604 /* In the integrated architecture we update the configuration from
3605 the INI file and from NV before vOSS has been started so that
3606 the final contents are available to send down to the cCPU */
3607
3608 // Apply the cfg.ini to cfg.dat
3609 if (FALSE == hdd_update_config_dat(pHddCtx))
3610 {
3611 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: config update failed",__func__ );
3612 goto err_vosclose;
3613 }
3614
3615 // Apply the NV to cfg.dat
3616 /* Prima Update MAC address only at here */
3617 if (VOS_STATUS_SUCCESS != hdd_update_config_from_nv(pHddCtx))
3618 {
3619#ifdef WLAN_AUTOGEN_MACADDR_FEATURE
3620 /* There was not a valid set of MAC Addresses in NV. See if the
3621 default addresses were modified by the cfg.ini settings. If so,
3622 we'll use them, but if not, we'll autogenerate a set of MAC
3623 addresses based upon the device serial number */
3624
3625 static const v_MACADDR_t default_address =
3626 {{0x00, 0x0A, 0xF5, 0x89, 0x89, 0xFF}};
3627 unsigned int serialno;
3628 int i;
3629
3630 serialno = wcnss_get_serial_number();
3631 if ((0 != serialno) &&
3632 (0 == memcmp(&default_address, &pHddCtx->cfg_ini->intfMacAddr[0],
3633 sizeof(default_address))))
3634 {
3635 /* cfg.ini has the default address, invoke autogen logic */
3636
3637 /* MAC address has 3 bytes of OUI so we have a maximum of 3
3638 bytes of the serial number that can be used to generate
3639 the other 3 bytes of the MAC address. Mask off all but
3640 the lower 3 bytes (this will also make sure we don't
3641 overflow in the next step) */
3642 serialno &= 0x00FFFFFF;
3643
3644 /* we need a unique address for each session */
3645 serialno *= VOS_MAX_CONCURRENCY_PERSONA;
3646
3647 /* autogen all addresses */
3648 for (i = 0; i < VOS_MAX_CONCURRENCY_PERSONA; i++)
3649 {
3650 /* start with the entire default address */
3651 pHddCtx->cfg_ini->intfMacAddr[i] = default_address;
3652 /* then replace the lower 3 bytes */
3653 pHddCtx->cfg_ini->intfMacAddr[i].bytes[3] = (serialno >> 16) & 0xFF;
3654 pHddCtx->cfg_ini->intfMacAddr[i].bytes[4] = (serialno >> 8) & 0xFF;
3655 pHddCtx->cfg_ini->intfMacAddr[i].bytes[5] = serialno & 0xFF;
3656
3657 serialno++;
3658 }
3659
3660 pr_info("wlan: Invalid MAC addresses in NV, autogenerated "
3661 MAC_ADDRESS_STR,
3662 MAC_ADDR_ARRAY(pHddCtx->cfg_ini->intfMacAddr[0].bytes));
3663 }
3664 else
3665#endif //WLAN_AUTOGEN_MACADDR_FEATURE
3666 {
3667 hddLog(VOS_TRACE_LEVEL_ERROR,
3668 "%s: Invalid MAC address in NV, using MAC from ini file "
3669 MAC_ADDRESS_STR, __func__,
3670 MAC_ADDR_ARRAY(pHddCtx->cfg_ini->intfMacAddr[0].bytes));
3671 }
3672 }
3673 {
3674 eHalStatus halStatus;
3675 // Set the MAC Address
3676 // Currently this is used by HAL to add self sta. Remove this once self sta is added as part of session open.
3677 halStatus = cfgSetStr( pHddCtx->hHal, WNI_CFG_STA_ID,
3678 (v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[0],
3679 sizeof( pHddCtx->cfg_ini->intfMacAddr[0]) );
3680
3681 if (!HAL_STATUS_SUCCESS( halStatus ))
3682 {
3683 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed to set MAC Address. "
3684 "HALStatus is %08d [x%08x]",__func__, halStatus, halStatus );
Madan Mohan Koyyalamudib8b126b2012-11-15 17:37:30 -08003685 goto err_vosclose;
Jeff Johnson295189b2012-06-20 16:38:30 -07003686 }
3687 }
3688#endif // FEATURE_WLAN_INTEGRATED_SOC
3689
3690 /*Start VOSS which starts up the SME/MAC/HAL modules and everything else
3691 Note: Firmware image will be read and downloaded inside vos_start API */
3692 status = vos_start( pHddCtx->pvosContext );
3693 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3694 {
3695 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_start failed",__func__);
3696 goto err_vosclose;
3697 }
3698
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003699 /* Exchange capability info between Host and FW and also get versioning info from FW */
3700 hdd_exchange_version_and_caps(pHddCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -07003701
3702 status = hdd_post_voss_start_config( pHddCtx );
3703 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3704 {
3705 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hdd_post_voss_start_config failed",
3706 __func__);
3707 goto err_vosstop;
3708 }
3709
3710#ifdef WLAN_SOFTAP_FEATURE
3711 if (VOS_STA_SAP_MODE == hdd_get_conparam())
3712 {
3713 pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_SOFTAP, "softap.%d",
3714 wlan_hdd_get_intf_addr(pHddCtx), FALSE );
3715 }
3716 else
3717 {
3718#endif
3719 pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_INFRA_STATION, "wlan%d",
3720 wlan_hdd_get_intf_addr(pHddCtx), FALSE );
3721 if (pAdapter != NULL)
3722 {
3723#ifdef WLAN_FEATURE_P2P
Madan Mohan Koyyalamudiedfc1b72012-10-18 20:25:55 -07003724 tANI_U8* p2p_dev_addr = wlan_hdd_get_intf_addr(pHddCtx);
3725 if (p2p_dev_addr != NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -07003726 {
Madan Mohan Koyyalamudiedfc1b72012-10-18 20:25:55 -07003727 vos_mem_copy(&pHddCtx->p2pDeviceAddress.bytes[0],
3728 p2p_dev_addr, VOS_MAC_ADDR_SIZE);
3729
3730 if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
3731 {
3732 /* Generate the P2P Device Address. This consists of the device's
3733 * primary MAC address with the locally administered bit set.
3734 */
3735 pHddCtx->p2pDeviceAddress.bytes[0] |= 0x02;
3736 }
Jeff Johnsone7245742012-09-05 17:12:55 -07003737 }
3738 else
3739 {
Madan Mohan Koyyalamudiedfc1b72012-10-18 20:25:55 -07003740 hddLog(VOS_TRACE_LEVEL_FATAL,
3741 "%s: Failed to allocate mac_address for p2p_device",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003742 __func__);
Madan Mohan Koyyalamudiedfc1b72012-10-18 20:25:55 -07003743 goto err_close_adapter;
Jeff Johnson295189b2012-06-20 16:38:30 -07003744 }
Jeff Johnsone7245742012-09-05 17:12:55 -07003745
3746 pP2pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_P2P_DEVICE, "p2p%d",
3747 &pHddCtx->p2pDeviceAddress.bytes[0], FALSE );
3748 if ( NULL == pP2pAdapter )
3749 {
3750 hddLog(VOS_TRACE_LEVEL_FATAL,
3751 "%s: Failed to do hdd_open_adapter for P2P Device Interface",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003752 __func__);
Jeff Johnsone7245742012-09-05 17:12:55 -07003753 goto err_close_adapter;
3754 }
Jeff Johnson295189b2012-06-20 16:38:30 -07003755#endif
Jeff Johnsone7245742012-09-05 17:12:55 -07003756 }
Jeff Johnson295189b2012-06-20 16:38:30 -07003757#ifdef WLAN_SOFTAP_FEATURE
3758 }
3759#endif
3760
3761 if( pAdapter == NULL )
3762 {
3763 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
3764#ifdef ANI_BUS_TYPE_SDIO
3765 goto err_balstop;
3766#else
3767 goto err_clkvote;
3768#endif
3769 }
Jeff Johnsone7245742012-09-05 17:12:55 -07003770
Jeff Johnson295189b2012-06-20 16:38:30 -07003771#ifdef WLAN_BTAMP_FEATURE
3772 vStatus = WLANBAP_Open(pVosContext);
3773 if(!VOS_IS_STATUS_SUCCESS(vStatus))
3774 {
3775 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3776 "%s: Failed to open BAP",__func__);
Jeff Johnsone7245742012-09-05 17:12:55 -07003777 goto err_close_adapter;
Jeff Johnson295189b2012-06-20 16:38:30 -07003778 }
3779
3780 vStatus = BSL_Init(pVosContext);
3781 if(!VOS_IS_STATUS_SUCCESS(vStatus))
3782 {
3783 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3784 "%s: Failed to Init BSL",__func__);
3785 goto err_bap_close;
3786 }
3787 vStatus = WLANBAP_Start(pVosContext);
3788 if (!VOS_IS_STATUS_SUCCESS(vStatus))
3789 {
3790 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3791 "%s: Failed to start TL",__func__);
3792 goto err_bap_close;
3793 }
3794
3795 pConfig = pHddCtx->cfg_ini;
3796 btAmpConfig.ucPreferredChannel = pConfig->preferredChannel;
3797 status = WLANBAP_SetConfig(&btAmpConfig);
3798
3799#endif //WLAN_BTAMP_FEATURE
Jeff Johnsone7245742012-09-05 17:12:55 -07003800
Jeff Johnson295189b2012-06-20 16:38:30 -07003801#ifdef FEATURE_WLAN_SCAN_PNO
3802 /*SME must send channel update configuration to RIVA*/
3803 sme_UpdateChannelConfig(pHddCtx->hHal);
3804#endif
3805
3806#ifdef FEATURE_WLAN_INTEGRATED_SOC
3807 /* Register with platform driver as client for Suspend/Resume */
3808 status = hddRegisterPmOps(pHddCtx);
3809 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3810 {
3811 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddRegisterPmOps failed",__func__);
3812#ifdef WLAN_BTAMP_FEATURE
3813 goto err_bap_stop;
3814#else
Jeff Johnsone7245742012-09-05 17:12:55 -07003815 goto err_close_adapter;
Jeff Johnson295189b2012-06-20 16:38:30 -07003816#endif //WLAN_BTAMP_FEATURE
3817 }
3818
3819 /* Register TM level change handler function to the platform */
3820 status = hddDevTmRegisterNotifyCallback(pHddCtx);
3821 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3822 {
3823 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDevTmRegisterNotifyCallback failed",__func__);
3824 goto err_unregister_pmops;
3825 }
3826#endif
3827
3828 /* register for riva power on lock to platform driver */
3829 if (req_riva_power_on_lock("wlan"))
3830 {
3831 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: req riva power on lock failed",
3832 __func__);
3833 goto err_unregister_pmops;
3834 }
3835
3836#ifdef CONFIG_HAS_EARLYSUSPEND
3837 // Register suspend/resume callbacks
3838 if(pHddCtx->cfg_ini->nEnableSuspend)
3839 {
3840 register_wlan_suspend();
3841 }
3842#endif
3843
3844 // register net device notifier for device change notification
3845 ret = register_netdevice_notifier(&hdd_netdev_notifier);
3846
3847 if(ret < 0)
3848 {
3849 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: register_netdevice_notifier failed",__func__);
3850 goto err_free_power_on_lock;
3851 }
3852
3853 //Initialize the nlink service
3854 if(nl_srv_init() != 0)
3855 {
3856 hddLog(VOS_TRACE_LEVEL_FATAL,"%S: nl_srv_init failed",__func__);
3857 goto err_reg_netdev;
3858 }
3859
3860 //Initialize the BTC service
3861 if(btc_activate_service(pHddCtx) != 0)
3862 {
3863 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: btc_activate_service failed",__func__);
3864 goto err_nl_srv;
3865 }
3866
3867#ifdef PTT_SOCK_SVC_ENABLE
3868 //Initialize the PTT service
3869 if(ptt_sock_activate_svc(pHddCtx) != 0)
3870 {
3871 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: ptt_sock_activate_svc failed",__func__);
3872 goto err_nl_srv;
3873 }
3874#endif
3875
Jeff Johnson295189b2012-06-20 16:38:30 -07003876#ifdef CONFIG_HAS_EARLYSUSPEND
3877 hdd_register_mcast_bcast_filter(pHddCtx);
3878#endif
3879#ifdef CONFIG_CFG80211
3880#ifdef WLAN_SOFTAP_FEATURE
3881 if (VOS_STA_SAP_MODE != hdd_get_conparam())
3882#endif
3883 {
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07003884 /* Action frame registered in one adapter which will
3885 * applicable to all interfaces
3886 */
Madan Mohan Koyyalamudie233e292012-09-18 17:38:02 -07003887 wlan_hdd_cfg80211_post_voss_start(pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -07003888 }
3889#endif
3890
3891 mutex_init(&pHddCtx->sap_lock);
3892
3893 pHddCtx->isLoadUnloadInProgress = FALSE;
3894
Jeff Johnsone7245742012-09-05 17:12:55 -07003895#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
3896 /* Initialize the wake lcok */
3897 wake_lock_init(&pHddCtx->rx_wake_lock,
3898 WAKE_LOCK_SUSPEND,
3899 "qcom_rx_wakelock");
3900#endif
Madan Mohan Koyyalamudi69fc3ad2012-11-28 16:04:56 -08003901 /* Initialize the wake lcok */
3902 wake_lock_init(&pHddCtx->sap_wake_lock,
3903 WAKE_LOCK_SUSPEND,
3904 "qcom_sap_wakelock");
Jeff Johnsone7245742012-09-05 17:12:55 -07003905
Madan Mohan Koyyalamudi2a1ba772012-10-11 14:59:06 -07003906 vos_event_init(&pHddCtx->scan_info.scan_finished_event);
3907 pHddCtx->scan_info.scan_pending_option = WEXT_SCAN_PENDING_GIVEUP;
Jeff Johnson295189b2012-06-20 16:38:30 -07003908
3909 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, FALSE);
3910 hdd_allow_suspend();
Jeff Johnsone7245742012-09-05 17:12:55 -07003911
3912 // Initialize the restart logic
3913 wlan_hdd_restart_init(pHddCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -07003914
3915 goto success;
3916
3917err_nl_srv:
3918 nl_srv_exit();
3919
3920err_reg_netdev:
3921 unregister_netdevice_notifier(&hdd_netdev_notifier);
3922
3923err_free_power_on_lock:
3924 free_riva_power_on_lock("wlan");
3925
3926err_unregister_pmops:
3927 hddDevTmUnregisterNotifyCallback(pHddCtx);
3928 hddDeregisterPmOps(pHddCtx);
3929
3930#ifdef WLAN_BTAMP_FEATURE
3931err_bap_stop:
3932 WLANBAP_Stop(pVosContext);
3933#endif
3934
3935#ifdef WLAN_BTAMP_FEATURE
3936err_bap_close:
3937 WLANBAP_Close(pVosContext);
3938#endif
3939
Jeff Johnson295189b2012-06-20 16:38:30 -07003940err_close_adapter:
3941 hdd_close_all_adapters( pHddCtx );
3942
3943err_vosstop:
3944 vos_stop(pVosContext);
3945
3946err_vosclose:
3947 status = vos_sched_close( pVosContext );
3948 if (!VOS_IS_STATUS_SUCCESS(status)) {
3949 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
3950 "%s: Failed to close VOSS Scheduler", __func__);
3951 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status ) );
3952 }
3953 vos_close(pVosContext );
3954
3955err_balstop:
3956#ifdef ANI_BUS_TYPE_SDIO
3957#ifndef ANI_MANF_DIAG
3958 wlan_hdd_enable_deepsleep(pHddCtx->pvosContext);
3959#endif
3960
3961 WLANBAL_Stop(pHddCtx->pvosContext);
3962 WLANBAL_SuspendChip(pHddCtx->pvosContext);
3963#endif
3964
3965#ifdef ANI_BUS_TYPE_SDIO
3966err_salstop:
3967 WLANSAL_Stop(pHddCtx->pvosContext);
3968
3969#endif
3970err_clkvote:
3971 vos_chipVoteOffXOBuffer(NULL, NULL, NULL);
3972
3973#ifdef ANI_BUS_TYPE_SDIO
3974err_balclose:
3975 WLANBAL_Close(pHddCtx->pvosContext);
3976#endif // ANI_BUS_TYPE_SDIO
3977
3978err_wdclose:
3979 if(pHddCtx->cfg_ini->fIsLogpEnabled)
3980 vos_watchdog_close(pVosContext);
3981
3982#ifdef CONFIG_CFG80211
3983err_wiphy_reg:
3984 wiphy_unregister(wiphy) ;
3985#endif
3986
3987err_config:
3988 kfree(pHddCtx->cfg_ini);
3989 pHddCtx->cfg_ini= NULL;
3990
3991err_free_hdd_context:
3992 hdd_allow_suspend();
3993#ifdef CONFIG_CFG80211
3994 wiphy_free(wiphy) ;
3995 //kfree(wdev) ;
3996#else
3997 vos_mem_free( pHddCtx );
3998#endif
3999 VOS_BUG(1);
4000
Madan Mohan Koyyalamudid57ae632012-11-06 18:42:48 -08004001 if (hdd_is_ssr_required())
4002 {
4003 /* WDI timeout had happened during load, so SSR is needed here */
4004 subsystem_restart("wcnss");
4005 msleep(5000);
4006 }
4007 hdd_set_ssr_required (VOS_FALSE);
4008
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08004009 return -EIO;
Jeff Johnson295189b2012-06-20 16:38:30 -07004010
4011success:
4012 EXIT();
4013 return 0;
4014}
4015
4016/**---------------------------------------------------------------------------
4017
Jeff Johnson32d95a32012-09-10 13:15:23 -07004018 \brief hdd_driver_init() - Core Driver Init Function
Jeff Johnson295189b2012-06-20 16:38:30 -07004019
Jeff Johnson32d95a32012-09-10 13:15:23 -07004020 This is the driver entry point - called in different timeline depending
4021 on whether the driver is statically or dynamically linked
Jeff Johnson295189b2012-06-20 16:38:30 -07004022
4023 \param - None
4024
4025 \return - 0 for success, non zero for failure
4026
4027 --------------------------------------------------------------------------*/
Jeff Johnson32d95a32012-09-10 13:15:23 -07004028static int hdd_driver_init( void)
Jeff Johnson295189b2012-06-20 16:38:30 -07004029{
4030 VOS_STATUS status;
4031 v_CONTEXT_t pVosContext = NULL;
4032#ifdef ANI_BUS_TYPE_SDIO
4033 struct sdio_func *sdio_func_dev = NULL;
4034 unsigned int attempts = 0;
4035#endif // ANI_BUS_TYPE_SDIO
4036 struct device *dev = NULL;
4037 int ret_status = 0;
4038
4039 ENTER();
4040
Jeff Johnsone7245742012-09-05 17:12:55 -07004041#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07004042 wake_lock_init(&wlan_wake_lock, WAKE_LOCK_SUSPEND, "wlan");
Jeff Johnsone7245742012-09-05 17:12:55 -07004043#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004044
4045 pr_info("%s: loading driver v%s\n", WLAN_MODULE_NAME,
4046 QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR);
4047
4048 //Power Up Libra WLAN card first if not already powered up
4049 status = vos_chipPowerUp(NULL,NULL,NULL);
4050 if (!VOS_IS_STATUS_SUCCESS(status))
4051 {
4052 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN not Powered Up. "
4053 "exiting", __func__);
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08004054 return -EIO;
Jeff Johnson295189b2012-06-20 16:38:30 -07004055 }
4056
4057#ifdef ANI_BUS_TYPE_SDIO
4058 //SDIO Polling should be turned on for card detection. When using Android Wi-Fi GUI
4059 //users need not trigger SDIO polling explicitly. However when loading drivers via
4060 //command line (Adb shell), users must turn on SDIO polling prior to loading WLAN.
4061 do {
4062 sdio_func_dev = libra_getsdio_funcdev();
4063 if (NULL == sdio_func_dev) {
4064 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN not detected yet.",__func__);
4065 attempts++;
4066 }
4067 else {
4068 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN detecton succeeded",__func__);
4069 dev = &sdio_func_dev->dev;
4070 break;
4071 }
4072
4073 if(attempts == 7)
4074 break;
4075
4076 msleep(250);
4077
4078 }while (attempts < 7);
4079
4080 //Retry to detect the card again by Powering Down the chip and Power up the chip
4081 //again. This retry is done to recover from CRC Error
4082 if (NULL == sdio_func_dev) {
4083
4084 attempts = 0;
4085
4086 //Vote off any PMIC voltage supplies
4087 vos_chipPowerDown(NULL, NULL, NULL);
4088
4089 msleep(1000);
4090
4091 //Power Up Libra WLAN card first if not already powered up
4092 status = vos_chipPowerUp(NULL,NULL,NULL);
4093 if (!VOS_IS_STATUS_SUCCESS(status))
4094 {
4095 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN not Powered Up. "
4096 "exiting", __func__);
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08004097 return -EIO;
Jeff Johnson295189b2012-06-20 16:38:30 -07004098 }
4099
4100 do {
4101 sdio_func_dev = libra_getsdio_funcdev();
4102 if (NULL == sdio_func_dev) {
4103 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN not detected yet.",__func__);
4104 attempts++;
4105 }
4106 else {
4107 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN detecton succeeded",__func__);
4108 dev = &sdio_func_dev->dev;
4109 break;
4110 }
4111
4112 if(attempts == 2)
4113 break;
4114
4115 msleep(1000);
4116
4117 }while (attempts < 3);
4118 }
4119
4120#endif // ANI_BUS_TYPE_SDIO
4121
4122#ifdef ANI_BUS_TYPE_PCI
4123
4124 dev = wcnss_wlan_get_device();
4125
4126#endif // ANI_BUS_TYPE_PCI
4127
4128#ifdef ANI_BUS_TYPE_PLATFORM
4129 dev = wcnss_wlan_get_device();
4130#endif // ANI_BUS_TYPE_PLATFORM
4131
4132
4133 do {
4134 if (NULL == dev) {
4135 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: WLAN device not found!!",__func__);
4136 ret_status = -1;
4137 break;
4138 }
4139
4140#ifdef MEMORY_DEBUG
4141 vos_mem_init();
4142#endif
4143
4144#ifdef TIMER_MANAGER
4145 vos_timer_manager_init();
4146#endif
4147
4148 /* Preopen VOSS so that it is ready to start at least SAL */
4149 status = vos_preOpen(&pVosContext);
4150
4151 if (!VOS_IS_STATUS_SUCCESS(status))
4152 {
4153 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed to preOpen VOSS", __func__);
4154 ret_status = -1;
4155 break;
4156 }
4157
4158#ifdef ANI_BUS_TYPE_SDIO
4159 /* Now Open SAL */
4160 status = WLANSAL_Open(pVosContext, 0);
4161
4162 if(!VOS_IS_STATUS_SUCCESS(status))
4163 {
4164 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed to open SAL", __func__);
4165
4166 /* If unable to open, cleanup and return failure */
4167 vos_preClose( &pVosContext );
4168 ret_status = -1;
4169 break;
4170 }
4171#endif // ANI_BUS_TYPE_SDIO
4172
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004173#ifndef MODULE
4174 /* For statically linked driver, call hdd_set_conparam to update curr_con_mode
4175 */
4176 hdd_set_conparam((v_UINT_t)con_mode);
4177#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004178
4179 // Call our main init function
4180 if(hdd_wlan_startup(dev)) {
4181 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: WLAN Driver Initialization failed",
4182 __func__);
4183#ifdef ANI_BUS_TYPE_SDIO
4184 WLANSAL_Close(pVosContext);
4185#endif // ANI_BUS_TYPE_SDIO
4186 vos_preClose( &pVosContext );
4187 ret_status = -1;
4188 break;
4189 }
4190
4191 /* Cancel the vote for XO Core ON
4192 * This is done here for safety purposes in case we re-initialize without turning
4193 * it OFF in any error scenario.
4194 */
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004195 hddLog(VOS_TRACE_LEVEL_INFO, "In module init: Ensure Force XO Core is OFF"
Jeff Johnson295189b2012-06-20 16:38:30 -07004196 " when WLAN is turned ON so Core toggles"
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004197 " unless we enter PSD");
Jeff Johnson295189b2012-06-20 16:38:30 -07004198 if (vos_chipVoteXOCore(NULL, NULL, NULL, VOS_FALSE) != VOS_STATUS_SUCCESS)
4199 {
4200 hddLog(VOS_TRACE_LEVEL_ERROR, "Could not cancel XO Core ON vote. Not returning failure."
4201 " Power consumed will be high\n");
4202 }
4203 } while (0);
4204
4205 if (0 != ret_status)
4206 {
4207 //Assert Deep sleep signal now to put Libra HW in lowest power state
4208 status = vos_chipAssertDeepSleep( NULL, NULL, NULL );
4209 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status) );
4210
4211 //Vote off any PMIC voltage supplies
4212 vos_chipPowerDown(NULL, NULL, NULL);
4213#ifdef TIMER_MANAGER
4214 vos_timer_exit();
4215#endif
4216#ifdef MEMORY_DEBUG
4217 vos_mem_exit();
4218#endif
4219
Jeff Johnsone7245742012-09-05 17:12:55 -07004220#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07004221 wake_lock_destroy(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07004222#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004223 pr_err("%s: driver load failure\n", WLAN_MODULE_NAME);
4224 }
4225 else
4226 {
4227 //Send WLAN UP indication to Nlink Service
4228 send_btc_nlink_msg(WLAN_MODULE_UP_IND, 0);
4229
4230 pr_info("%s: driver loaded\n", WLAN_MODULE_NAME);
4231
4232 }
4233
4234 EXIT();
4235
4236 return ret_status;
4237}
4238
Jeff Johnson32d95a32012-09-10 13:15:23 -07004239/**---------------------------------------------------------------------------
4240
4241 \brief hdd_module_init() - Init Function
4242
4243 This is the driver entry point (invoked when module is loaded using insmod)
4244
4245 \param - None
4246
4247 \return - 0 for success, non zero for failure
4248
4249 --------------------------------------------------------------------------*/
4250#ifdef MODULE
4251static int __init hdd_module_init ( void)
4252{
4253 return hdd_driver_init();
4254}
Jeff Johnson32d95a32012-09-10 13:15:23 -07004255#else /* #ifdef MODULE */
4256static int __init hdd_module_init ( void)
4257{
4258 /* Driver initialization is delayed to fwpath_changed_handler */
4259 return 0;
4260}
Jeff Johnson32d95a32012-09-10 13:15:23 -07004261#endif /* #ifdef MODULE */
4262
Jeff Johnson295189b2012-06-20 16:38:30 -07004263
4264/**---------------------------------------------------------------------------
4265
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004266 \brief hdd_driver_exit() - Exit function
Jeff Johnson295189b2012-06-20 16:38:30 -07004267
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004268 This is the driver exit point (invoked when module is unloaded using rmmod
4269 or con_mode was changed by userspace)
Jeff Johnson295189b2012-06-20 16:38:30 -07004270
4271 \param - None
4272
4273 \return - None
4274
4275 --------------------------------------------------------------------------*/
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004276static void hdd_driver_exit(void)
Jeff Johnson295189b2012-06-20 16:38:30 -07004277{
4278 hdd_context_t *pHddCtx = NULL;
4279 v_CONTEXT_t pVosContext = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07004280
4281 pr_info("%s: unloading driver v%s\n", WLAN_MODULE_NAME, QWLAN_VERSIONSTR);
4282
4283 //Get the global vos context
4284 pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
4285
4286 if(!pVosContext)
4287 {
4288 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
4289 goto done;
4290 }
4291
4292 //Get the HDD context.
4293 pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
4294
4295 if(!pHddCtx)
4296 {
4297 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: module exit called before probe",__func__);
4298 }
4299 else
4300 {
Jeff Johnsone7245742012-09-05 17:12:55 -07004301 /* module exit should never proceed if SSR is not completed */
Jeff Johnson295189b2012-06-20 16:38:30 -07004302 while(isWDresetInProgress()){
Jeff Johnsone7245742012-09-05 17:12:55 -07004303 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:SSR in Progress; block rmmod for 1 second!!!",__func__);
4304 msleep(1000);
Jeff Johnson295189b2012-06-20 16:38:30 -07004305 }
4306
4307 pHddCtx->isLoadUnloadInProgress = TRUE;
4308 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE);
4309
4310 //Do all the cleanup before deregistering the driver
4311 hdd_wlan_exit(pHddCtx);
4312 }
4313
4314#ifdef ANI_BUS_TYPE_SDIO
4315 WLANSAL_Close(pVosContext);
4316#endif // ANI_BUS_TYPE_SDIO
4317
4318 vos_preClose( &pVosContext );
4319
4320#ifdef TIMER_MANAGER
4321 vos_timer_exit();
4322#endif
4323#ifdef MEMORY_DEBUG
4324 vos_mem_exit();
4325#endif
4326
4327done:
Jeff Johnsone7245742012-09-05 17:12:55 -07004328#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07004329 wake_lock_destroy(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07004330#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004331 pr_info("%s: driver unloaded\n", WLAN_MODULE_NAME);
4332}
4333
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004334/**---------------------------------------------------------------------------
4335
4336 \brief hdd_module_exit() - Exit function
4337
4338 This is the driver exit point (invoked when module is unloaded using rmmod)
4339
4340 \param - None
4341
4342 \return - None
4343
4344 --------------------------------------------------------------------------*/
4345static void __exit hdd_module_exit(void)
4346{
4347 hdd_driver_exit();
4348}
4349
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004350#ifdef MODULE
4351static int fwpath_changed_handler(const char *kmessage,
4352 struct kernel_param *kp)
4353{
4354 /* nothing to do when driver is DLKM */
4355 return 0;
4356}
4357
4358static int con_mode_handler(const char *kmessage,
4359 struct kernel_param *kp)
4360{
Madan Mohan Koyyalamudif2f8d8b2012-10-11 17:06:59 -07004361 return param_set_int(kmessage, kp);
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004362}
4363#else /* #ifdef MODULE */
4364/**---------------------------------------------------------------------------
4365
4366 \brief fwpath_changed_handler() - Handler Function
4367
4368 This is the driver entry point
4369 - delayed driver initialization when driver is statically linked
4370 - invoked when module parameter fwpath is modified from userpspace to signal
4371 initializing the WLAN driver
4372
4373 \return - 0 for success, non zero for failure
4374
4375 --------------------------------------------------------------------------*/
4376static int fwpath_changed_handler(const char *kmessage,
4377 struct kernel_param *kp)
4378{
Madan Mohan Koyyalamudi62e60052012-10-05 14:27:22 -07004379 int ret_status;
4380
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004381 if (!wlan_hdd_inited) {
Madan Mohan Koyyalamudi62e60052012-10-05 14:27:22 -07004382 ret_status = hdd_driver_init();
4383 wlan_hdd_inited = ret_status ? 0 : 1;
4384 return ret_status;
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004385 }
4386
4387 hdd_driver_exit();
4388
4389 msleep(200);
4390
Madan Mohan Koyyalamudi62e60052012-10-05 14:27:22 -07004391 ret_status = hdd_driver_init();
4392 wlan_hdd_inited = ret_status ? 0 : 1;
4393 return ret_status;
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004394}
4395
Jeff Johnson295189b2012-06-20 16:38:30 -07004396/**---------------------------------------------------------------------------
4397
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004398 \brief con_mode_handler() -
4399
4400 Handler function for module param con_mode when it is changed by userspace
4401 Dynamically linked - do nothing
4402 Statically linked - exit and init driver, as in rmmod and insmod
4403
4404 \param -
4405
4406 \return -
4407
4408 --------------------------------------------------------------------------*/
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004409static int con_mode_handler(const char *kmessage,
4410 struct kernel_param *kp)
4411{
4412 int ret = param_set_int(kmessage, kp);
4413
4414 if (ret)
4415 return ret;
4416
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004417 return fwpath_changed_handler(kmessage, kp);
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004418}
4419#endif /* #ifdef MODULE */
4420
4421/**---------------------------------------------------------------------------
4422
Jeff Johnson295189b2012-06-20 16:38:30 -07004423 \brief hdd_get_conparam() -
4424
4425 This is the driver exit point (invoked when module is unloaded using rmmod)
4426
4427 \param - None
4428
4429 \return - tVOS_CON_MODE
4430
4431 --------------------------------------------------------------------------*/
4432tVOS_CON_MODE hdd_get_conparam ( void )
4433{
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004434#ifdef MODULE
Jeff Johnson295189b2012-06-20 16:38:30 -07004435 return (tVOS_CON_MODE)con_mode;
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004436#else
4437 return (tVOS_CON_MODE)curr_con_mode;
4438#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004439}
4440void hdd_set_conparam ( v_UINT_t newParam )
4441{
4442 con_mode = newParam;
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004443#ifndef MODULE
4444 curr_con_mode = con_mode;
4445#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004446}
4447/**---------------------------------------------------------------------------
4448
4449 \brief hdd_softap_sta_deauth() - function
4450
4451 This to take counter measure to handle deauth req from HDD
4452
4453 \param - pAdapter - Pointer to the HDD
4454
4455 \param - enable - boolean value
4456
4457 \return - None
4458
4459 --------------------------------------------------------------------------*/
4460
4461void hdd_softap_sta_deauth(hdd_adapter_t *pAdapter, v_U8_t *pDestMacAddress)
4462{
4463 v_U8_t STAId;
4464 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
4465#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
4466 tHalHandle hHalHandle;
4467#endif
4468
4469 ENTER();
4470
4471 hddLog( LOGE, "hdd_softap_sta_deauth:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
4472
4473 //Ignore request to deauth bcmc station
4474 if( pDestMacAddress[0] & 0x1 )
4475 return;
4476
4477 WLANSAP_DeauthSta(pVosContext,pDestMacAddress);
4478
4479 /*Get the Station ID*/
4480#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
4481 hHalHandle = (tHalHandle ) vos_get_context(VOS_MODULE_ID_HAL, pVosContext);
4482 if (eHAL_STATUS_SUCCESS ==
4483 halTable_FindStaidByAddr(hHalHandle, (tANI_U8 *)pDestMacAddress,
4484 &STAId))
4485 {
4486 hdd_softap_DeregisterSTA(pAdapter, STAId);
4487 }
4488#else
4489 if (VOS_STATUS_SUCCESS ==
4490 hdd_softap_GetStaId(pAdapter, (v_MACADDR_t *)pDestMacAddress,
4491 &STAId))
4492 {
4493 hdd_softap_DeregisterSTA(pAdapter, STAId);
4494 }
4495#endif
4496
4497 EXIT();
4498}
4499
4500/**---------------------------------------------------------------------------
4501
4502 \brief hdd_softap_sta_disassoc() - function
4503
4504 This to take counter measure to handle deauth req from HDD
4505
4506 \param - pAdapter - Pointer to the HDD
4507
4508 \param - enable - boolean value
4509
4510 \return - None
4511
4512 --------------------------------------------------------------------------*/
4513
4514void hdd_softap_sta_disassoc(hdd_adapter_t *pAdapter,v_U8_t *pDestMacAddress)
4515{
4516 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
4517
4518 ENTER();
4519
4520 hddLog( LOGE, "hdd_softap_sta_disassoc:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
4521
4522 //Ignore request to disassoc bcmc station
4523 if( pDestMacAddress[0] & 0x1 )
4524 return;
4525
4526 WLANSAP_DisassocSta(pVosContext,pDestMacAddress);
4527}
4528
4529void hdd_softap_tkip_mic_fail_counter_measure(hdd_adapter_t *pAdapter,v_BOOL_t enable)
4530{
4531 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
4532
4533 ENTER();
4534
4535 hddLog( LOGE, "hdd_softap_tkip_mic_fail_counter_measure:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
4536
4537 WLANSAP_SetCounterMeasure(pVosContext, (v_BOOL_t)enable);
4538}
4539
Jeff Johnson295189b2012-06-20 16:38:30 -07004540/**---------------------------------------------------------------------------
4541 *
4542 * \brief hdd_get__concurrency_mode() -
4543 *
4544 *
4545 * \param - None
4546 *
4547 * \return - CONCURRENCY MODE
4548 *
4549 * --------------------------------------------------------------------------*/
4550tVOS_CONCURRENCY_MODE hdd_get_concurrency_mode ( void )
4551{
4552 v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL );
4553 hdd_context_t *pHddCtx;
4554
4555 if (NULL != pVosContext)
4556 {
4557 pHddCtx = vos_get_context( VOS_MODULE_ID_HDD, pVosContext);
4558 if (NULL != pHddCtx)
4559 {
4560 return (tVOS_CONCURRENCY_MODE)pHddCtx->concurrency_mode;
4561 }
4562 }
4563
4564 /* we are in an invalid state :( */
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07004565 hddLog(LOGE, "%s: Invalid context", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07004566 return VOS_STA;
4567}
4568
4569/* Decide whether to allow/not the apps power collapse.
4570 * Allow apps power collapse if we are in connected state.
4571 * if not, allow only if we are in IMPS */
4572v_BOOL_t hdd_is_apps_power_collapse_allowed(hdd_context_t* pHddCtx)
4573{
4574 tPmcState pmcState = pmcGetPmcState(pHddCtx->hHal);
4575 hdd_config_t *pConfig = pHddCtx->cfg_ini;
4576 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
4577 hdd_adapter_t *pAdapter = NULL;
4578 VOS_STATUS status;
Yathish9f22e662012-12-10 14:21:35 -08004579 tVOS_CONCURRENCY_MODE concurrent_state = 0;
Jeff Johnson295189b2012-06-20 16:38:30 -07004580
4581#ifdef WLAN_SOFTAP_FEATURE
4582 if (VOS_STA_SAP_MODE == hdd_get_conparam())
4583 return TRUE;
4584#endif
4585
Yathish9f22e662012-12-10 14:21:35 -08004586 concurrent_state = hdd_get_concurrency_mode();
4587
4588#ifdef WLAN_ACTIVEMODE_OFFLOAD_FEATURE
4589 if(((concurrent_state == (VOS_STA | VOS_P2P_CLIENT)) ||
4590 (concurrent_state == (VOS_STA | VOS_P2P_GO))) &&
4591 (IS_ACTIVEMODE_OFFLOAD_FEATURE_ENABLE))
4592 return TRUE;
4593#endif
4594
Jeff Johnson295189b2012-06-20 16:38:30 -07004595 /*loop through all adapters. TBD fix for Concurrency */
4596 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
4597 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
4598 {
4599 pAdapter = pAdapterNode->pAdapter;
4600 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode)
4601 || (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) )
4602 {
4603 if ((pConfig->fIsImpsEnabled || pConfig->fIsBmpsEnabled)
4604 && (pmcState != IMPS && pmcState != BMPS
4605 && pmcState != STOPPED && pmcState != STANDBY))
4606 {
4607 return FALSE;
4608 }
4609 }
4610 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
4611 pAdapterNode = pNext;
4612 }
4613 return TRUE;
4614}
4615
Madan Mohan Koyyalamudic72a4d62012-11-08 14:59:34 -08004616/* Decides whether to send suspend notification to Riva
4617 * if any adapter is in BMPS; then it is required */
4618v_BOOL_t hdd_is_suspend_notify_allowed(hdd_context_t* pHddCtx)
4619{
4620 tPmcState pmcState = pmcGetPmcState(pHddCtx->hHal);
4621 hdd_config_t *pConfig = pHddCtx->cfg_ini;
4622
4623 if (pConfig->fIsBmpsEnabled && (pmcState == BMPS))
4624 {
4625 return TRUE;
4626 }
4627 return FALSE;
4628}
4629
Jeff Johnson295189b2012-06-20 16:38:30 -07004630void wlan_hdd_set_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
4631{
4632 switch(mode)
4633 {
4634 case WLAN_HDD_INFRA_STATION:
4635#ifdef WLAN_FEATURE_P2P
4636 case WLAN_HDD_P2P_CLIENT:
4637 case WLAN_HDD_P2P_GO:
4638#endif
4639 case WLAN_HDD_SOFTAP:
Jeff Johnsone7245742012-09-05 17:12:55 -07004640 pHddCtx->concurrency_mode |= (1 << mode);
4641 pHddCtx->no_of_sessions[mode]++;
Jeff Johnson295189b2012-06-20 16:38:30 -07004642 break;
4643 default:
4644 break;
4645
4646 }
4647 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
4648 __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
4649}
4650
4651
4652void wlan_hdd_clear_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
4653{
4654 switch(mode)
4655 {
4656 case WLAN_HDD_INFRA_STATION:
4657#ifdef WLAN_FEATURE_P2P
4658 case WLAN_HDD_P2P_CLIENT:
4659 case WLAN_HDD_P2P_GO:
4660#endif
4661 case WLAN_HDD_SOFTAP:
4662 pHddCtx->no_of_sessions[mode]--;
4663 if (!(pHddCtx->no_of_sessions[mode]))
4664 pHddCtx->concurrency_mode &= (~(1 << mode));
4665 break;
4666 default:
4667 break;
4668 }
4669 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
4670 __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
4671}
4672
Jeff Johnsone7245742012-09-05 17:12:55 -07004673/**---------------------------------------------------------------------------
4674 *
4675 * \brief wlan_hdd_restart_init
4676 *
4677 * This function initalizes restart timer/flag. An internal function.
4678 *
4679 * \param - pHddCtx
4680 *
4681 * \return - None
4682 *
4683 * --------------------------------------------------------------------------*/
4684
4685static void wlan_hdd_restart_init(hdd_context_t *pHddCtx)
4686{
4687 /* Initialize */
4688 pHddCtx->hdd_restart_retries = 0;
4689 atomic_set(&pHddCtx->isRestartInProgress, 0);
4690 vos_timer_init(&pHddCtx->hdd_restart_timer,
4691 VOS_TIMER_TYPE_SW,
4692 wlan_hdd_restart_timer_cb,
4693 pHddCtx);
4694}
4695/**---------------------------------------------------------------------------
4696 *
4697 * \brief wlan_hdd_restart_deinit
4698 *
4699 * This function cleans up the resources used. An internal function.
4700 *
4701 * \param - pHddCtx
4702 *
4703 * \return - None
4704 *
4705 * --------------------------------------------------------------------------*/
4706
4707static void wlan_hdd_restart_deinit(hdd_context_t* pHddCtx)
4708{
4709
4710 VOS_STATUS vos_status;
4711 /* Block any further calls */
4712 atomic_set(&pHddCtx->isRestartInProgress, 1);
4713 /* Cleanup */
4714 vos_status = vos_timer_stop( &pHddCtx->hdd_restart_timer );
4715 if (!VOS_IS_STATUS_SUCCESS(vos_status))
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004716 hddLog(LOGW, FL("Failed to stop HDD restart timer"));
Jeff Johnsone7245742012-09-05 17:12:55 -07004717 vos_status = vos_timer_destroy(&pHddCtx->hdd_restart_timer);
4718 if (!VOS_IS_STATUS_SUCCESS(vos_status))
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004719 hddLog(LOGW, FL("Failed to destroy HDD restart timer"));
Jeff Johnsone7245742012-09-05 17:12:55 -07004720
4721}
4722
4723/**---------------------------------------------------------------------------
4724 *
4725 * \brief wlan_hdd_framework_restart
4726 *
4727 * This function uses a cfg80211 API to start a framework initiated WLAN
4728 * driver module unload/load.
4729 *
4730 * Also this API keep retrying (WLAN_HDD_RESTART_RETRY_MAX_CNT).
4731 *
4732 *
4733 * \param - pHddCtx
4734 *
4735 * \return - VOS_STATUS_SUCCESS: Success
4736 * VOS_STATUS_E_EMPTY: Adapter is Empty
4737 * VOS_STATUS_E_NOMEM: No memory
4738
4739 * --------------------------------------------------------------------------*/
4740
4741static VOS_STATUS wlan_hdd_framework_restart(hdd_context_t *pHddCtx)
4742{
4743 VOS_STATUS status = VOS_STATUS_SUCCESS;
4744 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
4745 int len = (sizeof (struct ieee80211_mgmt));
4746 struct ieee80211_mgmt *mgmt = NULL;
4747
4748 /* Prepare the DEAUTH managment frame with reason code */
4749 mgmt = kzalloc(len, GFP_KERNEL);
4750 if(mgmt == NULL)
4751 {
4752 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
Jeff Johnson1250df42012-12-10 14:31:52 -08004753 "%s: memory allocation failed (%d bytes)", __func__, len);
Jeff Johnsone7245742012-09-05 17:12:55 -07004754 return VOS_STATUS_E_NOMEM;
4755 }
4756 mgmt->u.deauth.reason_code = WLAN_REASON_DISASSOC_LOW_ACK;
4757
4758 /* Iterate over all adapters/devices */
4759 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
4760 do
4761 {
4762 if( (status == VOS_STATUS_SUCCESS) &&
4763 pAdapterNode &&
4764 pAdapterNode->pAdapter)
4765 {
4766 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
4767 "restarting the driver(intf:\'%s\' mode:%d :try %d)",
4768 pAdapterNode->pAdapter->dev->name,
4769 pAdapterNode->pAdapter->device_mode,
4770 pHddCtx->hdd_restart_retries + 1);
4771 /*
4772 * CFG80211 event to restart the driver
4773 *
4774 * 'cfg80211_send_unprot_deauth' sends a
4775 * NL80211_CMD_UNPROT_DEAUTHENTICATE event to supplicant at any state
4776 * of SME(Linux Kernel) state machine.
4777 *
4778 * Reason code WLAN_REASON_DISASSOC_LOW_ACK is currently used to restart
4779 * the driver.
4780 *
4781 */
4782
4783 cfg80211_send_unprot_deauth(pAdapterNode->pAdapter->dev, (u_int8_t*)mgmt, len );
4784 }
4785 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
4786 pAdapterNode = pNext;
4787 } while((NULL != pAdapterNode) && (VOS_STATUS_SUCCESS == status));
4788
4789
4790 /* Free the allocated management frame */
4791 kfree(mgmt);
4792
4793 /* Retry until we unload or reach max count */
4794 if(++pHddCtx->hdd_restart_retries < WLAN_HDD_RESTART_RETRY_MAX_CNT)
4795 vos_timer_start(&pHddCtx->hdd_restart_timer, WLAN_HDD_RESTART_RETRY_DELAY_MS);
4796
4797 return status;
4798
4799}
4800/**---------------------------------------------------------------------------
4801 *
4802 * \brief wlan_hdd_restart_timer_cb
4803 *
4804 * Restart timer callback. An internal function.
4805 *
4806 * \param - User data:
4807 *
4808 * \return - None
4809 *
4810 * --------------------------------------------------------------------------*/
4811
4812void wlan_hdd_restart_timer_cb(v_PVOID_t usrDataForCallback)
4813{
4814 hdd_context_t *pHddCtx = usrDataForCallback;
4815 wlan_hdd_framework_restart(pHddCtx);
4816 return;
4817
4818}
4819
4820
4821/**---------------------------------------------------------------------------
4822 *
4823 * \brief wlan_hdd_restart_driver
4824 *
4825 * This function sends an event to supplicant to restart the WLAN driver.
4826 *
4827 * This function is called from vos_wlanRestart.
4828 *
4829 * \param - pHddCtx
4830 *
4831 * \return - VOS_STATUS_SUCCESS: Success
4832 * VOS_STATUS_E_EMPTY: Adapter is Empty
4833 * VOS_STATUS_E_ALREADY: Request already in progress
4834
4835 * --------------------------------------------------------------------------*/
4836VOS_STATUS wlan_hdd_restart_driver(hdd_context_t *pHddCtx)
4837{
4838 VOS_STATUS status = VOS_STATUS_SUCCESS;
4839
4840 /* A tight check to make sure reentrancy */
4841 if(atomic_xchg(&pHddCtx->isRestartInProgress, 1))
4842 {
4843 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
4844 "%s: WLAN restart is already in progress", __func__);
4845
4846 return VOS_STATUS_E_ALREADY;
4847 }
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07004848 /* when WLAN driver is statically linked, then invoke SSR by sending
Madan Mohan Koyyalamudibb8f0172012-09-28 15:36:06 -07004849 * the reset interrupt. If it is DLKM, then use restart API
4850 */
4851#ifdef MODULE
Jeff Johnsone7245742012-09-05 17:12:55 -07004852 status = wlan_hdd_framework_restart(pHddCtx);
Madan Mohan Koyyalamudibb8f0172012-09-28 15:36:06 -07004853#else
Madan Mohan Koyyalamudie388b342012-11-08 15:03:16 -08004854#ifdef HAVE_WCNSS_RESET_INTR
Madan Mohan Koyyalamudibb8f0172012-09-28 15:36:06 -07004855 wcnss_reset_intr();
4856#endif
Madan Mohan Koyyalamudie388b342012-11-08 15:03:16 -08004857#endif
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07004858
Jeff Johnsone7245742012-09-05 17:12:55 -07004859 return status;
4860}
4861
4862
Jeff Johnson295189b2012-06-20 16:38:30 -07004863//Register the module init/exit functions
4864module_init(hdd_module_init);
4865module_exit(hdd_module_exit);
4866
4867MODULE_LICENSE("Dual BSD/GPL");
4868MODULE_AUTHOR("Qualcomm Atheros, Inc.");
4869MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER");
4870
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004871module_param_call(con_mode, con_mode_handler, param_get_int, &con_mode,
4872 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Jeff Johnson32d95a32012-09-10 13:15:23 -07004873
4874module_param_call(fwpath, fwpath_changed_handler, param_get_string, fwpath,
4875 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);