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