blob: 563f85f328f912296cd6c5f57929a65da9caeabd [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
3166/**---------------------------------------------------------------------------
3167
3168 \brief hdd_wlan_startup() - HDD init function
3169
3170 This is the driver startup code executed once a WLAN device has been detected
3171
3172 \param - dev - Pointer to the underlying device
3173
3174 \return - 0 for success -1 for failure
3175
3176 --------------------------------------------------------------------------*/
3177
3178int hdd_wlan_startup(struct device *dev )
3179{
3180 VOS_STATUS status;
3181 hdd_adapter_t *pAdapter = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -07003182 hdd_adapter_t *pP2pAdapter = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07003183 hdd_context_t *pHddCtx = NULL;
3184 v_CONTEXT_t pVosContext= NULL;
3185#ifdef WLAN_BTAMP_FEATURE
3186 VOS_STATUS vStatus = VOS_STATUS_SUCCESS;
3187 WLANBAP_ConfigType btAmpConfig;
3188 hdd_config_t *pConfig;
3189#endif
3190 int ret;
3191#ifdef CONFIG_CFG80211
3192 struct wiphy *wiphy;
3193#endif
3194#ifdef ANI_BUS_TYPE_SDIO
3195 struct sdio_func *sdio_func_dev = dev_to_sdio_func(dev);
3196#endif //ANI_BUS_TYPE_SDIO
3197
3198 ENTER();
3199#ifdef CONFIG_CFG80211
3200 /*
3201 * cfg80211: wiphy allocation
3202 */
3203 wiphy = wlan_hdd_cfg80211_init(sizeof(hdd_context_t)) ;
3204
3205 if(wiphy == NULL)
3206 {
3207 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
3208 return -1;
3209 }
3210
3211 pHddCtx = wiphy_priv(wiphy);
3212
3213#else
3214
3215 pHddCtx = vos_mem_malloc ( sizeof( hdd_context_t ) );
3216 if(pHddCtx == NULL)
3217 {
3218 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
3219 return -1;
3220 }
3221
3222#endif
3223 //Initialize the adapter context to zeros.
3224 vos_mem_zero(pHddCtx, sizeof( hdd_context_t ));
3225
3226#ifdef CONFIG_CFG80211
3227 pHddCtx->wiphy = wiphy;
3228#endif
3229 hdd_prevent_suspend();
3230 pHddCtx->isLoadUnloadInProgress = TRUE;
3231
3232 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE);
3233
3234 /*Get vos context here bcoz vos_open requires it*/
3235 pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
3236
3237 //Save the Global VOSS context in adapter context for future.
3238 pHddCtx->pvosContext = pVosContext;
3239
3240 //Save the adapter context in global context for future.
3241 ((VosContextType*)(pVosContext))->pHDDContext = (v_VOID_t*)pHddCtx;
3242
3243#ifdef ANI_BUS_TYPE_SDIO
3244 // Set the private data for the device to our adapter.
3245 libra_sdio_setprivdata (sdio_func_dev, pHddCtx);
3246 atomic_set(&pHddCtx->sdio_claim_count, 0);
3247#endif // ANI_BUS_TYPE_SDIO
3248
3249 pHddCtx->parent_dev = dev;
3250
3251 init_completion(&pHddCtx->full_pwr_comp_var);
3252 init_completion(&pHddCtx->standby_comp_var);
3253 init_completion(&pHddCtx->req_bmps_comp_var);
3254
3255
3256 hdd_list_init( &pHddCtx->hddAdapters, MAX_NUMBER_OF_ADAPTERS );
3257
3258 // Load all config first as TL config is needed during vos_open
3259 pHddCtx->cfg_ini = (hdd_config_t*) kmalloc(sizeof(hdd_config_t), GFP_KERNEL);
3260 if(pHddCtx->cfg_ini == NULL)
3261 {
3262 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed kmalloc hdd_config_t",__func__);
3263 goto err_free_hdd_context;
3264 }
3265
3266 vos_mem_zero(pHddCtx->cfg_ini, sizeof( hdd_config_t ));
3267
3268 // Read and parse the qcom_cfg.ini file
3269 status = hdd_parse_config_ini( pHddCtx );
3270 if ( VOS_STATUS_SUCCESS != status )
3271 {
3272 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: error parsing %s",
3273 __func__, WLAN_INI_FILE);
3274 goto err_config;
3275 }
3276
3277#ifdef CONFIG_CFG80211
3278 /*
3279 * cfg80211: Initialization and registration ...
3280 */
3281 if (0 < wlan_hdd_cfg80211_register(dev, wiphy, pHddCtx->cfg_ini))
3282 {
3283 hddLog(VOS_TRACE_LEVEL_FATAL,
3284 "%s: wlan_hdd_cfg80211_register return failure", __func__);
3285 goto err_wiphy_reg;
3286 }
3287#endif
3288
3289#ifdef FEATURE_WLAN_INTEGRATED_SOC
3290 // Update WDI trace levels based upon the cfg.ini
3291 hdd_wdi_trace_enable(eWLAN_MODULE_DAL,
3292 pHddCtx->cfg_ini->wdiTraceEnableDAL);
3293 hdd_wdi_trace_enable(eWLAN_MODULE_DAL_CTRL,
3294 pHddCtx->cfg_ini->wdiTraceEnableCTL);
3295 hdd_wdi_trace_enable(eWLAN_MODULE_DAL_DATA,
3296 pHddCtx->cfg_ini->wdiTraceEnableDAT);
3297 hdd_wdi_trace_enable(eWLAN_MODULE_PAL,
3298 pHddCtx->cfg_ini->wdiTraceEnablePAL);
3299#endif /* FEATURE_WLAN_INTEGRATED_SOC */
3300
3301#ifdef ANI_MANF_DIAG
3302 if(VOS_FTM_MODE == hdd_get_conparam())
3303 {
3304 if ( VOS_STATUS_SUCCESS != wlan_hdd_ftm_open(pHddCtx) )
3305 {
3306 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: wlan_hdd_ftm_open Failed",__func__);
3307 goto err_free_hdd_context;
3308 }
3309 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: FTM driver loaded success fully",__func__);
3310 return VOS_STATUS_SUCCESS;
3311 }
3312#endif
3313
3314 //Open watchdog module
3315 if(pHddCtx->cfg_ini->fIsLogpEnabled)
3316 {
3317 status = vos_watchdog_open(pVosContext,
3318 &((VosContextType*)pVosContext)->vosWatchdog, sizeof(VosWatchdogContext));
3319
3320 if(!VOS_IS_STATUS_SUCCESS( status ))
3321 {
3322 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_watchdog_open failed",__func__);
3323#ifdef CONFIG_CFG80211
3324 goto err_wiphy_reg;
3325#else
3326 goto err_config;
3327#endif
3328 }
3329 }
3330
3331 pHddCtx->isLogpInProgress = FALSE;
3332 vos_set_logp_in_progress(VOS_MODULE_ID_VOSS, FALSE);
3333
3334#ifdef ANI_BUS_TYPE_SDIO
3335 status = WLANBAL_Open(pHddCtx->pvosContext);
3336 if(!VOS_IS_STATUS_SUCCESS(status))
3337 {
3338 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3339 "%s: Failed to open BAL",__func__);
3340 goto err_wdclose;
3341 }
3342#endif // ANI_BUS_TYPE_SDIO
3343
3344 status = vos_chipVoteOnXOBuffer(NULL, NULL, NULL);
3345 if(!VOS_IS_STATUS_SUCCESS(status))
3346 {
3347 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Failed to configure 19.2 MHz Clock", __func__);
3348#ifdef ANI_BUS_TYPE_SDIO
3349 goto err_balclose;
3350#else
3351 goto err_wdclose;
3352#endif
3353 }
3354
3355
3356#ifdef ANI_BUS_TYPE_SDIO
3357 status = WLANSAL_Start(pHddCtx->pvosContext);
3358 if (!VOS_IS_STATUS_SUCCESS(status))
3359 {
3360 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Failed to start SAL",__func__);
3361 goto err_clkvote;
3362 }
3363
3364 /* Start BAL */
3365 status = WLANBAL_Start(pHddCtx->pvosContext);
3366
3367 if (!VOS_IS_STATUS_SUCCESS(status))
3368 {
3369 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3370 "%s: Failed to start BAL",__func__);
3371 goto err_salstop;
3372 }
3373#endif // ANI_BUS_TYPE_SDIO
3374
3375#ifdef MSM_PLATFORM_7x30
3376 /* FIXME: Volans 2.0 configuration. Reconfigure 1.3v SW supply to 1.3v. It will be configured to
3377 * 1.4v in vos_ChipPowerup() routine above
3378 */
3379#endif
3380
3381 status = vos_open( &pVosContext, 0);
3382 if ( !VOS_IS_STATUS_SUCCESS( status ))
3383 {
3384 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_open failed",__func__);
3385 goto err_balstop;
3386 }
3387
3388 /* Save the hal context in Adapter */
3389 pHddCtx->hHal = (tHalHandle)vos_get_context( VOS_MODULE_ID_SME, pVosContext );
3390
3391 if ( NULL == pHddCtx->hHal )
3392 {
3393 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: HAL context is null",__func__);
3394 goto err_vosclose;
3395 }
3396
Jeff Johnsone7245742012-09-05 17:12:55 -07003397#ifdef FEATURE_WLAN_INTEGRATED_SOC
3398 /* Vos preStart is calling */
3399 /* vos preStart which does cfg download should be called before set sme config which accesses/sets some cfgs */
3400 status = vos_preStart( pHddCtx->pvosContext );
3401 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3402 {
3403 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_preStart failed",__func__);
3404 goto err_vosclose;
3405 }
3406#endif
3407
Jeff Johnson295189b2012-06-20 16:38:30 -07003408 // Set the SME configuration parameters...
3409 status = hdd_set_sme_config( pHddCtx );
3410
3411 if ( VOS_STATUS_SUCCESS != status )
3412 {
3413 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed hdd_set_sme_config",__func__);
3414 goto err_vosclose;
3415 }
3416
3417 //Initialize the WMM module
3418 status = hdd_wmm_init(pHddCtx);
3419 if (!VOS_IS_STATUS_SUCCESS(status))
3420 {
3421 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: hdd_wmm_init failed", __FUNCTION__);
3422 goto err_vosclose;
3423 }
3424
3425#ifdef FEATURE_WLAN_INTEGRATED_SOC
Jeff Johnson295189b2012-06-20 16:38:30 -07003426 /* In the integrated architecture we update the configuration from
3427 the INI file and from NV before vOSS has been started so that
3428 the final contents are available to send down to the cCPU */
3429
3430 // Apply the cfg.ini to cfg.dat
3431 if (FALSE == hdd_update_config_dat(pHddCtx))
3432 {
3433 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: config update failed",__func__ );
3434 goto err_vosclose;
3435 }
3436
3437 // Apply the NV to cfg.dat
3438 /* Prima Update MAC address only at here */
3439 if (VOS_STATUS_SUCCESS != hdd_update_config_from_nv(pHddCtx))
3440 {
3441#ifdef WLAN_AUTOGEN_MACADDR_FEATURE
3442 /* There was not a valid set of MAC Addresses in NV. See if the
3443 default addresses were modified by the cfg.ini settings. If so,
3444 we'll use them, but if not, we'll autogenerate a set of MAC
3445 addresses based upon the device serial number */
3446
3447 static const v_MACADDR_t default_address =
3448 {{0x00, 0x0A, 0xF5, 0x89, 0x89, 0xFF}};
3449 unsigned int serialno;
3450 int i;
3451
3452 serialno = wcnss_get_serial_number();
3453 if ((0 != serialno) &&
3454 (0 == memcmp(&default_address, &pHddCtx->cfg_ini->intfMacAddr[0],
3455 sizeof(default_address))))
3456 {
3457 /* cfg.ini has the default address, invoke autogen logic */
3458
3459 /* MAC address has 3 bytes of OUI so we have a maximum of 3
3460 bytes of the serial number that can be used to generate
3461 the other 3 bytes of the MAC address. Mask off all but
3462 the lower 3 bytes (this will also make sure we don't
3463 overflow in the next step) */
3464 serialno &= 0x00FFFFFF;
3465
3466 /* we need a unique address for each session */
3467 serialno *= VOS_MAX_CONCURRENCY_PERSONA;
3468
3469 /* autogen all addresses */
3470 for (i = 0; i < VOS_MAX_CONCURRENCY_PERSONA; i++)
3471 {
3472 /* start with the entire default address */
3473 pHddCtx->cfg_ini->intfMacAddr[i] = default_address;
3474 /* then replace the lower 3 bytes */
3475 pHddCtx->cfg_ini->intfMacAddr[i].bytes[3] = (serialno >> 16) & 0xFF;
3476 pHddCtx->cfg_ini->intfMacAddr[i].bytes[4] = (serialno >> 8) & 0xFF;
3477 pHddCtx->cfg_ini->intfMacAddr[i].bytes[5] = serialno & 0xFF;
3478
3479 serialno++;
3480 }
3481
3482 pr_info("wlan: Invalid MAC addresses in NV, autogenerated "
3483 MAC_ADDRESS_STR,
3484 MAC_ADDR_ARRAY(pHddCtx->cfg_ini->intfMacAddr[0].bytes));
3485 }
3486 else
3487#endif //WLAN_AUTOGEN_MACADDR_FEATURE
3488 {
3489 hddLog(VOS_TRACE_LEVEL_ERROR,
3490 "%s: Invalid MAC address in NV, using MAC from ini file "
3491 MAC_ADDRESS_STR, __func__,
3492 MAC_ADDR_ARRAY(pHddCtx->cfg_ini->intfMacAddr[0].bytes));
3493 }
3494 }
3495 {
3496 eHalStatus halStatus;
3497 // Set the MAC Address
3498 // Currently this is used by HAL to add self sta. Remove this once self sta is added as part of session open.
3499 halStatus = cfgSetStr( pHddCtx->hHal, WNI_CFG_STA_ID,
3500 (v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[0],
3501 sizeof( pHddCtx->cfg_ini->intfMacAddr[0]) );
3502
3503 if (!HAL_STATUS_SUCCESS( halStatus ))
3504 {
3505 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed to set MAC Address. "
3506 "HALStatus is %08d [x%08x]",__func__, halStatus, halStatus );
3507 return VOS_STATUS_E_FAILURE;
3508 }
3509 }
3510#endif // FEATURE_WLAN_INTEGRATED_SOC
3511
3512 /*Start VOSS which starts up the SME/MAC/HAL modules and everything else
3513 Note: Firmware image will be read and downloaded inside vos_start API */
3514 status = vos_start( pHddCtx->pvosContext );
3515 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3516 {
3517 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_start failed",__func__);
3518 goto err_vosclose;
3519 }
3520
3521#ifdef FEATURE_WLAN_INTEGRATED_SOC
3522 /* retrieve and display WCNSS version information */
3523 do {
3524 tSirVersionType versionCompiled;
3525 tSirVersionType versionReported;
3526 tSirVersionString versionString;
3527 tANI_U8 fwFeatCapsMsgSupported = 0;
3528 VOS_STATUS vstatus;
3529
3530 vstatus = sme_GetWcnssWlanCompiledVersion(pHddCtx->hHal,
3531 &versionCompiled);
3532 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3533 {
3534 hddLog(VOS_TRACE_LEVEL_FATAL,
3535 "%s: unable to retrieve WCNSS WLAN compiled version",
3536 __FUNCTION__);
3537 break;
3538 }
3539
3540 vstatus = sme_GetWcnssWlanReportedVersion(pHddCtx->hHal,
3541 &versionReported);
3542 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3543 {
3544 hddLog(VOS_TRACE_LEVEL_FATAL,
3545 "%s: unable to retrieve WCNSS WLAN reported version",
3546 __FUNCTION__);
3547 break;
3548 }
3549
3550 if ((versionCompiled.major != versionReported.major) ||
3551 (versionCompiled.minor != versionReported.minor) ||
3552 (versionCompiled.version != versionReported.version) ||
3553 (versionCompiled.revision != versionReported.revision))
3554 {
Jeff Johnson04dd8a82012-06-29 20:41:40 -07003555 pr_err("%s: WCNSS WLAN Version %u.%u.%u.%u, "
Jeff Johnson295189b2012-06-20 16:38:30 -07003556 "Host expected %u.%u.%u.%u\n",
3557 WLAN_MODULE_NAME,
3558 (int)versionReported.major,
3559 (int)versionReported.minor,
3560 (int)versionReported.version,
3561 (int)versionReported.revision,
3562 (int)versionCompiled.major,
3563 (int)versionCompiled.minor,
3564 (int)versionCompiled.version,
3565 (int)versionCompiled.revision);
3566 }
3567 else
3568 {
3569 pr_info("%s: WCNSS WLAN version %u.%u.%u.%u\n",
3570 WLAN_MODULE_NAME,
3571 (int)versionReported.major,
3572 (int)versionReported.minor,
3573 (int)versionReported.version,
3574 (int)versionReported.revision);
3575 }
3576
3577 vstatus = sme_GetWcnssSoftwareVersion(pHddCtx->hHal,
3578 versionString,
3579 sizeof(versionString));
3580 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3581 {
3582 hddLog(VOS_TRACE_LEVEL_FATAL,
3583 "%s: unable to retrieve WCNSS software version string",
3584 __FUNCTION__);
3585 break;
3586 }
3587
3588 pr_info("%s: WCNSS software version %s\n",
3589 WLAN_MODULE_NAME, versionString);
3590
3591 vstatus = sme_GetWcnssHardwareVersion(pHddCtx->hHal,
3592 versionString,
3593 sizeof(versionString));
3594 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3595 {
3596 hddLog(VOS_TRACE_LEVEL_FATAL,
3597 "%s: unable to retrieve WCNSS hardware version string",
3598 __FUNCTION__);
3599 break;
3600 }
3601
3602 pr_info("%s: WCNSS hardware version %s\n",
3603 WLAN_MODULE_NAME, versionString);
3604
Jeff Johnsone7245742012-09-05 17:12:55 -07003605 /* 1.Check if FW version is greater than 0.1.1.0. Only then send host-FW capability exchange message
3606 2.Host-FW capability exchange message is only present on riva 1.1 so
3607 send the message only if it the riva is 1.1
3608 minor numbers for different riva branches:
3609 0 -> (1.0)Mainline Build
3610 1 -> (1.1)Mainline Build
3611 2->(1.04) Stability Build
3612 */
3613 if (((versionReported.major>0) || (versionReported.minor>1) ||
3614 ((versionReported.minor>=1) && (versionReported.version>=1)))
3615 && ((versionReported.major == 1) && (versionReported.minor >= 1)))
Jeff Johnson295189b2012-06-20 16:38:30 -07003616 fwFeatCapsMsgSupported = 1;
3617 if (fwFeatCapsMsgSupported)
Jeff Johnsone7245742012-09-05 17:12:55 -07003618 sme_featureCapsExchange(pHddCtx->hHal);
Jeff Johnson295189b2012-06-20 16:38:30 -07003619 } while (0);
3620
3621#endif // FEATURE_WLAN_INTEGRATED_SOC
3622
3623 status = hdd_post_voss_start_config( pHddCtx );
3624 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3625 {
3626 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hdd_post_voss_start_config failed",
3627 __func__);
3628 goto err_vosstop;
3629 }
3630
3631#ifdef WLAN_SOFTAP_FEATURE
3632 if (VOS_STA_SAP_MODE == hdd_get_conparam())
3633 {
3634 pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_SOFTAP, "softap.%d",
3635 wlan_hdd_get_intf_addr(pHddCtx), FALSE );
3636 }
3637 else
3638 {
3639#endif
3640 pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_INFRA_STATION, "wlan%d",
3641 wlan_hdd_get_intf_addr(pHddCtx), FALSE );
3642 if (pAdapter != NULL)
3643 {
3644#ifdef WLAN_FEATURE_P2P
Jeff Johnson295189b2012-06-20 16:38:30 -07003645 if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
3646 {
Jeff Johnsone7245742012-09-05 17:12:55 -07003647 vos_mem_copy( pHddCtx->p2pDeviceAddress.bytes,
3648 pHddCtx->cfg_ini->intfMacAddr[0].bytes,
3649 sizeof(tSirMacAddr));
Jeff Johnson295189b2012-06-20 16:38:30 -07003650 /* Generate the P2P Device Address. This consists of the device's
3651 * primary MAC address with the locally administered bit set.
3652 */
3653 pHddCtx->p2pDeviceAddress.bytes[0] |= 0x02;
Jeff Johnsone7245742012-09-05 17:12:55 -07003654 }
3655 else
3656 {
3657 tANI_U8* p2p_dev_addr = wlan_hdd_get_intf_addr(pHddCtx);
3658 if (p2p_dev_addr != NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -07003659 {
Jeff Johnsone7245742012-09-05 17:12:55 -07003660 vos_mem_copy(&pHddCtx->p2pDeviceAddress.bytes[0],
3661 p2p_dev_addr, VOS_MAC_ADDR_SIZE);
3662 }
3663 else
3664 {
3665 hddLog(VOS_TRACE_LEVEL_FATAL,
3666 "%s: Failed to allocate mac_address for p2p_device",
3667 __FUNCTION__);
3668 goto err_close_adapter;
Jeff Johnson295189b2012-06-20 16:38:30 -07003669 }
3670 }
Jeff Johnsone7245742012-09-05 17:12:55 -07003671
3672 pP2pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_P2P_DEVICE, "p2p%d",
3673 &pHddCtx->p2pDeviceAddress.bytes[0], FALSE );
3674 if ( NULL == pP2pAdapter )
3675 {
3676 hddLog(VOS_TRACE_LEVEL_FATAL,
3677 "%s: Failed to do hdd_open_adapter for P2P Device Interface",
3678 __FUNCTION__);
3679 goto err_close_adapter;
3680 }
Jeff Johnson295189b2012-06-20 16:38:30 -07003681#endif
Jeff Johnsone7245742012-09-05 17:12:55 -07003682 }
Jeff Johnson295189b2012-06-20 16:38:30 -07003683#ifdef WLAN_SOFTAP_FEATURE
3684 }
3685#endif
3686
3687 if( pAdapter == NULL )
3688 {
3689 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
3690#ifdef ANI_BUS_TYPE_SDIO
3691 goto err_balstop;
3692#else
3693 goto err_clkvote;
3694#endif
3695 }
Jeff Johnsone7245742012-09-05 17:12:55 -07003696
Jeff Johnson295189b2012-06-20 16:38:30 -07003697#ifdef WLAN_BTAMP_FEATURE
3698 vStatus = WLANBAP_Open(pVosContext);
3699 if(!VOS_IS_STATUS_SUCCESS(vStatus))
3700 {
3701 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3702 "%s: Failed to open BAP",__func__);
Jeff Johnsone7245742012-09-05 17:12:55 -07003703 goto err_close_adapter;
Jeff Johnson295189b2012-06-20 16:38:30 -07003704 }
3705
3706 vStatus = BSL_Init(pVosContext);
3707 if(!VOS_IS_STATUS_SUCCESS(vStatus))
3708 {
3709 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3710 "%s: Failed to Init BSL",__func__);
3711 goto err_bap_close;
3712 }
3713 vStatus = WLANBAP_Start(pVosContext);
3714 if (!VOS_IS_STATUS_SUCCESS(vStatus))
3715 {
3716 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3717 "%s: Failed to start TL",__func__);
3718 goto err_bap_close;
3719 }
3720
3721 pConfig = pHddCtx->cfg_ini;
3722 btAmpConfig.ucPreferredChannel = pConfig->preferredChannel;
3723 status = WLANBAP_SetConfig(&btAmpConfig);
3724
3725#endif //WLAN_BTAMP_FEATURE
Jeff Johnsone7245742012-09-05 17:12:55 -07003726
Jeff Johnson295189b2012-06-20 16:38:30 -07003727#ifdef FEATURE_WLAN_SCAN_PNO
3728 /*SME must send channel update configuration to RIVA*/
3729 sme_UpdateChannelConfig(pHddCtx->hHal);
3730#endif
3731
3732#ifdef FEATURE_WLAN_INTEGRATED_SOC
3733 /* Register with platform driver as client for Suspend/Resume */
3734 status = hddRegisterPmOps(pHddCtx);
3735 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3736 {
3737 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddRegisterPmOps failed",__func__);
3738#ifdef WLAN_BTAMP_FEATURE
3739 goto err_bap_stop;
3740#else
Jeff Johnsone7245742012-09-05 17:12:55 -07003741 goto err_close_adapter;
Jeff Johnson295189b2012-06-20 16:38:30 -07003742#endif //WLAN_BTAMP_FEATURE
3743 }
3744
3745 /* Register TM level change handler function to the platform */
3746 status = hddDevTmRegisterNotifyCallback(pHddCtx);
3747 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3748 {
3749 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDevTmRegisterNotifyCallback failed",__func__);
3750 goto err_unregister_pmops;
3751 }
3752#endif
3753
3754 /* register for riva power on lock to platform driver */
3755 if (req_riva_power_on_lock("wlan"))
3756 {
3757 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: req riva power on lock failed",
3758 __func__);
3759 goto err_unregister_pmops;
3760 }
3761
3762#ifdef CONFIG_HAS_EARLYSUSPEND
3763 // Register suspend/resume callbacks
3764 if(pHddCtx->cfg_ini->nEnableSuspend)
3765 {
3766 register_wlan_suspend();
3767 }
3768#endif
3769
3770 // register net device notifier for device change notification
3771 ret = register_netdevice_notifier(&hdd_netdev_notifier);
3772
3773 if(ret < 0)
3774 {
3775 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: register_netdevice_notifier failed",__func__);
3776 goto err_free_power_on_lock;
3777 }
3778
3779 //Initialize the nlink service
3780 if(nl_srv_init() != 0)
3781 {
3782 hddLog(VOS_TRACE_LEVEL_FATAL,"%S: nl_srv_init failed",__func__);
3783 goto err_reg_netdev;
3784 }
3785
3786 //Initialize the BTC service
3787 if(btc_activate_service(pHddCtx) != 0)
3788 {
3789 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: btc_activate_service failed",__func__);
3790 goto err_nl_srv;
3791 }
3792
3793#ifdef PTT_SOCK_SVC_ENABLE
3794 //Initialize the PTT service
3795 if(ptt_sock_activate_svc(pHddCtx) != 0)
3796 {
3797 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: ptt_sock_activate_svc failed",__func__);
3798 goto err_nl_srv;
3799 }
3800#endif
3801
3802 //Initialize the WoWL service
3803 if(!hdd_init_wowl(pHddCtx))
3804 {
3805 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hdd_init_wowl failed",__func__);
3806 goto err_nl_srv;
3807 }
3808
3809#ifdef CONFIG_HAS_EARLYSUSPEND
3810 hdd_register_mcast_bcast_filter(pHddCtx);
3811#endif
3812#ifdef CONFIG_CFG80211
3813#ifdef WLAN_SOFTAP_FEATURE
3814 if (VOS_STA_SAP_MODE != hdd_get_conparam())
3815#endif
3816 {
Jeff Johnsone7245742012-09-05 17:12:55 -07003817 wlan_hdd_cfg80211_post_voss_start(pP2pAdapter);
Madan Mohan Koyyalamudie233e292012-09-18 17:38:02 -07003818 wlan_hdd_cfg80211_post_voss_start(pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -07003819 }
3820#endif
3821
3822 mutex_init(&pHddCtx->sap_lock);
3823
3824 pHddCtx->isLoadUnloadInProgress = FALSE;
3825
Jeff Johnsone7245742012-09-05 17:12:55 -07003826#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
3827 /* Initialize the wake lcok */
3828 wake_lock_init(&pHddCtx->rx_wake_lock,
3829 WAKE_LOCK_SUSPEND,
3830 "qcom_rx_wakelock");
3831#endif
3832
Jeff Johnson295189b2012-06-20 16:38:30 -07003833 vos_event_init(&pAdapter->scan_info.scan_finished_event);
3834 pAdapter->scan_info.scan_pending_option = WEXT_SCAN_PENDING_GIVEUP;
3835
3836 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, FALSE);
3837 hdd_allow_suspend();
Jeff Johnsone7245742012-09-05 17:12:55 -07003838
3839 // Initialize the restart logic
3840 wlan_hdd_restart_init(pHddCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -07003841
3842 goto success;
3843
3844err_nl_srv:
3845 nl_srv_exit();
3846
3847err_reg_netdev:
3848 unregister_netdevice_notifier(&hdd_netdev_notifier);
3849
3850err_free_power_on_lock:
3851 free_riva_power_on_lock("wlan");
3852
3853err_unregister_pmops:
3854 hddDevTmUnregisterNotifyCallback(pHddCtx);
3855 hddDeregisterPmOps(pHddCtx);
3856
3857#ifdef WLAN_BTAMP_FEATURE
3858err_bap_stop:
3859 WLANBAP_Stop(pVosContext);
3860#endif
3861
3862#ifdef WLAN_BTAMP_FEATURE
3863err_bap_close:
3864 WLANBAP_Close(pVosContext);
3865#endif
3866
Jeff Johnson295189b2012-06-20 16:38:30 -07003867err_close_adapter:
3868 hdd_close_all_adapters( pHddCtx );
3869
3870err_vosstop:
3871 vos_stop(pVosContext);
3872
3873err_vosclose:
3874 status = vos_sched_close( pVosContext );
3875 if (!VOS_IS_STATUS_SUCCESS(status)) {
3876 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
3877 "%s: Failed to close VOSS Scheduler", __func__);
3878 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status ) );
3879 }
3880 vos_close(pVosContext );
3881
3882err_balstop:
3883#ifdef ANI_BUS_TYPE_SDIO
3884#ifndef ANI_MANF_DIAG
3885 wlan_hdd_enable_deepsleep(pHddCtx->pvosContext);
3886#endif
3887
3888 WLANBAL_Stop(pHddCtx->pvosContext);
3889 WLANBAL_SuspendChip(pHddCtx->pvosContext);
3890#endif
3891
3892#ifdef ANI_BUS_TYPE_SDIO
3893err_salstop:
3894 WLANSAL_Stop(pHddCtx->pvosContext);
3895
3896#endif
3897err_clkvote:
3898 vos_chipVoteOffXOBuffer(NULL, NULL, NULL);
3899
3900#ifdef ANI_BUS_TYPE_SDIO
3901err_balclose:
3902 WLANBAL_Close(pHddCtx->pvosContext);
3903#endif // ANI_BUS_TYPE_SDIO
3904
3905err_wdclose:
3906 if(pHddCtx->cfg_ini->fIsLogpEnabled)
3907 vos_watchdog_close(pVosContext);
3908
3909#ifdef CONFIG_CFG80211
3910err_wiphy_reg:
3911 wiphy_unregister(wiphy) ;
3912#endif
3913
3914err_config:
3915 kfree(pHddCtx->cfg_ini);
3916 pHddCtx->cfg_ini= NULL;
3917
3918err_free_hdd_context:
3919 hdd_allow_suspend();
3920#ifdef CONFIG_CFG80211
3921 wiphy_free(wiphy) ;
3922 //kfree(wdev) ;
3923#else
3924 vos_mem_free( pHddCtx );
3925#endif
3926 VOS_BUG(1);
3927
3928 return -1;
3929
3930success:
3931 EXIT();
3932 return 0;
3933}
3934
3935/**---------------------------------------------------------------------------
3936
Jeff Johnson32d95a32012-09-10 13:15:23 -07003937 \brief hdd_driver_init() - Core Driver Init Function
Jeff Johnson295189b2012-06-20 16:38:30 -07003938
Jeff Johnson32d95a32012-09-10 13:15:23 -07003939 This is the driver entry point - called in different timeline depending
3940 on whether the driver is statically or dynamically linked
Jeff Johnson295189b2012-06-20 16:38:30 -07003941
3942 \param - None
3943
3944 \return - 0 for success, non zero for failure
3945
3946 --------------------------------------------------------------------------*/
Jeff Johnson32d95a32012-09-10 13:15:23 -07003947static int hdd_driver_init( void)
Jeff Johnson295189b2012-06-20 16:38:30 -07003948{
3949 VOS_STATUS status;
3950 v_CONTEXT_t pVosContext = NULL;
3951#ifdef ANI_BUS_TYPE_SDIO
3952 struct sdio_func *sdio_func_dev = NULL;
3953 unsigned int attempts = 0;
3954#endif // ANI_BUS_TYPE_SDIO
3955 struct device *dev = NULL;
3956 int ret_status = 0;
3957
3958 ENTER();
3959
Jeff Johnsone7245742012-09-05 17:12:55 -07003960#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07003961 wake_lock_init(&wlan_wake_lock, WAKE_LOCK_SUSPEND, "wlan");
Jeff Johnsone7245742012-09-05 17:12:55 -07003962#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07003963
3964 pr_info("%s: loading driver v%s\n", WLAN_MODULE_NAME,
3965 QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR);
3966
3967 //Power Up Libra WLAN card first if not already powered up
3968 status = vos_chipPowerUp(NULL,NULL,NULL);
3969 if (!VOS_IS_STATUS_SUCCESS(status))
3970 {
3971 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN not Powered Up. "
3972 "exiting", __func__);
3973 return -1;
3974 }
3975
3976#ifdef ANI_BUS_TYPE_SDIO
3977 //SDIO Polling should be turned on for card detection. When using Android Wi-Fi GUI
3978 //users need not trigger SDIO polling explicitly. However when loading drivers via
3979 //command line (Adb shell), users must turn on SDIO polling prior to loading WLAN.
3980 do {
3981 sdio_func_dev = libra_getsdio_funcdev();
3982 if (NULL == sdio_func_dev) {
3983 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN not detected yet.",__func__);
3984 attempts++;
3985 }
3986 else {
3987 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN detecton succeeded",__func__);
3988 dev = &sdio_func_dev->dev;
3989 break;
3990 }
3991
3992 if(attempts == 7)
3993 break;
3994
3995 msleep(250);
3996
3997 }while (attempts < 7);
3998
3999 //Retry to detect the card again by Powering Down the chip and Power up the chip
4000 //again. This retry is done to recover from CRC Error
4001 if (NULL == sdio_func_dev) {
4002
4003 attempts = 0;
4004
4005 //Vote off any PMIC voltage supplies
4006 vos_chipPowerDown(NULL, NULL, NULL);
4007
4008 msleep(1000);
4009
4010 //Power Up Libra WLAN card first if not already powered up
4011 status = vos_chipPowerUp(NULL,NULL,NULL);
4012 if (!VOS_IS_STATUS_SUCCESS(status))
4013 {
4014 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN not Powered Up. "
4015 "exiting", __func__);
4016 return -1;
4017 }
4018
4019 do {
4020 sdio_func_dev = libra_getsdio_funcdev();
4021 if (NULL == sdio_func_dev) {
4022 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN not detected yet.",__func__);
4023 attempts++;
4024 }
4025 else {
4026 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN detecton succeeded",__func__);
4027 dev = &sdio_func_dev->dev;
4028 break;
4029 }
4030
4031 if(attempts == 2)
4032 break;
4033
4034 msleep(1000);
4035
4036 }while (attempts < 3);
4037 }
4038
4039#endif // ANI_BUS_TYPE_SDIO
4040
4041#ifdef ANI_BUS_TYPE_PCI
4042
4043 dev = wcnss_wlan_get_device();
4044
4045#endif // ANI_BUS_TYPE_PCI
4046
4047#ifdef ANI_BUS_TYPE_PLATFORM
4048 dev = wcnss_wlan_get_device();
4049#endif // ANI_BUS_TYPE_PLATFORM
4050
4051
4052 do {
4053 if (NULL == dev) {
4054 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: WLAN device not found!!",__func__);
4055 ret_status = -1;
4056 break;
4057 }
4058
4059#ifdef MEMORY_DEBUG
4060 vos_mem_init();
4061#endif
4062
4063#ifdef TIMER_MANAGER
4064 vos_timer_manager_init();
4065#endif
4066
4067 /* Preopen VOSS so that it is ready to start at least SAL */
4068 status = vos_preOpen(&pVosContext);
4069
4070 if (!VOS_IS_STATUS_SUCCESS(status))
4071 {
4072 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed to preOpen VOSS", __func__);
4073 ret_status = -1;
4074 break;
4075 }
4076
4077#ifdef ANI_BUS_TYPE_SDIO
4078 /* Now Open SAL */
4079 status = WLANSAL_Open(pVosContext, 0);
4080
4081 if(!VOS_IS_STATUS_SUCCESS(status))
4082 {
4083 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed to open SAL", __func__);
4084
4085 /* If unable to open, cleanup and return failure */
4086 vos_preClose( &pVosContext );
4087 ret_status = -1;
4088 break;
4089 }
4090#endif // ANI_BUS_TYPE_SDIO
4091
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004092#ifndef MODULE
4093 /* For statically linked driver, call hdd_set_conparam to update curr_con_mode
4094 */
4095 hdd_set_conparam((v_UINT_t)con_mode);
4096#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004097
4098 // Call our main init function
4099 if(hdd_wlan_startup(dev)) {
4100 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: WLAN Driver Initialization failed",
4101 __func__);
4102#ifdef ANI_BUS_TYPE_SDIO
4103 WLANSAL_Close(pVosContext);
4104#endif // ANI_BUS_TYPE_SDIO
4105 vos_preClose( &pVosContext );
4106 ret_status = -1;
4107 break;
4108 }
4109
4110 /* Cancel the vote for XO Core ON
4111 * This is done here for safety purposes in case we re-initialize without turning
4112 * it OFF in any error scenario.
4113 */
4114 hddLog(VOS_TRACE_LEVEL_ERROR, "In module init: Ensure Force XO Core is OFF"
4115 " when WLAN is turned ON so Core toggles"
4116 " unless we enter PS\n");
4117 if (vos_chipVoteXOCore(NULL, NULL, NULL, VOS_FALSE) != VOS_STATUS_SUCCESS)
4118 {
4119 hddLog(VOS_TRACE_LEVEL_ERROR, "Could not cancel XO Core ON vote. Not returning failure."
4120 " Power consumed will be high\n");
4121 }
4122 } while (0);
4123
4124 if (0 != ret_status)
4125 {
4126 //Assert Deep sleep signal now to put Libra HW in lowest power state
4127 status = vos_chipAssertDeepSleep( NULL, NULL, NULL );
4128 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status) );
4129
4130 //Vote off any PMIC voltage supplies
4131 vos_chipPowerDown(NULL, NULL, NULL);
4132#ifdef TIMER_MANAGER
4133 vos_timer_exit();
4134#endif
4135#ifdef MEMORY_DEBUG
4136 vos_mem_exit();
4137#endif
4138
Jeff Johnsone7245742012-09-05 17:12:55 -07004139#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07004140 wake_lock_destroy(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07004141#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004142 pr_err("%s: driver load failure\n", WLAN_MODULE_NAME);
4143 }
4144 else
4145 {
4146 //Send WLAN UP indication to Nlink Service
4147 send_btc_nlink_msg(WLAN_MODULE_UP_IND, 0);
4148
4149 pr_info("%s: driver loaded\n", WLAN_MODULE_NAME);
4150
4151 }
4152
4153 EXIT();
4154
4155 return ret_status;
4156}
4157
Jeff Johnson32d95a32012-09-10 13:15:23 -07004158/**---------------------------------------------------------------------------
4159
4160 \brief hdd_module_init() - Init Function
4161
4162 This is the driver entry point (invoked when module is loaded using insmod)
4163
4164 \param - None
4165
4166 \return - 0 for success, non zero for failure
4167
4168 --------------------------------------------------------------------------*/
4169#ifdef MODULE
4170static int __init hdd_module_init ( void)
4171{
4172 return hdd_driver_init();
4173}
Jeff Johnson32d95a32012-09-10 13:15:23 -07004174#else /* #ifdef MODULE */
4175static int __init hdd_module_init ( void)
4176{
4177 /* Driver initialization is delayed to fwpath_changed_handler */
4178 return 0;
4179}
Jeff Johnson32d95a32012-09-10 13:15:23 -07004180#endif /* #ifdef MODULE */
4181
Jeff Johnson295189b2012-06-20 16:38:30 -07004182
4183/**---------------------------------------------------------------------------
4184
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004185 \brief hdd_driver_exit() - Exit function
Jeff Johnson295189b2012-06-20 16:38:30 -07004186
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004187 This is the driver exit point (invoked when module is unloaded using rmmod
4188 or con_mode was changed by userspace)
Jeff Johnson295189b2012-06-20 16:38:30 -07004189
4190 \param - None
4191
4192 \return - None
4193
4194 --------------------------------------------------------------------------*/
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004195static void hdd_driver_exit(void)
Jeff Johnson295189b2012-06-20 16:38:30 -07004196{
4197 hdd_context_t *pHddCtx = NULL;
4198 v_CONTEXT_t pVosContext = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07004199
4200 pr_info("%s: unloading driver v%s\n", WLAN_MODULE_NAME, QWLAN_VERSIONSTR);
4201
4202 //Get the global vos context
4203 pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
4204
4205 if(!pVosContext)
4206 {
4207 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
4208 goto done;
4209 }
4210
4211 //Get the HDD context.
4212 pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
4213
4214 if(!pHddCtx)
4215 {
4216 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: module exit called before probe",__func__);
4217 }
4218 else
4219 {
Jeff Johnsone7245742012-09-05 17:12:55 -07004220 /* module exit should never proceed if SSR is not completed */
Jeff Johnson295189b2012-06-20 16:38:30 -07004221 while(isWDresetInProgress()){
Jeff Johnsone7245742012-09-05 17:12:55 -07004222 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:SSR in Progress; block rmmod for 1 second!!!",__func__);
4223 msleep(1000);
Jeff Johnson295189b2012-06-20 16:38:30 -07004224 }
4225
4226 pHddCtx->isLoadUnloadInProgress = TRUE;
4227 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE);
4228
4229 //Do all the cleanup before deregistering the driver
4230 hdd_wlan_exit(pHddCtx);
4231 }
4232
4233#ifdef ANI_BUS_TYPE_SDIO
4234 WLANSAL_Close(pVosContext);
4235#endif // ANI_BUS_TYPE_SDIO
4236
4237 vos_preClose( &pVosContext );
4238
4239#ifdef TIMER_MANAGER
4240 vos_timer_exit();
4241#endif
4242#ifdef MEMORY_DEBUG
4243 vos_mem_exit();
4244#endif
4245
4246done:
Jeff Johnsone7245742012-09-05 17:12:55 -07004247#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07004248 wake_lock_destroy(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07004249#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004250 pr_info("%s: driver unloaded\n", WLAN_MODULE_NAME);
4251}
4252
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004253/**---------------------------------------------------------------------------
4254
4255 \brief hdd_module_exit() - Exit function
4256
4257 This is the driver exit point (invoked when module is unloaded using rmmod)
4258
4259 \param - None
4260
4261 \return - None
4262
4263 --------------------------------------------------------------------------*/
4264static void __exit hdd_module_exit(void)
4265{
4266 hdd_driver_exit();
4267}
4268
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004269#ifdef MODULE
4270static int fwpath_changed_handler(const char *kmessage,
4271 struct kernel_param *kp)
4272{
4273 /* nothing to do when driver is DLKM */
4274 return 0;
4275}
4276
4277static int con_mode_handler(const char *kmessage,
4278 struct kernel_param *kp)
4279{
4280 return 0;
4281}
4282#else /* #ifdef MODULE */
4283/**---------------------------------------------------------------------------
4284
4285 \brief fwpath_changed_handler() - Handler Function
4286
4287 This is the driver entry point
4288 - delayed driver initialization when driver is statically linked
4289 - invoked when module parameter fwpath is modified from userpspace to signal
4290 initializing the WLAN driver
4291
4292 \return - 0 for success, non zero for failure
4293
4294 --------------------------------------------------------------------------*/
4295static int fwpath_changed_handler(const char *kmessage,
4296 struct kernel_param *kp)
4297{
4298 if (!wlan_hdd_inited) {
4299 wlan_hdd_inited = 1;
4300 return hdd_driver_init();
4301 }
4302
4303 hdd_driver_exit();
4304
4305 msleep(200);
4306
4307 return hdd_driver_init();
4308}
4309
Jeff Johnson295189b2012-06-20 16:38:30 -07004310/**---------------------------------------------------------------------------
4311
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004312 \brief con_mode_handler() -
4313
4314 Handler function for module param con_mode when it is changed by userspace
4315 Dynamically linked - do nothing
4316 Statically linked - exit and init driver, as in rmmod and insmod
4317
4318 \param -
4319
4320 \return -
4321
4322 --------------------------------------------------------------------------*/
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004323static int con_mode_handler(const char *kmessage,
4324 struct kernel_param *kp)
4325{
4326 int ret = param_set_int(kmessage, kp);
4327
4328 if (ret)
4329 return ret;
4330
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004331 return fwpath_changed_handler(kmessage, kp);
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004332}
4333#endif /* #ifdef MODULE */
4334
4335/**---------------------------------------------------------------------------
4336
Jeff Johnson295189b2012-06-20 16:38:30 -07004337 \brief hdd_get_conparam() -
4338
4339 This is the driver exit point (invoked when module is unloaded using rmmod)
4340
4341 \param - None
4342
4343 \return - tVOS_CON_MODE
4344
4345 --------------------------------------------------------------------------*/
4346tVOS_CON_MODE hdd_get_conparam ( void )
4347{
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004348#ifdef MODULE
Jeff Johnson295189b2012-06-20 16:38:30 -07004349 return (tVOS_CON_MODE)con_mode;
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004350#else
4351 return (tVOS_CON_MODE)curr_con_mode;
4352#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004353}
4354void hdd_set_conparam ( v_UINT_t newParam )
4355{
4356 con_mode = newParam;
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004357#ifndef MODULE
4358 curr_con_mode = con_mode;
4359#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004360}
4361/**---------------------------------------------------------------------------
4362
4363 \brief hdd_softap_sta_deauth() - function
4364
4365 This to take counter measure to handle deauth req from HDD
4366
4367 \param - pAdapter - Pointer to the HDD
4368
4369 \param - enable - boolean value
4370
4371 \return - None
4372
4373 --------------------------------------------------------------------------*/
4374
4375void hdd_softap_sta_deauth(hdd_adapter_t *pAdapter, v_U8_t *pDestMacAddress)
4376{
4377 v_U8_t STAId;
4378 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
4379#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
4380 tHalHandle hHalHandle;
4381#endif
4382
4383 ENTER();
4384
4385 hddLog( LOGE, "hdd_softap_sta_deauth:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
4386
4387 //Ignore request to deauth bcmc station
4388 if( pDestMacAddress[0] & 0x1 )
4389 return;
4390
4391 WLANSAP_DeauthSta(pVosContext,pDestMacAddress);
4392
4393 /*Get the Station ID*/
4394#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
4395 hHalHandle = (tHalHandle ) vos_get_context(VOS_MODULE_ID_HAL, pVosContext);
4396 if (eHAL_STATUS_SUCCESS ==
4397 halTable_FindStaidByAddr(hHalHandle, (tANI_U8 *)pDestMacAddress,
4398 &STAId))
4399 {
4400 hdd_softap_DeregisterSTA(pAdapter, STAId);
4401 }
4402#else
4403 if (VOS_STATUS_SUCCESS ==
4404 hdd_softap_GetStaId(pAdapter, (v_MACADDR_t *)pDestMacAddress,
4405 &STAId))
4406 {
4407 hdd_softap_DeregisterSTA(pAdapter, STAId);
4408 }
4409#endif
4410
4411 EXIT();
4412}
4413
4414/**---------------------------------------------------------------------------
4415
4416 \brief hdd_softap_sta_disassoc() - function
4417
4418 This to take counter measure to handle deauth req from HDD
4419
4420 \param - pAdapter - Pointer to the HDD
4421
4422 \param - enable - boolean value
4423
4424 \return - None
4425
4426 --------------------------------------------------------------------------*/
4427
4428void hdd_softap_sta_disassoc(hdd_adapter_t *pAdapter,v_U8_t *pDestMacAddress)
4429{
4430 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
4431
4432 ENTER();
4433
4434 hddLog( LOGE, "hdd_softap_sta_disassoc:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
4435
4436 //Ignore request to disassoc bcmc station
4437 if( pDestMacAddress[0] & 0x1 )
4438 return;
4439
4440 WLANSAP_DisassocSta(pVosContext,pDestMacAddress);
4441}
4442
4443void hdd_softap_tkip_mic_fail_counter_measure(hdd_adapter_t *pAdapter,v_BOOL_t enable)
4444{
4445 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
4446
4447 ENTER();
4448
4449 hddLog( LOGE, "hdd_softap_tkip_mic_fail_counter_measure:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
4450
4451 WLANSAP_SetCounterMeasure(pVosContext, (v_BOOL_t)enable);
4452}
4453
Jeff Johnson295189b2012-06-20 16:38:30 -07004454/**---------------------------------------------------------------------------
4455 *
4456 * \brief hdd_get__concurrency_mode() -
4457 *
4458 *
4459 * \param - None
4460 *
4461 * \return - CONCURRENCY MODE
4462 *
4463 * --------------------------------------------------------------------------*/
4464tVOS_CONCURRENCY_MODE hdd_get_concurrency_mode ( void )
4465{
4466 v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL );
4467 hdd_context_t *pHddCtx;
4468
4469 if (NULL != pVosContext)
4470 {
4471 pHddCtx = vos_get_context( VOS_MODULE_ID_HDD, pVosContext);
4472 if (NULL != pHddCtx)
4473 {
4474 return (tVOS_CONCURRENCY_MODE)pHddCtx->concurrency_mode;
4475 }
4476 }
4477
4478 /* we are in an invalid state :( */
4479 hddLog(LOGE, "%s: Invalid context", __FUNCTION__);
4480 return VOS_STA;
4481}
4482
4483/* Decide whether to allow/not the apps power collapse.
4484 * Allow apps power collapse if we are in connected state.
4485 * if not, allow only if we are in IMPS */
4486v_BOOL_t hdd_is_apps_power_collapse_allowed(hdd_context_t* pHddCtx)
4487{
4488 tPmcState pmcState = pmcGetPmcState(pHddCtx->hHal);
4489 hdd_config_t *pConfig = pHddCtx->cfg_ini;
4490 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
4491 hdd_adapter_t *pAdapter = NULL;
4492 VOS_STATUS status;
4493
4494#ifdef WLAN_SOFTAP_FEATURE
4495 if (VOS_STA_SAP_MODE == hdd_get_conparam())
4496 return TRUE;
4497#endif
4498
4499 /*loop through all adapters. TBD fix for Concurrency */
4500 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
4501 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
4502 {
4503 pAdapter = pAdapterNode->pAdapter;
4504 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode)
4505 || (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) )
4506 {
4507 if ((pConfig->fIsImpsEnabled || pConfig->fIsBmpsEnabled)
4508 && (pmcState != IMPS && pmcState != BMPS
4509 && pmcState != STOPPED && pmcState != STANDBY))
4510 {
4511 return FALSE;
4512 }
4513 }
4514 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
4515 pAdapterNode = pNext;
4516 }
4517 return TRUE;
4518}
4519
4520void wlan_hdd_set_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
4521{
4522 switch(mode)
4523 {
4524 case WLAN_HDD_INFRA_STATION:
4525#ifdef WLAN_FEATURE_P2P
4526 case WLAN_HDD_P2P_CLIENT:
4527 case WLAN_HDD_P2P_GO:
4528#endif
4529 case WLAN_HDD_SOFTAP:
Jeff Johnsone7245742012-09-05 17:12:55 -07004530 pHddCtx->concurrency_mode |= (1 << mode);
4531 pHddCtx->no_of_sessions[mode]++;
Jeff Johnson295189b2012-06-20 16:38:30 -07004532 break;
4533 default:
4534 break;
4535
4536 }
4537 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
4538 __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
4539}
4540
4541
4542void wlan_hdd_clear_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
4543{
4544 switch(mode)
4545 {
4546 case WLAN_HDD_INFRA_STATION:
4547#ifdef WLAN_FEATURE_P2P
4548 case WLAN_HDD_P2P_CLIENT:
4549 case WLAN_HDD_P2P_GO:
4550#endif
4551 case WLAN_HDD_SOFTAP:
4552 pHddCtx->no_of_sessions[mode]--;
4553 if (!(pHddCtx->no_of_sessions[mode]))
4554 pHddCtx->concurrency_mode &= (~(1 << mode));
4555 break;
4556 default:
4557 break;
4558 }
4559 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
4560 __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
4561}
4562
Jeff Johnsone7245742012-09-05 17:12:55 -07004563/**---------------------------------------------------------------------------
4564 *
4565 * \brief wlan_hdd_restart_init
4566 *
4567 * This function initalizes restart timer/flag. An internal function.
4568 *
4569 * \param - pHddCtx
4570 *
4571 * \return - None
4572 *
4573 * --------------------------------------------------------------------------*/
4574
4575static void wlan_hdd_restart_init(hdd_context_t *pHddCtx)
4576{
4577 /* Initialize */
4578 pHddCtx->hdd_restart_retries = 0;
4579 atomic_set(&pHddCtx->isRestartInProgress, 0);
4580 vos_timer_init(&pHddCtx->hdd_restart_timer,
4581 VOS_TIMER_TYPE_SW,
4582 wlan_hdd_restart_timer_cb,
4583 pHddCtx);
4584}
4585/**---------------------------------------------------------------------------
4586 *
4587 * \brief wlan_hdd_restart_deinit
4588 *
4589 * This function cleans up the resources used. An internal function.
4590 *
4591 * \param - pHddCtx
4592 *
4593 * \return - None
4594 *
4595 * --------------------------------------------------------------------------*/
4596
4597static void wlan_hdd_restart_deinit(hdd_context_t* pHddCtx)
4598{
4599
4600 VOS_STATUS vos_status;
4601 /* Block any further calls */
4602 atomic_set(&pHddCtx->isRestartInProgress, 1);
4603 /* Cleanup */
4604 vos_status = vos_timer_stop( &pHddCtx->hdd_restart_timer );
4605 if (!VOS_IS_STATUS_SUCCESS(vos_status))
4606 hddLog(LOGE, FL("Failed to stop HDD restart timer\n"));
4607 vos_status = vos_timer_destroy(&pHddCtx->hdd_restart_timer);
4608 if (!VOS_IS_STATUS_SUCCESS(vos_status))
4609 hddLog(LOGE, FL("Failed to destroy HDD restart timer\n"));
4610
4611}
4612
4613/**---------------------------------------------------------------------------
4614 *
4615 * \brief wlan_hdd_framework_restart
4616 *
4617 * This function uses a cfg80211 API to start a framework initiated WLAN
4618 * driver module unload/load.
4619 *
4620 * Also this API keep retrying (WLAN_HDD_RESTART_RETRY_MAX_CNT).
4621 *
4622 *
4623 * \param - pHddCtx
4624 *
4625 * \return - VOS_STATUS_SUCCESS: Success
4626 * VOS_STATUS_E_EMPTY: Adapter is Empty
4627 * VOS_STATUS_E_NOMEM: No memory
4628
4629 * --------------------------------------------------------------------------*/
4630
4631static VOS_STATUS wlan_hdd_framework_restart(hdd_context_t *pHddCtx)
4632{
4633 VOS_STATUS status = VOS_STATUS_SUCCESS;
4634 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
4635 int len = (sizeof (struct ieee80211_mgmt));
4636 struct ieee80211_mgmt *mgmt = NULL;
4637
4638 /* Prepare the DEAUTH managment frame with reason code */
4639 mgmt = kzalloc(len, GFP_KERNEL);
4640 if(mgmt == NULL)
4641 {
4642 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
4643 "%s: memory allocatoin failed (%d bytes)", __func__, len);
4644 return VOS_STATUS_E_NOMEM;
4645 }
4646 mgmt->u.deauth.reason_code = WLAN_REASON_DISASSOC_LOW_ACK;
4647
4648 /* Iterate over all adapters/devices */
4649 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
4650 do
4651 {
4652 if( (status == VOS_STATUS_SUCCESS) &&
4653 pAdapterNode &&
4654 pAdapterNode->pAdapter)
4655 {
4656 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
4657 "restarting the driver(intf:\'%s\' mode:%d :try %d)",
4658 pAdapterNode->pAdapter->dev->name,
4659 pAdapterNode->pAdapter->device_mode,
4660 pHddCtx->hdd_restart_retries + 1);
4661 /*
4662 * CFG80211 event to restart the driver
4663 *
4664 * 'cfg80211_send_unprot_deauth' sends a
4665 * NL80211_CMD_UNPROT_DEAUTHENTICATE event to supplicant at any state
4666 * of SME(Linux Kernel) state machine.
4667 *
4668 * Reason code WLAN_REASON_DISASSOC_LOW_ACK is currently used to restart
4669 * the driver.
4670 *
4671 */
4672
4673 cfg80211_send_unprot_deauth(pAdapterNode->pAdapter->dev, (u_int8_t*)mgmt, len );
4674 }
4675 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
4676 pAdapterNode = pNext;
4677 } while((NULL != pAdapterNode) && (VOS_STATUS_SUCCESS == status));
4678
4679
4680 /* Free the allocated management frame */
4681 kfree(mgmt);
4682
4683 /* Retry until we unload or reach max count */
4684 if(++pHddCtx->hdd_restart_retries < WLAN_HDD_RESTART_RETRY_MAX_CNT)
4685 vos_timer_start(&pHddCtx->hdd_restart_timer, WLAN_HDD_RESTART_RETRY_DELAY_MS);
4686
4687 return status;
4688
4689}
4690/**---------------------------------------------------------------------------
4691 *
4692 * \brief wlan_hdd_restart_timer_cb
4693 *
4694 * Restart timer callback. An internal function.
4695 *
4696 * \param - User data:
4697 *
4698 * \return - None
4699 *
4700 * --------------------------------------------------------------------------*/
4701
4702void wlan_hdd_restart_timer_cb(v_PVOID_t usrDataForCallback)
4703{
4704 hdd_context_t *pHddCtx = usrDataForCallback;
4705 wlan_hdd_framework_restart(pHddCtx);
4706 return;
4707
4708}
4709
4710
4711/**---------------------------------------------------------------------------
4712 *
4713 * \brief wlan_hdd_restart_driver
4714 *
4715 * This function sends an event to supplicant to restart the WLAN driver.
4716 *
4717 * This function is called from vos_wlanRestart.
4718 *
4719 * \param - pHddCtx
4720 *
4721 * \return - VOS_STATUS_SUCCESS: Success
4722 * VOS_STATUS_E_EMPTY: Adapter is Empty
4723 * VOS_STATUS_E_ALREADY: Request already in progress
4724
4725 * --------------------------------------------------------------------------*/
4726VOS_STATUS wlan_hdd_restart_driver(hdd_context_t *pHddCtx)
4727{
4728 VOS_STATUS status = VOS_STATUS_SUCCESS;
4729
4730 /* A tight check to make sure reentrancy */
4731 if(atomic_xchg(&pHddCtx->isRestartInProgress, 1))
4732 {
4733 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
4734 "%s: WLAN restart is already in progress", __func__);
4735
4736 return VOS_STATUS_E_ALREADY;
4737 }
4738
4739 /* Restart API */
4740 status = wlan_hdd_framework_restart(pHddCtx);
4741
4742 return status;
4743}
4744
4745
Jeff Johnson295189b2012-06-20 16:38:30 -07004746//Register the module init/exit functions
4747module_init(hdd_module_init);
4748module_exit(hdd_module_exit);
4749
4750MODULE_LICENSE("Dual BSD/GPL");
4751MODULE_AUTHOR("Qualcomm Atheros, Inc.");
4752MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER");
4753
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004754module_param_call(con_mode, con_mode_handler, param_get_int, &con_mode,
4755 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Jeff Johnson32d95a32012-09-10 13:15:23 -07004756
4757module_param_call(fwpath, fwpath_changed_handler, param_get_string, fwpath,
4758 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);