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