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