blob: 014ddcd1276a7607ad9cfe5f5a4faf9a17cbd1fb [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
Jeff Johnson295189b2012-06-20 16:38:30 -07002936
2937 //Close VOSS
2938 //This frees pMac(HAL) context. There should not be any call that requires pMac access after this.
2939 vos_close(pVosContext);
2940
2941#ifdef ANI_BUS_TYPE_SDIO
2942 vosStatus = WLANBAL_Close(pVosContext);
2943 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2944 {
2945 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2946 "%s: Failed to close BAL",__func__);
2947 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2948 }
2949 hddLog(VOS_TRACE_LEVEL_ERROR,"Returned WLAN BAL CLOSE\n\n\n\n");
2950#endif // ANI_BUS_TYPE_SDIO
2951
2952 //Close Watchdog
2953 if(pHddCtx->cfg_ini->fIsLogpEnabled)
2954 vos_watchdog_close(pVosContext);
2955
2956 /* Cancel the vote for XO Core ON.
2957 * This is done here to ensure there is no race condition since MC, TX and WD threads have
2958 * exited at this point
2959 */
2960 hddLog(VOS_TRACE_LEVEL_WARN, "In module exit: Cancel the vote for XO Core ON"
2961 " when WLAN is turned OFF\n");
2962 if (vos_chipVoteXOCore(NULL, NULL, NULL, VOS_FALSE) != VOS_STATUS_SUCCESS)
2963 {
2964 hddLog(VOS_TRACE_LEVEL_ERROR, "Could not cancel the vote for XO Core ON."
2965 " Not returning failure."
2966 " Power consumed will be high\n");
2967 }
2968
2969 hdd_close_all_adapters( pHddCtx );
2970
2971
2972 //Free up dynamically allocated members inside HDD Adapter
2973 kfree(pHddCtx->cfg_ini);
2974 pHddCtx->cfg_ini= NULL;
2975
2976 /* free the power on lock from platform driver */
2977 if (free_riva_power_on_lock("wlan"))
2978 {
2979 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: failed to free power on lock",
2980 __func__);
2981 }
2982
2983#ifdef ANI_MANF_DIAG
2984free_hdd_ctx:
2985#endif
2986#ifdef CONFIG_CFG80211
2987 wiphy_unregister(wiphy) ;
2988 wiphy_free(wiphy) ;
2989#else
2990 vos_mem_free( pHddCtx );
2991#endif
2992 if (hdd_is_ssr_required())
2993 {
2994 /* WDI timeout had happened during unload, so SSR is needed here */
Madan Mohan Koyyalamudi3246f5b2012-10-15 15:40:02 -07002995 subsystem_restart("wcnss");
Jeff Johnson295189b2012-06-20 16:38:30 -07002996 msleep(5000);
2997 }
2998 hdd_set_ssr_required (VOS_FALSE);
2999}
3000
3001
3002/**---------------------------------------------------------------------------
3003
3004 \brief hdd_update_config_from_nv() - Function to update the contents of
3005 the running configuration with parameters taken from NV storage
3006
3007 \param - pHddCtx - Pointer to the HDD global context
3008
3009 \return - VOS_STATUS_SUCCESS if successful
3010
3011 --------------------------------------------------------------------------*/
3012static VOS_STATUS hdd_update_config_from_nv(hdd_context_t* pHddCtx)
3013{
3014#ifndef FEATURE_WLAN_INTEGRATED_SOC
3015 eHalStatus halStatus;
3016#endif
3017
3018#ifdef FEATURE_WLAN_INTEGRATED_SOC
3019 v_BOOL_t itemIsValid = VOS_FALSE;
3020 VOS_STATUS status;
3021 v_MACADDR_t macFromNV[VOS_MAX_CONCURRENCY_PERSONA];
3022 v_U8_t macLoop;
3023
3024 /*If the NV is valid then get the macaddress from nv else get it from qcom_cfg.ini*/
3025 status = vos_nv_getValidity(VNV_FIELD_IMAGE, &itemIsValid);
3026 if(status != VOS_STATUS_SUCCESS)
3027 {
3028 hddLog(VOS_TRACE_LEVEL_ERROR," vos_nv_getValidity() failed\n ");
3029 return VOS_STATUS_E_FAILURE;
3030 }
3031
3032 if (itemIsValid == VOS_TRUE)
3033 {
3034 hddLog(VOS_TRACE_LEVEL_INFO_HIGH," Reading the Macaddress from NV\n ");
3035 status = vos_nv_readMultiMacAddress((v_U8_t *)&macFromNV[0].bytes[0],
3036 VOS_MAX_CONCURRENCY_PERSONA);
3037 if(status != VOS_STATUS_SUCCESS)
3038 {
3039 /* Get MAC from NV fail, not update CFG info
3040 * INI MAC value will be used for MAC setting */
3041 hddLog(VOS_TRACE_LEVEL_ERROR," vos_nv_readMacAddress() failed\n ");
3042 return VOS_STATUS_E_FAILURE;
3043 }
3044
3045 /* If first MAC is not valid, treat all others are not valid
3046 * Then all MACs will be got from ini file */
3047 if(vos_is_macaddr_zero(&macFromNV[0]))
3048 {
3049 /* MAC address in NV file is not configured yet */
3050 hddLog(VOS_TRACE_LEVEL_WARN, "Invalid MAC in NV file");
3051 return VOS_STATUS_E_INVAL;
3052 }
3053
3054 /* Get MAC address from NV, update CFG info */
3055 for(macLoop = 0; macLoop < VOS_MAX_CONCURRENCY_PERSONA; macLoop++)
3056 {
3057 if(vos_is_macaddr_zero(&macFromNV[macLoop]))
3058 {
3059 printk(KERN_ERR "not valid MAC from NV for %d", macLoop);
3060 /* This MAC is not valid, skip it
3061 * This MAC will be got from ini file */
3062 }
3063 else
3064 {
3065 vos_mem_copy((v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[macLoop].bytes[0],
3066 (v_U8_t *)&macFromNV[macLoop].bytes[0],
3067 VOS_MAC_ADDR_SIZE);
3068 }
3069 }
3070 }
3071 else
3072 {
3073 hddLog(VOS_TRACE_LEVEL_ERROR, "NV ITEM, MAC Not valid");
3074 return VOS_STATUS_E_FAILURE;
3075 }
3076#endif /* FEATURE_WLAN_INTEGRATED_SOC */
3077
3078#ifndef FEATURE_WLAN_INTEGRATED_SOC
3079#if 1 /* need to fix for concurrency */
3080 // Set the MAC Address
3081 // Currently this is used by HAL to add self sta. Remove this once self sta is added as part of session open.
3082 halStatus = ccmCfgSetStr( pHddCtx->hHal, WNI_CFG_STA_ID,
3083 (v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[0],
3084 sizeof( pHddCtx->cfg_ini->intfMacAddr[0]),
3085 hdd_set_mac_addr_cb, VOS_FALSE );
3086
3087 if (!HAL_STATUS_SUCCESS( halStatus ))
3088 {
3089 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed to set MAC Address. "
3090 "HALStatus is %08d [x%08x]",__func__, halStatus, halStatus );
3091 return VOS_STATUS_E_FAILURE;
3092 }
3093#endif
3094#endif
3095
3096 return VOS_STATUS_SUCCESS;
3097}
3098
3099/**---------------------------------------------------------------------------
3100
3101 \brief hdd_post_voss_start_config() - HDD post voss start config helper
3102
3103 \param - pAdapter - Pointer to the HDD
3104
3105 \return - None
3106
3107 --------------------------------------------------------------------------*/
3108VOS_STATUS hdd_post_voss_start_config(hdd_context_t* pHddCtx)
3109{
3110 eHalStatus halStatus;
3111 v_U32_t listenInterval;
3112
3113#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
3114 /* In the non-integrated architecture we update the configuration from
3115 the INI file and from NV after vOSS has been started
3116 */
3117
3118 // Apply the cfg.ini to cfg.dat
3119 if (FALSE == hdd_update_config_dat(pHddCtx))
3120 {
3121 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: config update failed",__func__ );
3122 return VOS_STATUS_E_FAILURE;
3123 }
3124
3125 // Apply the NV to cfg.dat
3126 if (VOS_STATUS_SUCCESS != hdd_update_config_from_nv(pHddCtx))
3127 {
3128 hddLog(VOS_TRACE_LEVEL_FATAL,
3129 "%s: config update from NV failed", __func__ );
3130 return VOS_STATUS_E_FAILURE;
3131 }
3132#endif // FEATURE_WLAN_NON_INTEGRATED_SOC
3133
3134 // Send ready indication to the HDD. This will kick off the MAC
3135 // into a 'running' state and should kick off an initial scan.
3136 halStatus = sme_HDDReadyInd( pHddCtx->hHal );
3137 if ( !HAL_STATUS_SUCCESS( halStatus ) )
3138 {
3139 hddLog(VOS_TRACE_LEVEL_ERROR,"%S: sme_HDDReadyInd() failed with status "
3140 "code %08d [x%08x]",__func__, halStatus, halStatus );
3141 return VOS_STATUS_E_FAILURE;
3142 }
3143
3144 // Set default LI into HDD context,
3145 // otherwise under some race condition, HDD will set 0 LI value into RIVA,
3146 // And RIVA will crash
3147 wlan_cfgGetInt(pHddCtx->hHal, WNI_CFG_LISTEN_INTERVAL, &listenInterval);
3148 pHddCtx->hdd_actual_LI_value = listenInterval;
3149
3150 return VOS_STATUS_SUCCESS;
3151}
3152
3153#ifdef ANI_BUS_TYPE_SDIO
3154
3155#ifndef ANI_MANF_DIAG
3156// Routine to initialize the PMU
3157void wlan_hdd_enable_deepsleep(v_VOID_t * pVosContext)
3158{
3159/*-------------- Need to fix this correctly while doing Deepsleep testing
3160 tANI_U32 regValue = 0;
3161
3162 regValue = QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_DEEP_SLEEP_EN_MASK |
3163 QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_1P23_LPM_AON_MASK_MASK |
3164 QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_1P23_LPM_SW_MASK_MASK |
3165 QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_2P3_LPM_MASK_MASK;
3166
3167 WLANBAL_WriteRegister(pVosContext, QWLAN_PMU_LDO_CTRL_REG_REG, regValue);
3168---------------------*/
3169
3170 return;
3171}
3172#endif
3173#endif
3174
3175/* wake lock APIs for HDD */
3176void hdd_prevent_suspend(void)
3177{
Jeff Johnsone7245742012-09-05 17:12:55 -07003178#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07003179 wake_lock(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07003180#else
3181 wcnss_prevent_suspend();
3182#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07003183}
3184
3185void hdd_allow_suspend(void)
3186{
Jeff Johnsone7245742012-09-05 17:12:55 -07003187#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07003188 wake_unlock(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07003189#else
3190 wcnss_allow_suspend();
3191#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07003192}
3193
Madan Mohan Koyyalamudi10d83a92012-09-28 15:47:05 -07003194void hdd_allow_suspend_timeout(v_U32_t timeout)
3195{
3196#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
3197 wake_lock_timeout(&wlan_wake_lock, timeout);
3198#else
3199 /* Do nothing as there is no API in wcnss for timeout*/
3200#endif
3201}
3202
Jeff Johnson295189b2012-06-20 16:38:30 -07003203/**---------------------------------------------------------------------------
3204
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003205 \brief hdd_exchange_version_and_caps() - HDD function to exchange version and capability
3206 information between Host and Riva
3207
3208 This function gets reported version of FW
3209 It also finds the version of Riva headers used to compile the host
3210 It compares the above two and prints a warning if they are different
3211 It gets the SW and HW version string
3212 Finally, it exchanges capabilities between host and Riva i.e. host and riva exchange a msg
3213 indicating the features they support through a bitmap
3214
3215 \param - pHddCtx - Pointer to HDD context
3216
3217 \return - void
3218
3219 --------------------------------------------------------------------------*/
3220
3221void hdd_exchange_version_and_caps(hdd_context_t *pHddCtx)
3222{
3223
3224 tSirVersionType versionCompiled;
3225 tSirVersionType versionReported;
3226 tSirVersionString versionString;
3227 tANI_U8 fwFeatCapsMsgSupported = 0;
3228 VOS_STATUS vstatus;
3229
3230 /* retrieve and display WCNSS version information */
3231 do {
3232
3233 vstatus = sme_GetWcnssWlanCompiledVersion(pHddCtx->hHal,
3234 &versionCompiled);
3235 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3236 {
3237 hddLog(VOS_TRACE_LEVEL_FATAL,
3238 "%s: unable to retrieve WCNSS WLAN compiled version",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003239 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003240 break;
3241 }
3242
3243 vstatus = sme_GetWcnssWlanReportedVersion(pHddCtx->hHal,
3244 &versionReported);
3245 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3246 {
3247 hddLog(VOS_TRACE_LEVEL_FATAL,
3248 "%s: unable to retrieve WCNSS WLAN reported version",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003249 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003250 break;
3251 }
3252
3253 if ((versionCompiled.major != versionReported.major) ||
3254 (versionCompiled.minor != versionReported.minor) ||
3255 (versionCompiled.version != versionReported.version) ||
3256 (versionCompiled.revision != versionReported.revision))
3257 {
3258 pr_err("%s: WCNSS WLAN Version %u.%u.%u.%u, "
3259 "Host expected %u.%u.%u.%u\n",
3260 WLAN_MODULE_NAME,
3261 (int)versionReported.major,
3262 (int)versionReported.minor,
3263 (int)versionReported.version,
3264 (int)versionReported.revision,
3265 (int)versionCompiled.major,
3266 (int)versionCompiled.minor,
3267 (int)versionCompiled.version,
3268 (int)versionCompiled.revision);
3269 }
3270 else
3271 {
3272 pr_info("%s: WCNSS WLAN version %u.%u.%u.%u\n",
3273 WLAN_MODULE_NAME,
3274 (int)versionReported.major,
3275 (int)versionReported.minor,
3276 (int)versionReported.version,
3277 (int)versionReported.revision);
3278 }
3279
3280 vstatus = sme_GetWcnssSoftwareVersion(pHddCtx->hHal,
3281 versionString,
3282 sizeof(versionString));
3283 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3284 {
3285 hddLog(VOS_TRACE_LEVEL_FATAL,
3286 "%s: unable to retrieve WCNSS software version string",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003287 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003288 break;
3289 }
3290
3291 pr_info("%s: WCNSS software version %s\n",
3292 WLAN_MODULE_NAME, versionString);
3293
3294 vstatus = sme_GetWcnssHardwareVersion(pHddCtx->hHal,
3295 versionString,
3296 sizeof(versionString));
3297 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3298 {
3299 hddLog(VOS_TRACE_LEVEL_FATAL,
3300 "%s: unable to retrieve WCNSS hardware version string",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003301 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003302 break;
3303 }
3304
3305 pr_info("%s: WCNSS hardware version %s\n",
3306 WLAN_MODULE_NAME, versionString);
3307
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07003308 /* 1.Check if FW version is greater than 0.1.1.0. Only then send host-FW capability exchange message
3309 2.Host-FW capability exchange message is only present on riva 1.1 so
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003310 send the message only if it the riva is 1.1
3311 minor numbers for different riva branches:
3312 0 -> (1.0)Mainline Build
3313 1 -> (1.1)Mainline Build
3314 2->(1.04) Stability Build
3315 */
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07003316 if (((versionReported.major>0) || (versionReported.minor>1) ||
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003317 ((versionReported.minor>=1) && (versionReported.version>=1)))
3318 && ((versionReported.major == 1) && (versionReported.minor >= 1)))
3319 fwFeatCapsMsgSupported = 1;
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07003320
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003321 if (fwFeatCapsMsgSupported)
3322 sme_featureCapsExchange(pHddCtx->hHal);
3323
3324 } while (0);
3325
3326}
3327
3328/**---------------------------------------------------------------------------
3329
Jeff Johnson295189b2012-06-20 16:38:30 -07003330 \brief hdd_wlan_startup() - HDD init function
3331
3332 This is the driver startup code executed once a WLAN device has been detected
3333
3334 \param - dev - Pointer to the underlying device
3335
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08003336 \return - 0 for success, < 0 for failure
Jeff Johnson295189b2012-06-20 16:38:30 -07003337
3338 --------------------------------------------------------------------------*/
3339
3340int hdd_wlan_startup(struct device *dev )
3341{
3342 VOS_STATUS status;
3343 hdd_adapter_t *pAdapter = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -07003344 hdd_adapter_t *pP2pAdapter = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07003345 hdd_context_t *pHddCtx = NULL;
3346 v_CONTEXT_t pVosContext= NULL;
3347#ifdef WLAN_BTAMP_FEATURE
3348 VOS_STATUS vStatus = VOS_STATUS_SUCCESS;
3349 WLANBAP_ConfigType btAmpConfig;
3350 hdd_config_t *pConfig;
3351#endif
3352 int ret;
3353#ifdef CONFIG_CFG80211
3354 struct wiphy *wiphy;
3355#endif
3356#ifdef ANI_BUS_TYPE_SDIO
3357 struct sdio_func *sdio_func_dev = dev_to_sdio_func(dev);
3358#endif //ANI_BUS_TYPE_SDIO
3359
3360 ENTER();
3361#ifdef CONFIG_CFG80211
3362 /*
3363 * cfg80211: wiphy allocation
3364 */
3365 wiphy = wlan_hdd_cfg80211_init(sizeof(hdd_context_t)) ;
3366
3367 if(wiphy == NULL)
3368 {
3369 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08003370 return -EIO;
Jeff Johnson295189b2012-06-20 16:38:30 -07003371 }
3372
3373 pHddCtx = wiphy_priv(wiphy);
3374
3375#else
3376
3377 pHddCtx = vos_mem_malloc ( sizeof( hdd_context_t ) );
3378 if(pHddCtx == NULL)
3379 {
3380 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08003381 return -ENOMEM;
Jeff Johnson295189b2012-06-20 16:38:30 -07003382 }
3383
3384#endif
3385 //Initialize the adapter context to zeros.
3386 vos_mem_zero(pHddCtx, sizeof( hdd_context_t ));
3387
3388#ifdef CONFIG_CFG80211
3389 pHddCtx->wiphy = wiphy;
3390#endif
3391 hdd_prevent_suspend();
3392 pHddCtx->isLoadUnloadInProgress = TRUE;
3393
3394 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE);
3395
3396 /*Get vos context here bcoz vos_open requires it*/
3397 pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
3398
3399 //Save the Global VOSS context in adapter context for future.
3400 pHddCtx->pvosContext = pVosContext;
3401
3402 //Save the adapter context in global context for future.
3403 ((VosContextType*)(pVosContext))->pHDDContext = (v_VOID_t*)pHddCtx;
3404
3405#ifdef ANI_BUS_TYPE_SDIO
3406 // Set the private data for the device to our adapter.
3407 libra_sdio_setprivdata (sdio_func_dev, pHddCtx);
3408 atomic_set(&pHddCtx->sdio_claim_count, 0);
3409#endif // ANI_BUS_TYPE_SDIO
3410
3411 pHddCtx->parent_dev = dev;
3412
3413 init_completion(&pHddCtx->full_pwr_comp_var);
3414 init_completion(&pHddCtx->standby_comp_var);
3415 init_completion(&pHddCtx->req_bmps_comp_var);
Madan Mohan Koyyalamudi2a1ba772012-10-11 14:59:06 -07003416 init_completion(&pHddCtx->scan_info.scan_req_completion_event);
Madan Mohan Koyyalamudif4e81002012-11-13 10:46:38 -08003417 init_completion(&pHddCtx->scan_info.abortscan_event_var);
Jeff Johnson295189b2012-06-20 16:38:30 -07003418
3419 hdd_list_init( &pHddCtx->hddAdapters, MAX_NUMBER_OF_ADAPTERS );
3420
3421 // Load all config first as TL config is needed during vos_open
3422 pHddCtx->cfg_ini = (hdd_config_t*) kmalloc(sizeof(hdd_config_t), GFP_KERNEL);
3423 if(pHddCtx->cfg_ini == NULL)
3424 {
3425 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed kmalloc hdd_config_t",__func__);
3426 goto err_free_hdd_context;
3427 }
3428
3429 vos_mem_zero(pHddCtx->cfg_ini, sizeof( hdd_config_t ));
3430
3431 // Read and parse the qcom_cfg.ini file
3432 status = hdd_parse_config_ini( pHddCtx );
3433 if ( VOS_STATUS_SUCCESS != status )
3434 {
3435 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: error parsing %s",
3436 __func__, WLAN_INI_FILE);
3437 goto err_config;
3438 }
3439
3440#ifdef CONFIG_CFG80211
3441 /*
3442 * cfg80211: Initialization and registration ...
3443 */
3444 if (0 < wlan_hdd_cfg80211_register(dev, wiphy, pHddCtx->cfg_ini))
3445 {
3446 hddLog(VOS_TRACE_LEVEL_FATAL,
3447 "%s: wlan_hdd_cfg80211_register return failure", __func__);
3448 goto err_wiphy_reg;
3449 }
3450#endif
3451
3452#ifdef FEATURE_WLAN_INTEGRATED_SOC
3453 // Update WDI trace levels based upon the cfg.ini
3454 hdd_wdi_trace_enable(eWLAN_MODULE_DAL,
3455 pHddCtx->cfg_ini->wdiTraceEnableDAL);
3456 hdd_wdi_trace_enable(eWLAN_MODULE_DAL_CTRL,
3457 pHddCtx->cfg_ini->wdiTraceEnableCTL);
3458 hdd_wdi_trace_enable(eWLAN_MODULE_DAL_DATA,
3459 pHddCtx->cfg_ini->wdiTraceEnableDAT);
3460 hdd_wdi_trace_enable(eWLAN_MODULE_PAL,
3461 pHddCtx->cfg_ini->wdiTraceEnablePAL);
3462#endif /* FEATURE_WLAN_INTEGRATED_SOC */
3463
3464#ifdef ANI_MANF_DIAG
3465 if(VOS_FTM_MODE == hdd_get_conparam())
3466 {
3467 if ( VOS_STATUS_SUCCESS != wlan_hdd_ftm_open(pHddCtx) )
3468 {
3469 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: wlan_hdd_ftm_open Failed",__func__);
3470 goto err_free_hdd_context;
3471 }
3472 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: FTM driver loaded success fully",__func__);
3473 return VOS_STATUS_SUCCESS;
3474 }
3475#endif
3476
3477 //Open watchdog module
3478 if(pHddCtx->cfg_ini->fIsLogpEnabled)
3479 {
3480 status = vos_watchdog_open(pVosContext,
3481 &((VosContextType*)pVosContext)->vosWatchdog, sizeof(VosWatchdogContext));
3482
3483 if(!VOS_IS_STATUS_SUCCESS( status ))
3484 {
3485 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_watchdog_open failed",__func__);
3486#ifdef CONFIG_CFG80211
3487 goto err_wiphy_reg;
3488#else
3489 goto err_config;
3490#endif
3491 }
3492 }
3493
3494 pHddCtx->isLogpInProgress = FALSE;
3495 vos_set_logp_in_progress(VOS_MODULE_ID_VOSS, FALSE);
3496
3497#ifdef ANI_BUS_TYPE_SDIO
3498 status = WLANBAL_Open(pHddCtx->pvosContext);
3499 if(!VOS_IS_STATUS_SUCCESS(status))
3500 {
3501 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3502 "%s: Failed to open BAL",__func__);
3503 goto err_wdclose;
3504 }
3505#endif // ANI_BUS_TYPE_SDIO
3506
3507 status = vos_chipVoteOnXOBuffer(NULL, NULL, NULL);
3508 if(!VOS_IS_STATUS_SUCCESS(status))
3509 {
3510 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Failed to configure 19.2 MHz Clock", __func__);
3511#ifdef ANI_BUS_TYPE_SDIO
3512 goto err_balclose;
3513#else
3514 goto err_wdclose;
3515#endif
3516 }
3517
3518
3519#ifdef ANI_BUS_TYPE_SDIO
3520 status = WLANSAL_Start(pHddCtx->pvosContext);
3521 if (!VOS_IS_STATUS_SUCCESS(status))
3522 {
3523 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Failed to start SAL",__func__);
3524 goto err_clkvote;
3525 }
3526
3527 /* Start BAL */
3528 status = WLANBAL_Start(pHddCtx->pvosContext);
3529
3530 if (!VOS_IS_STATUS_SUCCESS(status))
3531 {
3532 VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3533 "%s: Failed to start BAL",__func__);
3534 goto err_salstop;
3535 }
3536#endif // ANI_BUS_TYPE_SDIO
3537
3538#ifdef MSM_PLATFORM_7x30
3539 /* FIXME: Volans 2.0 configuration. Reconfigure 1.3v SW supply to 1.3v. It will be configured to
3540 * 1.4v in vos_ChipPowerup() routine above
3541 */
3542#endif
3543
3544 status = vos_open( &pVosContext, 0);
3545 if ( !VOS_IS_STATUS_SUCCESS( status ))
3546 {
3547 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_open failed",__func__);
3548 goto err_balstop;
3549 }
3550
3551 /* Save the hal context in Adapter */
3552 pHddCtx->hHal = (tHalHandle)vos_get_context( VOS_MODULE_ID_SME, pVosContext );
3553
3554 if ( NULL == pHddCtx->hHal )
3555 {
3556 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: HAL context is null",__func__);
3557 goto err_vosclose;
3558 }
3559
Jeff Johnsone7245742012-09-05 17:12:55 -07003560#ifdef FEATURE_WLAN_INTEGRATED_SOC
3561 /* Vos preStart is calling */
3562 /* vos preStart which does cfg download should be called before set sme config which accesses/sets some cfgs */
3563 status = vos_preStart( pHddCtx->pvosContext );
3564 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3565 {
3566 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_preStart failed",__func__);
3567 goto err_vosclose;
3568 }
3569#endif
3570
Jeff Johnson295189b2012-06-20 16:38:30 -07003571 // Set the SME configuration parameters...
3572 status = hdd_set_sme_config( pHddCtx );
3573
3574 if ( VOS_STATUS_SUCCESS != status )
3575 {
3576 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed hdd_set_sme_config",__func__);
3577 goto err_vosclose;
3578 }
3579
3580 //Initialize the WMM module
3581 status = hdd_wmm_init(pHddCtx);
3582 if (!VOS_IS_STATUS_SUCCESS(status))
3583 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003584 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: hdd_wmm_init failed", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07003585 goto err_vosclose;
3586 }
3587
3588#ifdef FEATURE_WLAN_INTEGRATED_SOC
Jeff Johnson295189b2012-06-20 16:38:30 -07003589 /* In the integrated architecture we update the configuration from
3590 the INI file and from NV before vOSS has been started so that
3591 the final contents are available to send down to the cCPU */
3592
3593 // Apply the cfg.ini to cfg.dat
3594 if (FALSE == hdd_update_config_dat(pHddCtx))
3595 {
3596 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: config update failed",__func__ );
3597 goto err_vosclose;
3598 }
3599
3600 // Apply the NV to cfg.dat
3601 /* Prima Update MAC address only at here */
3602 if (VOS_STATUS_SUCCESS != hdd_update_config_from_nv(pHddCtx))
3603 {
3604#ifdef WLAN_AUTOGEN_MACADDR_FEATURE
3605 /* There was not a valid set of MAC Addresses in NV. See if the
3606 default addresses were modified by the cfg.ini settings. If so,
3607 we'll use them, but if not, we'll autogenerate a set of MAC
3608 addresses based upon the device serial number */
3609
3610 static const v_MACADDR_t default_address =
3611 {{0x00, 0x0A, 0xF5, 0x89, 0x89, 0xFF}};
3612 unsigned int serialno;
3613 int i;
3614
3615 serialno = wcnss_get_serial_number();
3616 if ((0 != serialno) &&
3617 (0 == memcmp(&default_address, &pHddCtx->cfg_ini->intfMacAddr[0],
3618 sizeof(default_address))))
3619 {
3620 /* cfg.ini has the default address, invoke autogen logic */
3621
3622 /* MAC address has 3 bytes of OUI so we have a maximum of 3
3623 bytes of the serial number that can be used to generate
3624 the other 3 bytes of the MAC address. Mask off all but
3625 the lower 3 bytes (this will also make sure we don't
3626 overflow in the next step) */
3627 serialno &= 0x00FFFFFF;
3628
3629 /* we need a unique address for each session */
3630 serialno *= VOS_MAX_CONCURRENCY_PERSONA;
3631
3632 /* autogen all addresses */
3633 for (i = 0; i < VOS_MAX_CONCURRENCY_PERSONA; i++)
3634 {
3635 /* start with the entire default address */
3636 pHddCtx->cfg_ini->intfMacAddr[i] = default_address;
3637 /* then replace the lower 3 bytes */
3638 pHddCtx->cfg_ini->intfMacAddr[i].bytes[3] = (serialno >> 16) & 0xFF;
3639 pHddCtx->cfg_ini->intfMacAddr[i].bytes[4] = (serialno >> 8) & 0xFF;
3640 pHddCtx->cfg_ini->intfMacAddr[i].bytes[5] = serialno & 0xFF;
3641
3642 serialno++;
3643 }
3644
3645 pr_info("wlan: Invalid MAC addresses in NV, autogenerated "
3646 MAC_ADDRESS_STR,
3647 MAC_ADDR_ARRAY(pHddCtx->cfg_ini->intfMacAddr[0].bytes));
3648 }
3649 else
3650#endif //WLAN_AUTOGEN_MACADDR_FEATURE
3651 {
3652 hddLog(VOS_TRACE_LEVEL_ERROR,
3653 "%s: Invalid MAC address in NV, using MAC from ini file "
3654 MAC_ADDRESS_STR, __func__,
3655 MAC_ADDR_ARRAY(pHddCtx->cfg_ini->intfMacAddr[0].bytes));
3656 }
3657 }
3658 {
3659 eHalStatus halStatus;
3660 // Set the MAC Address
3661 // Currently this is used by HAL to add self sta. Remove this once self sta is added as part of session open.
3662 halStatus = cfgSetStr( pHddCtx->hHal, WNI_CFG_STA_ID,
3663 (v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[0],
3664 sizeof( pHddCtx->cfg_ini->intfMacAddr[0]) );
3665
3666 if (!HAL_STATUS_SUCCESS( halStatus ))
3667 {
3668 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed to set MAC Address. "
3669 "HALStatus is %08d [x%08x]",__func__, halStatus, halStatus );
3670 return VOS_STATUS_E_FAILURE;
3671 }
3672 }
3673#endif // FEATURE_WLAN_INTEGRATED_SOC
3674
3675 /*Start VOSS which starts up the SME/MAC/HAL modules and everything else
3676 Note: Firmware image will be read and downloaded inside vos_start API */
3677 status = vos_start( pHddCtx->pvosContext );
3678 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3679 {
3680 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: vos_start failed",__func__);
3681 goto err_vosclose;
3682 }
3683
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003684 /* Exchange capability info between Host and FW and also get versioning info from FW */
3685 hdd_exchange_version_and_caps(pHddCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -07003686
3687 status = hdd_post_voss_start_config( pHddCtx );
3688 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3689 {
3690 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hdd_post_voss_start_config failed",
3691 __func__);
3692 goto err_vosstop;
3693 }
3694
3695#ifdef WLAN_SOFTAP_FEATURE
3696 if (VOS_STA_SAP_MODE == hdd_get_conparam())
3697 {
3698 pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_SOFTAP, "softap.%d",
3699 wlan_hdd_get_intf_addr(pHddCtx), FALSE );
3700 }
3701 else
3702 {
3703#endif
3704 pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_INFRA_STATION, "wlan%d",
3705 wlan_hdd_get_intf_addr(pHddCtx), FALSE );
3706 if (pAdapter != NULL)
3707 {
3708#ifdef WLAN_FEATURE_P2P
Madan Mohan Koyyalamudiedfc1b72012-10-18 20:25:55 -07003709 tANI_U8* p2p_dev_addr = wlan_hdd_get_intf_addr(pHddCtx);
3710 if (p2p_dev_addr != NULL)
Jeff Johnson295189b2012-06-20 16:38:30 -07003711 {
Madan Mohan Koyyalamudiedfc1b72012-10-18 20:25:55 -07003712 vos_mem_copy(&pHddCtx->p2pDeviceAddress.bytes[0],
3713 p2p_dev_addr, VOS_MAC_ADDR_SIZE);
3714
3715 if ( pHddCtx->cfg_ini->isP2pDeviceAddrAdministrated )
3716 {
3717 /* Generate the P2P Device Address. This consists of the device's
3718 * primary MAC address with the locally administered bit set.
3719 */
3720 pHddCtx->p2pDeviceAddress.bytes[0] |= 0x02;
3721 }
Jeff Johnsone7245742012-09-05 17:12:55 -07003722 }
3723 else
3724 {
Madan Mohan Koyyalamudiedfc1b72012-10-18 20:25:55 -07003725 hddLog(VOS_TRACE_LEVEL_FATAL,
3726 "%s: Failed to allocate mac_address for p2p_device",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003727 __func__);
Madan Mohan Koyyalamudiedfc1b72012-10-18 20:25:55 -07003728 goto err_close_adapter;
Jeff Johnson295189b2012-06-20 16:38:30 -07003729 }
Jeff Johnsone7245742012-09-05 17:12:55 -07003730
3731 pP2pAdapter = hdd_open_adapter( pHddCtx, WLAN_HDD_P2P_DEVICE, "p2p%d",
3732 &pHddCtx->p2pDeviceAddress.bytes[0], FALSE );
3733 if ( NULL == pP2pAdapter )
3734 {
3735 hddLog(VOS_TRACE_LEVEL_FATAL,
3736 "%s: Failed to do hdd_open_adapter for P2P Device Interface",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003737 __func__);
Jeff Johnsone7245742012-09-05 17:12:55 -07003738 goto err_close_adapter;
3739 }
Jeff Johnson295189b2012-06-20 16:38:30 -07003740#endif
Jeff Johnsone7245742012-09-05 17:12:55 -07003741 }
Jeff Johnson295189b2012-06-20 16:38:30 -07003742#ifdef WLAN_SOFTAP_FEATURE
3743 }
3744#endif
3745
3746 if( pAdapter == NULL )
3747 {
3748 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: hdd_open_adapter failed",__func__);
3749#ifdef ANI_BUS_TYPE_SDIO
3750 goto err_balstop;
3751#else
3752 goto err_clkvote;
3753#endif
3754 }
Jeff Johnsone7245742012-09-05 17:12:55 -07003755
Jeff Johnson295189b2012-06-20 16:38:30 -07003756#ifdef WLAN_BTAMP_FEATURE
3757 vStatus = WLANBAP_Open(pVosContext);
3758 if(!VOS_IS_STATUS_SUCCESS(vStatus))
3759 {
3760 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3761 "%s: Failed to open BAP",__func__);
Jeff Johnsone7245742012-09-05 17:12:55 -07003762 goto err_close_adapter;
Jeff Johnson295189b2012-06-20 16:38:30 -07003763 }
3764
3765 vStatus = BSL_Init(pVosContext);
3766 if(!VOS_IS_STATUS_SUCCESS(vStatus))
3767 {
3768 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3769 "%s: Failed to Init BSL",__func__);
3770 goto err_bap_close;
3771 }
3772 vStatus = WLANBAP_Start(pVosContext);
3773 if (!VOS_IS_STATUS_SUCCESS(vStatus))
3774 {
3775 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
3776 "%s: Failed to start TL",__func__);
3777 goto err_bap_close;
3778 }
3779
3780 pConfig = pHddCtx->cfg_ini;
3781 btAmpConfig.ucPreferredChannel = pConfig->preferredChannel;
3782 status = WLANBAP_SetConfig(&btAmpConfig);
3783
3784#endif //WLAN_BTAMP_FEATURE
Jeff Johnsone7245742012-09-05 17:12:55 -07003785
Jeff Johnson295189b2012-06-20 16:38:30 -07003786#ifdef FEATURE_WLAN_SCAN_PNO
3787 /*SME must send channel update configuration to RIVA*/
3788 sme_UpdateChannelConfig(pHddCtx->hHal);
3789#endif
3790
3791#ifdef FEATURE_WLAN_INTEGRATED_SOC
3792 /* Register with platform driver as client for Suspend/Resume */
3793 status = hddRegisterPmOps(pHddCtx);
3794 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3795 {
3796 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddRegisterPmOps failed",__func__);
3797#ifdef WLAN_BTAMP_FEATURE
3798 goto err_bap_stop;
3799#else
Jeff Johnsone7245742012-09-05 17:12:55 -07003800 goto err_close_adapter;
Jeff Johnson295189b2012-06-20 16:38:30 -07003801#endif //WLAN_BTAMP_FEATURE
3802 }
3803
3804 /* Register TM level change handler function to the platform */
3805 status = hddDevTmRegisterNotifyCallback(pHddCtx);
3806 if ( !VOS_IS_STATUS_SUCCESS( status ) )
3807 {
3808 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDevTmRegisterNotifyCallback failed",__func__);
3809 goto err_unregister_pmops;
3810 }
3811#endif
3812
3813 /* register for riva power on lock to platform driver */
3814 if (req_riva_power_on_lock("wlan"))
3815 {
3816 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: req riva power on lock failed",
3817 __func__);
3818 goto err_unregister_pmops;
3819 }
3820
3821#ifdef CONFIG_HAS_EARLYSUSPEND
3822 // Register suspend/resume callbacks
3823 if(pHddCtx->cfg_ini->nEnableSuspend)
3824 {
3825 register_wlan_suspend();
3826 }
3827#endif
3828
3829 // register net device notifier for device change notification
3830 ret = register_netdevice_notifier(&hdd_netdev_notifier);
3831
3832 if(ret < 0)
3833 {
3834 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: register_netdevice_notifier failed",__func__);
3835 goto err_free_power_on_lock;
3836 }
3837
3838 //Initialize the nlink service
3839 if(nl_srv_init() != 0)
3840 {
3841 hddLog(VOS_TRACE_LEVEL_FATAL,"%S: nl_srv_init failed",__func__);
3842 goto err_reg_netdev;
3843 }
3844
3845 //Initialize the BTC service
3846 if(btc_activate_service(pHddCtx) != 0)
3847 {
3848 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: btc_activate_service failed",__func__);
3849 goto err_nl_srv;
3850 }
3851
3852#ifdef PTT_SOCK_SVC_ENABLE
3853 //Initialize the PTT service
3854 if(ptt_sock_activate_svc(pHddCtx) != 0)
3855 {
3856 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: ptt_sock_activate_svc failed",__func__);
3857 goto err_nl_srv;
3858 }
3859#endif
3860
Jeff Johnson295189b2012-06-20 16:38:30 -07003861#ifdef CONFIG_HAS_EARLYSUSPEND
3862 hdd_register_mcast_bcast_filter(pHddCtx);
3863#endif
3864#ifdef CONFIG_CFG80211
3865#ifdef WLAN_SOFTAP_FEATURE
3866 if (VOS_STA_SAP_MODE != hdd_get_conparam())
3867#endif
3868 {
Madan Mohan Koyyalamudic537df22012-10-22 15:07:08 -07003869 /* Action frame registered in one adapter which will
3870 * applicable to all interfaces
3871 */
Madan Mohan Koyyalamudie233e292012-09-18 17:38:02 -07003872 wlan_hdd_cfg80211_post_voss_start(pAdapter);
Jeff Johnson295189b2012-06-20 16:38:30 -07003873 }
3874#endif
3875
3876 mutex_init(&pHddCtx->sap_lock);
3877
3878 pHddCtx->isLoadUnloadInProgress = FALSE;
3879
Jeff Johnsone7245742012-09-05 17:12:55 -07003880#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
3881 /* Initialize the wake lcok */
3882 wake_lock_init(&pHddCtx->rx_wake_lock,
3883 WAKE_LOCK_SUSPEND,
3884 "qcom_rx_wakelock");
3885#endif
3886
Madan Mohan Koyyalamudi2a1ba772012-10-11 14:59:06 -07003887 vos_event_init(&pHddCtx->scan_info.scan_finished_event);
3888 pHddCtx->scan_info.scan_pending_option = WEXT_SCAN_PENDING_GIVEUP;
Jeff Johnson295189b2012-06-20 16:38:30 -07003889
3890 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, FALSE);
3891 hdd_allow_suspend();
Jeff Johnsone7245742012-09-05 17:12:55 -07003892
3893 // Initialize the restart logic
3894 wlan_hdd_restart_init(pHddCtx);
Jeff Johnson295189b2012-06-20 16:38:30 -07003895
3896 goto success;
3897
3898err_nl_srv:
3899 nl_srv_exit();
3900
3901err_reg_netdev:
3902 unregister_netdevice_notifier(&hdd_netdev_notifier);
3903
3904err_free_power_on_lock:
3905 free_riva_power_on_lock("wlan");
3906
3907err_unregister_pmops:
3908 hddDevTmUnregisterNotifyCallback(pHddCtx);
3909 hddDeregisterPmOps(pHddCtx);
3910
3911#ifdef WLAN_BTAMP_FEATURE
3912err_bap_stop:
3913 WLANBAP_Stop(pVosContext);
3914#endif
3915
3916#ifdef WLAN_BTAMP_FEATURE
3917err_bap_close:
3918 WLANBAP_Close(pVosContext);
3919#endif
3920
Jeff Johnson295189b2012-06-20 16:38:30 -07003921err_close_adapter:
3922 hdd_close_all_adapters( pHddCtx );
3923
3924err_vosstop:
3925 vos_stop(pVosContext);
3926
3927err_vosclose:
3928 status = vos_sched_close( pVosContext );
3929 if (!VOS_IS_STATUS_SUCCESS(status)) {
3930 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
3931 "%s: Failed to close VOSS Scheduler", __func__);
3932 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status ) );
3933 }
3934 vos_close(pVosContext );
3935
3936err_balstop:
3937#ifdef ANI_BUS_TYPE_SDIO
3938#ifndef ANI_MANF_DIAG
3939 wlan_hdd_enable_deepsleep(pHddCtx->pvosContext);
3940#endif
3941
3942 WLANBAL_Stop(pHddCtx->pvosContext);
3943 WLANBAL_SuspendChip(pHddCtx->pvosContext);
3944#endif
3945
3946#ifdef ANI_BUS_TYPE_SDIO
3947err_salstop:
3948 WLANSAL_Stop(pHddCtx->pvosContext);
3949
3950#endif
3951err_clkvote:
3952 vos_chipVoteOffXOBuffer(NULL, NULL, NULL);
3953
3954#ifdef ANI_BUS_TYPE_SDIO
3955err_balclose:
3956 WLANBAL_Close(pHddCtx->pvosContext);
3957#endif // ANI_BUS_TYPE_SDIO
3958
3959err_wdclose:
3960 if(pHddCtx->cfg_ini->fIsLogpEnabled)
3961 vos_watchdog_close(pVosContext);
3962
3963#ifdef CONFIG_CFG80211
3964err_wiphy_reg:
3965 wiphy_unregister(wiphy) ;
3966#endif
3967
3968err_config:
3969 kfree(pHddCtx->cfg_ini);
3970 pHddCtx->cfg_ini= NULL;
3971
3972err_free_hdd_context:
3973 hdd_allow_suspend();
3974#ifdef CONFIG_CFG80211
3975 wiphy_free(wiphy) ;
3976 //kfree(wdev) ;
3977#else
3978 vos_mem_free( pHddCtx );
3979#endif
3980 VOS_BUG(1);
3981
Madan Mohan Koyyalamudid57ae632012-11-06 18:42:48 -08003982 if (hdd_is_ssr_required())
3983 {
3984 /* WDI timeout had happened during load, so SSR is needed here */
3985 subsystem_restart("wcnss");
3986 msleep(5000);
3987 }
3988 hdd_set_ssr_required (VOS_FALSE);
3989
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08003990 return -EIO;
Jeff Johnson295189b2012-06-20 16:38:30 -07003991
3992success:
3993 EXIT();
3994 return 0;
3995}
3996
3997/**---------------------------------------------------------------------------
3998
Jeff Johnson32d95a32012-09-10 13:15:23 -07003999 \brief hdd_driver_init() - Core Driver Init Function
Jeff Johnson295189b2012-06-20 16:38:30 -07004000
Jeff Johnson32d95a32012-09-10 13:15:23 -07004001 This is the driver entry point - called in different timeline depending
4002 on whether the driver is statically or dynamically linked
Jeff Johnson295189b2012-06-20 16:38:30 -07004003
4004 \param - None
4005
4006 \return - 0 for success, non zero for failure
4007
4008 --------------------------------------------------------------------------*/
Jeff Johnson32d95a32012-09-10 13:15:23 -07004009static int hdd_driver_init( void)
Jeff Johnson295189b2012-06-20 16:38:30 -07004010{
4011 VOS_STATUS status;
4012 v_CONTEXT_t pVosContext = NULL;
4013#ifdef ANI_BUS_TYPE_SDIO
4014 struct sdio_func *sdio_func_dev = NULL;
4015 unsigned int attempts = 0;
4016#endif // ANI_BUS_TYPE_SDIO
4017 struct device *dev = NULL;
4018 int ret_status = 0;
4019
4020 ENTER();
4021
Jeff Johnsone7245742012-09-05 17:12:55 -07004022#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07004023 wake_lock_init(&wlan_wake_lock, WAKE_LOCK_SUSPEND, "wlan");
Jeff Johnsone7245742012-09-05 17:12:55 -07004024#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004025
4026 pr_info("%s: loading driver v%s\n", WLAN_MODULE_NAME,
4027 QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR);
4028
4029 //Power Up Libra WLAN card first if not already powered up
4030 status = vos_chipPowerUp(NULL,NULL,NULL);
4031 if (!VOS_IS_STATUS_SUCCESS(status))
4032 {
4033 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN not Powered Up. "
4034 "exiting", __func__);
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08004035 return -EIO;
Jeff Johnson295189b2012-06-20 16:38:30 -07004036 }
4037
4038#ifdef ANI_BUS_TYPE_SDIO
4039 //SDIO Polling should be turned on for card detection. When using Android Wi-Fi GUI
4040 //users need not trigger SDIO polling explicitly. However when loading drivers via
4041 //command line (Adb shell), users must turn on SDIO polling prior to loading WLAN.
4042 do {
4043 sdio_func_dev = libra_getsdio_funcdev();
4044 if (NULL == sdio_func_dev) {
4045 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN not detected yet.",__func__);
4046 attempts++;
4047 }
4048 else {
4049 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Libra WLAN detecton succeeded",__func__);
4050 dev = &sdio_func_dev->dev;
4051 break;
4052 }
4053
4054 if(attempts == 7)
4055 break;
4056
4057 msleep(250);
4058
4059 }while (attempts < 7);
4060
4061 //Retry to detect the card again by Powering Down the chip and Power up the chip
4062 //again. This retry is done to recover from CRC Error
4063 if (NULL == sdio_func_dev) {
4064
4065 attempts = 0;
4066
4067 //Vote off any PMIC voltage supplies
4068 vos_chipPowerDown(NULL, NULL, NULL);
4069
4070 msleep(1000);
4071
4072 //Power Up Libra WLAN card first if not already powered up
4073 status = vos_chipPowerUp(NULL,NULL,NULL);
4074 if (!VOS_IS_STATUS_SUCCESS(status))
4075 {
4076 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN not Powered Up. "
4077 "exiting", __func__);
Madan Mohan Koyyalamudicae253a2012-11-06 19:10:35 -08004078 return -EIO;
Jeff Johnson295189b2012-06-20 16:38:30 -07004079 }
4080
4081 do {
4082 sdio_func_dev = libra_getsdio_funcdev();
4083 if (NULL == sdio_func_dev) {
4084 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN not detected yet.",__func__);
4085 attempts++;
4086 }
4087 else {
4088 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Retry Libra WLAN detecton succeeded",__func__);
4089 dev = &sdio_func_dev->dev;
4090 break;
4091 }
4092
4093 if(attempts == 2)
4094 break;
4095
4096 msleep(1000);
4097
4098 }while (attempts < 3);
4099 }
4100
4101#endif // ANI_BUS_TYPE_SDIO
4102
4103#ifdef ANI_BUS_TYPE_PCI
4104
4105 dev = wcnss_wlan_get_device();
4106
4107#endif // ANI_BUS_TYPE_PCI
4108
4109#ifdef ANI_BUS_TYPE_PLATFORM
4110 dev = wcnss_wlan_get_device();
4111#endif // ANI_BUS_TYPE_PLATFORM
4112
4113
4114 do {
4115 if (NULL == dev) {
4116 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: WLAN device not found!!",__func__);
4117 ret_status = -1;
4118 break;
4119 }
4120
4121#ifdef MEMORY_DEBUG
4122 vos_mem_init();
4123#endif
4124
4125#ifdef TIMER_MANAGER
4126 vos_timer_manager_init();
4127#endif
4128
4129 /* Preopen VOSS so that it is ready to start at least SAL */
4130 status = vos_preOpen(&pVosContext);
4131
4132 if (!VOS_IS_STATUS_SUCCESS(status))
4133 {
4134 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed to preOpen VOSS", __func__);
4135 ret_status = -1;
4136 break;
4137 }
4138
4139#ifdef ANI_BUS_TYPE_SDIO
4140 /* Now Open SAL */
4141 status = WLANSAL_Open(pVosContext, 0);
4142
4143 if(!VOS_IS_STATUS_SUCCESS(status))
4144 {
4145 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Failed to open SAL", __func__);
4146
4147 /* If unable to open, cleanup and return failure */
4148 vos_preClose( &pVosContext );
4149 ret_status = -1;
4150 break;
4151 }
4152#endif // ANI_BUS_TYPE_SDIO
4153
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004154#ifndef MODULE
4155 /* For statically linked driver, call hdd_set_conparam to update curr_con_mode
4156 */
4157 hdd_set_conparam((v_UINT_t)con_mode);
4158#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004159
4160 // Call our main init function
4161 if(hdd_wlan_startup(dev)) {
4162 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: WLAN Driver Initialization failed",
4163 __func__);
4164#ifdef ANI_BUS_TYPE_SDIO
4165 WLANSAL_Close(pVosContext);
4166#endif // ANI_BUS_TYPE_SDIO
4167 vos_preClose( &pVosContext );
4168 ret_status = -1;
4169 break;
4170 }
4171
4172 /* Cancel the vote for XO Core ON
4173 * This is done here for safety purposes in case we re-initialize without turning
4174 * it OFF in any error scenario.
4175 */
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004176 hddLog(VOS_TRACE_LEVEL_INFO, "In module init: Ensure Force XO Core is OFF"
Jeff Johnson295189b2012-06-20 16:38:30 -07004177 " when WLAN is turned ON so Core toggles"
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004178 " unless we enter PSD");
Jeff Johnson295189b2012-06-20 16:38:30 -07004179 if (vos_chipVoteXOCore(NULL, NULL, NULL, VOS_FALSE) != VOS_STATUS_SUCCESS)
4180 {
4181 hddLog(VOS_TRACE_LEVEL_ERROR, "Could not cancel XO Core ON vote. Not returning failure."
4182 " Power consumed will be high\n");
4183 }
4184 } while (0);
4185
4186 if (0 != ret_status)
4187 {
4188 //Assert Deep sleep signal now to put Libra HW in lowest power state
4189 status = vos_chipAssertDeepSleep( NULL, NULL, NULL );
4190 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( status) );
4191
4192 //Vote off any PMIC voltage supplies
4193 vos_chipPowerDown(NULL, NULL, NULL);
4194#ifdef TIMER_MANAGER
4195 vos_timer_exit();
4196#endif
4197#ifdef MEMORY_DEBUG
4198 vos_mem_exit();
4199#endif
4200
Jeff Johnsone7245742012-09-05 17:12:55 -07004201#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07004202 wake_lock_destroy(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07004203#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004204 pr_err("%s: driver load failure\n", WLAN_MODULE_NAME);
4205 }
4206 else
4207 {
4208 //Send WLAN UP indication to Nlink Service
4209 send_btc_nlink_msg(WLAN_MODULE_UP_IND, 0);
4210
4211 pr_info("%s: driver loaded\n", WLAN_MODULE_NAME);
4212
4213 }
4214
4215 EXIT();
4216
4217 return ret_status;
4218}
4219
Jeff Johnson32d95a32012-09-10 13:15:23 -07004220/**---------------------------------------------------------------------------
4221
4222 \brief hdd_module_init() - Init Function
4223
4224 This is the driver entry point (invoked when module is loaded using insmod)
4225
4226 \param - None
4227
4228 \return - 0 for success, non zero for failure
4229
4230 --------------------------------------------------------------------------*/
4231#ifdef MODULE
4232static int __init hdd_module_init ( void)
4233{
4234 return hdd_driver_init();
4235}
Jeff Johnson32d95a32012-09-10 13:15:23 -07004236#else /* #ifdef MODULE */
4237static int __init hdd_module_init ( void)
4238{
4239 /* Driver initialization is delayed to fwpath_changed_handler */
4240 return 0;
4241}
Jeff Johnson32d95a32012-09-10 13:15:23 -07004242#endif /* #ifdef MODULE */
4243
Jeff Johnson295189b2012-06-20 16:38:30 -07004244
4245/**---------------------------------------------------------------------------
4246
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004247 \brief hdd_driver_exit() - Exit function
Jeff Johnson295189b2012-06-20 16:38:30 -07004248
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004249 This is the driver exit point (invoked when module is unloaded using rmmod
4250 or con_mode was changed by userspace)
Jeff Johnson295189b2012-06-20 16:38:30 -07004251
4252 \param - None
4253
4254 \return - None
4255
4256 --------------------------------------------------------------------------*/
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004257static void hdd_driver_exit(void)
Jeff Johnson295189b2012-06-20 16:38:30 -07004258{
4259 hdd_context_t *pHddCtx = NULL;
4260 v_CONTEXT_t pVosContext = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07004261
4262 pr_info("%s: unloading driver v%s\n", WLAN_MODULE_NAME, QWLAN_VERSIONSTR);
4263
4264 //Get the global vos context
4265 pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
4266
4267 if(!pVosContext)
4268 {
4269 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: Global VOS context is Null", __func__);
4270 goto done;
4271 }
4272
4273 //Get the HDD context.
4274 pHddCtx = (hdd_context_t *)vos_get_context(VOS_MODULE_ID_HDD, pVosContext );
4275
4276 if(!pHddCtx)
4277 {
4278 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: module exit called before probe",__func__);
4279 }
4280 else
4281 {
Jeff Johnsone7245742012-09-05 17:12:55 -07004282 /* module exit should never proceed if SSR is not completed */
Jeff Johnson295189b2012-06-20 16:38:30 -07004283 while(isWDresetInProgress()){
Jeff Johnsone7245742012-09-05 17:12:55 -07004284 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s:SSR in Progress; block rmmod for 1 second!!!",__func__);
4285 msleep(1000);
Jeff Johnson295189b2012-06-20 16:38:30 -07004286 }
4287
4288 pHddCtx->isLoadUnloadInProgress = TRUE;
4289 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE);
4290
4291 //Do all the cleanup before deregistering the driver
4292 hdd_wlan_exit(pHddCtx);
4293 }
4294
4295#ifdef ANI_BUS_TYPE_SDIO
4296 WLANSAL_Close(pVosContext);
4297#endif // ANI_BUS_TYPE_SDIO
4298
4299 vos_preClose( &pVosContext );
4300
4301#ifdef TIMER_MANAGER
4302 vos_timer_exit();
4303#endif
4304#ifdef MEMORY_DEBUG
4305 vos_mem_exit();
4306#endif
4307
4308done:
Jeff Johnsone7245742012-09-05 17:12:55 -07004309#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07004310 wake_lock_destroy(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07004311#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004312 pr_info("%s: driver unloaded\n", WLAN_MODULE_NAME);
4313}
4314
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004315/**---------------------------------------------------------------------------
4316
4317 \brief hdd_module_exit() - Exit function
4318
4319 This is the driver exit point (invoked when module is unloaded using rmmod)
4320
4321 \param - None
4322
4323 \return - None
4324
4325 --------------------------------------------------------------------------*/
4326static void __exit hdd_module_exit(void)
4327{
4328 hdd_driver_exit();
4329}
4330
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004331#ifdef MODULE
4332static int fwpath_changed_handler(const char *kmessage,
4333 struct kernel_param *kp)
4334{
4335 /* nothing to do when driver is DLKM */
4336 return 0;
4337}
4338
4339static int con_mode_handler(const char *kmessage,
4340 struct kernel_param *kp)
4341{
Madan Mohan Koyyalamudif2f8d8b2012-10-11 17:06:59 -07004342 return param_set_int(kmessage, kp);
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004343}
4344#else /* #ifdef MODULE */
4345/**---------------------------------------------------------------------------
4346
4347 \brief fwpath_changed_handler() - Handler Function
4348
4349 This is the driver entry point
4350 - delayed driver initialization when driver is statically linked
4351 - invoked when module parameter fwpath is modified from userpspace to signal
4352 initializing the WLAN driver
4353
4354 \return - 0 for success, non zero for failure
4355
4356 --------------------------------------------------------------------------*/
4357static int fwpath_changed_handler(const char *kmessage,
4358 struct kernel_param *kp)
4359{
Madan Mohan Koyyalamudi62e60052012-10-05 14:27:22 -07004360 int ret_status;
4361
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004362 if (!wlan_hdd_inited) {
Madan Mohan Koyyalamudi62e60052012-10-05 14:27:22 -07004363 ret_status = hdd_driver_init();
4364 wlan_hdd_inited = ret_status ? 0 : 1;
4365 return ret_status;
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004366 }
4367
4368 hdd_driver_exit();
4369
4370 msleep(200);
4371
Madan Mohan Koyyalamudi62e60052012-10-05 14:27:22 -07004372 ret_status = hdd_driver_init();
4373 wlan_hdd_inited = ret_status ? 0 : 1;
4374 return ret_status;
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004375}
4376
Jeff Johnson295189b2012-06-20 16:38:30 -07004377/**---------------------------------------------------------------------------
4378
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004379 \brief con_mode_handler() -
4380
4381 Handler function for module param con_mode when it is changed by userspace
4382 Dynamically linked - do nothing
4383 Statically linked - exit and init driver, as in rmmod and insmod
4384
4385 \param -
4386
4387 \return -
4388
4389 --------------------------------------------------------------------------*/
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004390static int con_mode_handler(const char *kmessage,
4391 struct kernel_param *kp)
4392{
4393 int ret = param_set_int(kmessage, kp);
4394
4395 if (ret)
4396 return ret;
4397
Madan Mohan Koyyalamudic2ec3bd2012-09-18 19:49:40 -07004398 return fwpath_changed_handler(kmessage, kp);
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004399}
4400#endif /* #ifdef MODULE */
4401
4402/**---------------------------------------------------------------------------
4403
Jeff Johnson295189b2012-06-20 16:38:30 -07004404 \brief hdd_get_conparam() -
4405
4406 This is the driver exit point (invoked when module is unloaded using rmmod)
4407
4408 \param - None
4409
4410 \return - tVOS_CON_MODE
4411
4412 --------------------------------------------------------------------------*/
4413tVOS_CON_MODE hdd_get_conparam ( void )
4414{
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004415#ifdef MODULE
Jeff Johnson295189b2012-06-20 16:38:30 -07004416 return (tVOS_CON_MODE)con_mode;
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004417#else
4418 return (tVOS_CON_MODE)curr_con_mode;
4419#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004420}
4421void hdd_set_conparam ( v_UINT_t newParam )
4422{
4423 con_mode = newParam;
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004424#ifndef MODULE
4425 curr_con_mode = con_mode;
4426#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07004427}
4428/**---------------------------------------------------------------------------
4429
4430 \brief hdd_softap_sta_deauth() - function
4431
4432 This to take counter measure to handle deauth req from HDD
4433
4434 \param - pAdapter - Pointer to the HDD
4435
4436 \param - enable - boolean value
4437
4438 \return - None
4439
4440 --------------------------------------------------------------------------*/
4441
4442void hdd_softap_sta_deauth(hdd_adapter_t *pAdapter, v_U8_t *pDestMacAddress)
4443{
4444 v_U8_t STAId;
4445 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
4446#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
4447 tHalHandle hHalHandle;
4448#endif
4449
4450 ENTER();
4451
4452 hddLog( LOGE, "hdd_softap_sta_deauth:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
4453
4454 //Ignore request to deauth bcmc station
4455 if( pDestMacAddress[0] & 0x1 )
4456 return;
4457
4458 WLANSAP_DeauthSta(pVosContext,pDestMacAddress);
4459
4460 /*Get the Station ID*/
4461#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
4462 hHalHandle = (tHalHandle ) vos_get_context(VOS_MODULE_ID_HAL, pVosContext);
4463 if (eHAL_STATUS_SUCCESS ==
4464 halTable_FindStaidByAddr(hHalHandle, (tANI_U8 *)pDestMacAddress,
4465 &STAId))
4466 {
4467 hdd_softap_DeregisterSTA(pAdapter, STAId);
4468 }
4469#else
4470 if (VOS_STATUS_SUCCESS ==
4471 hdd_softap_GetStaId(pAdapter, (v_MACADDR_t *)pDestMacAddress,
4472 &STAId))
4473 {
4474 hdd_softap_DeregisterSTA(pAdapter, STAId);
4475 }
4476#endif
4477
4478 EXIT();
4479}
4480
4481/**---------------------------------------------------------------------------
4482
4483 \brief hdd_softap_sta_disassoc() - function
4484
4485 This to take counter measure to handle deauth req from HDD
4486
4487 \param - pAdapter - Pointer to the HDD
4488
4489 \param - enable - boolean value
4490
4491 \return - None
4492
4493 --------------------------------------------------------------------------*/
4494
4495void hdd_softap_sta_disassoc(hdd_adapter_t *pAdapter,v_U8_t *pDestMacAddress)
4496{
4497 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
4498
4499 ENTER();
4500
4501 hddLog( LOGE, "hdd_softap_sta_disassoc:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
4502
4503 //Ignore request to disassoc bcmc station
4504 if( pDestMacAddress[0] & 0x1 )
4505 return;
4506
4507 WLANSAP_DisassocSta(pVosContext,pDestMacAddress);
4508}
4509
4510void hdd_softap_tkip_mic_fail_counter_measure(hdd_adapter_t *pAdapter,v_BOOL_t enable)
4511{
4512 v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pAdapter))->pvosContext;
4513
4514 ENTER();
4515
4516 hddLog( LOGE, "hdd_softap_tkip_mic_fail_counter_measure:(0x%x, false)", (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
4517
4518 WLANSAP_SetCounterMeasure(pVosContext, (v_BOOL_t)enable);
4519}
4520
Jeff Johnson295189b2012-06-20 16:38:30 -07004521/**---------------------------------------------------------------------------
4522 *
4523 * \brief hdd_get__concurrency_mode() -
4524 *
4525 *
4526 * \param - None
4527 *
4528 * \return - CONCURRENCY MODE
4529 *
4530 * --------------------------------------------------------------------------*/
4531tVOS_CONCURRENCY_MODE hdd_get_concurrency_mode ( void )
4532{
4533 v_CONTEXT_t pVosContext = vos_get_global_context( VOS_MODULE_ID_HDD, NULL );
4534 hdd_context_t *pHddCtx;
4535
4536 if (NULL != pVosContext)
4537 {
4538 pHddCtx = vos_get_context( VOS_MODULE_ID_HDD, pVosContext);
4539 if (NULL != pHddCtx)
4540 {
4541 return (tVOS_CONCURRENCY_MODE)pHddCtx->concurrency_mode;
4542 }
4543 }
4544
4545 /* we are in an invalid state :( */
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07004546 hddLog(LOGE, "%s: Invalid context", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07004547 return VOS_STA;
4548}
4549
4550/* Decide whether to allow/not the apps power collapse.
4551 * Allow apps power collapse if we are in connected state.
4552 * if not, allow only if we are in IMPS */
4553v_BOOL_t hdd_is_apps_power_collapse_allowed(hdd_context_t* pHddCtx)
4554{
4555 tPmcState pmcState = pmcGetPmcState(pHddCtx->hHal);
4556 hdd_config_t *pConfig = pHddCtx->cfg_ini;
4557 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
4558 hdd_adapter_t *pAdapter = NULL;
4559 VOS_STATUS status;
4560
4561#ifdef WLAN_SOFTAP_FEATURE
4562 if (VOS_STA_SAP_MODE == hdd_get_conparam())
4563 return TRUE;
4564#endif
4565
4566 /*loop through all adapters. TBD fix for Concurrency */
4567 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
4568 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
4569 {
4570 pAdapter = pAdapterNode->pAdapter;
4571 if ( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode)
4572 || (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) )
4573 {
4574 if ((pConfig->fIsImpsEnabled || pConfig->fIsBmpsEnabled)
4575 && (pmcState != IMPS && pmcState != BMPS
4576 && pmcState != STOPPED && pmcState != STANDBY))
4577 {
4578 return FALSE;
4579 }
4580 }
4581 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
4582 pAdapterNode = pNext;
4583 }
4584 return TRUE;
4585}
4586
Madan Mohan Koyyalamudic72a4d62012-11-08 14:59:34 -08004587/* Decides whether to send suspend notification to Riva
4588 * if any adapter is in BMPS; then it is required */
4589v_BOOL_t hdd_is_suspend_notify_allowed(hdd_context_t* pHddCtx)
4590{
4591 tPmcState pmcState = pmcGetPmcState(pHddCtx->hHal);
4592 hdd_config_t *pConfig = pHddCtx->cfg_ini;
4593
4594 if (pConfig->fIsBmpsEnabled && (pmcState == BMPS))
4595 {
4596 return TRUE;
4597 }
4598 return FALSE;
4599}
4600
Jeff Johnson295189b2012-06-20 16:38:30 -07004601void wlan_hdd_set_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
4602{
4603 switch(mode)
4604 {
4605 case WLAN_HDD_INFRA_STATION:
4606#ifdef WLAN_FEATURE_P2P
4607 case WLAN_HDD_P2P_CLIENT:
4608 case WLAN_HDD_P2P_GO:
4609#endif
4610 case WLAN_HDD_SOFTAP:
Jeff Johnsone7245742012-09-05 17:12:55 -07004611 pHddCtx->concurrency_mode |= (1 << mode);
4612 pHddCtx->no_of_sessions[mode]++;
Jeff Johnson295189b2012-06-20 16:38:30 -07004613 break;
4614 default:
4615 break;
4616
4617 }
4618 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
4619 __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
4620}
4621
4622
4623void wlan_hdd_clear_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
4624{
4625 switch(mode)
4626 {
4627 case WLAN_HDD_INFRA_STATION:
4628#ifdef WLAN_FEATURE_P2P
4629 case WLAN_HDD_P2P_CLIENT:
4630 case WLAN_HDD_P2P_GO:
4631#endif
4632 case WLAN_HDD_SOFTAP:
4633 pHddCtx->no_of_sessions[mode]--;
4634 if (!(pHddCtx->no_of_sessions[mode]))
4635 pHddCtx->concurrency_mode &= (~(1 << mode));
4636 break;
4637 default:
4638 break;
4639 }
4640 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
4641 __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
4642}
4643
Jeff Johnsone7245742012-09-05 17:12:55 -07004644/**---------------------------------------------------------------------------
4645 *
4646 * \brief wlan_hdd_restart_init
4647 *
4648 * This function initalizes restart timer/flag. An internal function.
4649 *
4650 * \param - pHddCtx
4651 *
4652 * \return - None
4653 *
4654 * --------------------------------------------------------------------------*/
4655
4656static void wlan_hdd_restart_init(hdd_context_t *pHddCtx)
4657{
4658 /* Initialize */
4659 pHddCtx->hdd_restart_retries = 0;
4660 atomic_set(&pHddCtx->isRestartInProgress, 0);
4661 vos_timer_init(&pHddCtx->hdd_restart_timer,
4662 VOS_TIMER_TYPE_SW,
4663 wlan_hdd_restart_timer_cb,
4664 pHddCtx);
4665}
4666/**---------------------------------------------------------------------------
4667 *
4668 * \brief wlan_hdd_restart_deinit
4669 *
4670 * This function cleans up the resources used. An internal function.
4671 *
4672 * \param - pHddCtx
4673 *
4674 * \return - None
4675 *
4676 * --------------------------------------------------------------------------*/
4677
4678static void wlan_hdd_restart_deinit(hdd_context_t* pHddCtx)
4679{
4680
4681 VOS_STATUS vos_status;
4682 /* Block any further calls */
4683 atomic_set(&pHddCtx->isRestartInProgress, 1);
4684 /* Cleanup */
4685 vos_status = vos_timer_stop( &pHddCtx->hdd_restart_timer );
4686 if (!VOS_IS_STATUS_SUCCESS(vos_status))
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004687 hddLog(LOGW, FL("Failed to stop HDD restart timer"));
Jeff Johnsone7245742012-09-05 17:12:55 -07004688 vos_status = vos_timer_destroy(&pHddCtx->hdd_restart_timer);
4689 if (!VOS_IS_STATUS_SUCCESS(vos_status))
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004690 hddLog(LOGW, FL("Failed to destroy HDD restart timer"));
Jeff Johnsone7245742012-09-05 17:12:55 -07004691
4692}
4693
4694/**---------------------------------------------------------------------------
4695 *
4696 * \brief wlan_hdd_framework_restart
4697 *
4698 * This function uses a cfg80211 API to start a framework initiated WLAN
4699 * driver module unload/load.
4700 *
4701 * Also this API keep retrying (WLAN_HDD_RESTART_RETRY_MAX_CNT).
4702 *
4703 *
4704 * \param - pHddCtx
4705 *
4706 * \return - VOS_STATUS_SUCCESS: Success
4707 * VOS_STATUS_E_EMPTY: Adapter is Empty
4708 * VOS_STATUS_E_NOMEM: No memory
4709
4710 * --------------------------------------------------------------------------*/
4711
4712static VOS_STATUS wlan_hdd_framework_restart(hdd_context_t *pHddCtx)
4713{
4714 VOS_STATUS status = VOS_STATUS_SUCCESS;
4715 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
4716 int len = (sizeof (struct ieee80211_mgmt));
4717 struct ieee80211_mgmt *mgmt = NULL;
4718
4719 /* Prepare the DEAUTH managment frame with reason code */
4720 mgmt = kzalloc(len, GFP_KERNEL);
4721 if(mgmt == NULL)
4722 {
4723 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
4724 "%s: memory allocatoin failed (%d bytes)", __func__, len);
4725 return VOS_STATUS_E_NOMEM;
4726 }
4727 mgmt->u.deauth.reason_code = WLAN_REASON_DISASSOC_LOW_ACK;
4728
4729 /* Iterate over all adapters/devices */
4730 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
4731 do
4732 {
4733 if( (status == VOS_STATUS_SUCCESS) &&
4734 pAdapterNode &&
4735 pAdapterNode->pAdapter)
4736 {
4737 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
4738 "restarting the driver(intf:\'%s\' mode:%d :try %d)",
4739 pAdapterNode->pAdapter->dev->name,
4740 pAdapterNode->pAdapter->device_mode,
4741 pHddCtx->hdd_restart_retries + 1);
4742 /*
4743 * CFG80211 event to restart the driver
4744 *
4745 * 'cfg80211_send_unprot_deauth' sends a
4746 * NL80211_CMD_UNPROT_DEAUTHENTICATE event to supplicant at any state
4747 * of SME(Linux Kernel) state machine.
4748 *
4749 * Reason code WLAN_REASON_DISASSOC_LOW_ACK is currently used to restart
4750 * the driver.
4751 *
4752 */
4753
4754 cfg80211_send_unprot_deauth(pAdapterNode->pAdapter->dev, (u_int8_t*)mgmt, len );
4755 }
4756 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
4757 pAdapterNode = pNext;
4758 } while((NULL != pAdapterNode) && (VOS_STATUS_SUCCESS == status));
4759
4760
4761 /* Free the allocated management frame */
4762 kfree(mgmt);
4763
4764 /* Retry until we unload or reach max count */
4765 if(++pHddCtx->hdd_restart_retries < WLAN_HDD_RESTART_RETRY_MAX_CNT)
4766 vos_timer_start(&pHddCtx->hdd_restart_timer, WLAN_HDD_RESTART_RETRY_DELAY_MS);
4767
4768 return status;
4769
4770}
4771/**---------------------------------------------------------------------------
4772 *
4773 * \brief wlan_hdd_restart_timer_cb
4774 *
4775 * Restart timer callback. An internal function.
4776 *
4777 * \param - User data:
4778 *
4779 * \return - None
4780 *
4781 * --------------------------------------------------------------------------*/
4782
4783void wlan_hdd_restart_timer_cb(v_PVOID_t usrDataForCallback)
4784{
4785 hdd_context_t *pHddCtx = usrDataForCallback;
4786 wlan_hdd_framework_restart(pHddCtx);
4787 return;
4788
4789}
4790
4791
4792/**---------------------------------------------------------------------------
4793 *
4794 * \brief wlan_hdd_restart_driver
4795 *
4796 * This function sends an event to supplicant to restart the WLAN driver.
4797 *
4798 * This function is called from vos_wlanRestart.
4799 *
4800 * \param - pHddCtx
4801 *
4802 * \return - VOS_STATUS_SUCCESS: Success
4803 * VOS_STATUS_E_EMPTY: Adapter is Empty
4804 * VOS_STATUS_E_ALREADY: Request already in progress
4805
4806 * --------------------------------------------------------------------------*/
4807VOS_STATUS wlan_hdd_restart_driver(hdd_context_t *pHddCtx)
4808{
4809 VOS_STATUS status = VOS_STATUS_SUCCESS;
4810
4811 /* A tight check to make sure reentrancy */
4812 if(atomic_xchg(&pHddCtx->isRestartInProgress, 1))
4813 {
4814 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
4815 "%s: WLAN restart is already in progress", __func__);
4816
4817 return VOS_STATUS_E_ALREADY;
4818 }
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07004819 /* when WLAN driver is statically linked, then invoke SSR by sending
Madan Mohan Koyyalamudibb8f0172012-09-28 15:36:06 -07004820 * the reset interrupt. If it is DLKM, then use restart API
4821 */
4822#ifdef MODULE
Jeff Johnsone7245742012-09-05 17:12:55 -07004823 status = wlan_hdd_framework_restart(pHddCtx);
Madan Mohan Koyyalamudibb8f0172012-09-28 15:36:06 -07004824#else
Madan Mohan Koyyalamudie388b342012-11-08 15:03:16 -08004825#ifdef HAVE_WCNSS_RESET_INTR
Madan Mohan Koyyalamudibb8f0172012-09-28 15:36:06 -07004826 wcnss_reset_intr();
4827#endif
Madan Mohan Koyyalamudie388b342012-11-08 15:03:16 -08004828#endif
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07004829
Jeff Johnsone7245742012-09-05 17:12:55 -07004830 return status;
4831}
4832
4833
Jeff Johnson295189b2012-06-20 16:38:30 -07004834//Register the module init/exit functions
4835module_init(hdd_module_init);
4836module_exit(hdd_module_exit);
4837
4838MODULE_LICENSE("Dual BSD/GPL");
4839MODULE_AUTHOR("Qualcomm Atheros, Inc.");
4840MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER");
4841
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004842module_param_call(con_mode, con_mode_handler, param_get_int, &con_mode,
4843 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Jeff Johnson32d95a32012-09-10 13:15:23 -07004844
4845module_param_call(fwpath, fwpath_changed_handler, param_get_string, fwpath,
4846 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);