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