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