blob: 4fc75bb87b6310522d26245fdb7f3dffa685290a [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;
233 INIT_COMPLETION(pAdapter->abortscan_event_var);
234 hdd_abort_mac_scan(pAdapter->pHddCtx);
235 result = wait_for_completion_interruptible_timeout(
236 &pAdapter->abortscan_event_var,
237 msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN));
238 if(!result)
239 {
240 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
241 "%s: Timeout occured while waiting for abortscan" ,
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__);
Jeff Johnson295189b2012-06-20 16:38:30 -0700544 return -1;
545 }
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);
1130 init_completion(&pAdapter->abortscan_event_var);
1131#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
1132 init_completion(&pAdapter->offchannel_tx_event);
1133#endif
1134#ifdef CONFIG_CFG80211
1135 init_completion(&pAdapter->tx_action_cnf_event);
1136#endif
1137 init_completion(&pHddCtx->mc_sus_event_var);
1138 init_completion(&pHddCtx->tx_sus_event_var);
1139
Jeff Johnson295189b2012-06-20 16:38:30 -07001140 pAdapter->isLinkUpSvcNeeded = FALSE;
1141 pAdapter->higherDtimTransition = eANI_BOOLEAN_TRUE;
1142 //Init the net_device structure
1143 strlcpy(pWlanDev->name, name, IFNAMSIZ);
1144
1145 vos_mem_copy(pWlanDev->dev_addr, (void *)macAddr, sizeof(tSirMacAddr));
1146 vos_mem_copy( pAdapter->macAddressCurrent.bytes, macAddr, sizeof(tSirMacAddr));
1147 pWlanDev->watchdog_timeo = HDD_TX_TIMEOUT;
1148 pWlanDev->hard_header_len += LIBRA_HW_NEEDED_HEADROOM;
1149
1150 hdd_set_station_ops( pAdapter->dev );
1151
1152 pWlanDev->destructor = free_netdev;
1153#ifdef CONFIG_CFG80211
1154 pWlanDev->ieee80211_ptr = &pAdapter->wdev ;
1155 pAdapter->wdev.wiphy = pHddCtx->wiphy;
1156 pAdapter->wdev.netdev = pWlanDev;
1157#endif
1158 /* set pWlanDev's parent to underlying device */
1159 SET_NETDEV_DEV(pWlanDev, pHddCtx->parent_dev);
1160 }
1161
1162 return pAdapter;
1163}
1164
1165VOS_STATUS hdd_register_interface( hdd_adapter_t *pAdapter, tANI_U8 rtnl_lock_held )
1166{
1167 struct net_device *pWlanDev = pAdapter->dev;
1168 //hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
1169 //hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
1170 //eHalStatus halStatus = eHAL_STATUS_SUCCESS;
1171
1172 if( rtnl_lock_held )
1173 {
Madan Mohan Koyyalamudid8ac8662012-11-06 19:04:56 -08001174 if (strnchr(pWlanDev->name, strlen(pWlanDev->name), '%')) {
Jeff Johnson295189b2012-06-20 16:38:30 -07001175 if( dev_alloc_name(pWlanDev, pWlanDev->name) < 0 )
1176 {
1177 hddLog(VOS_TRACE_LEVEL_ERROR,"%s:Failed:dev_alloc_name",__func__);
1178 return VOS_STATUS_E_FAILURE;
1179 }
1180 }
1181 if (register_netdevice(pWlanDev))
1182 {
1183 hddLog(VOS_TRACE_LEVEL_ERROR,"%s:Failed:register_netdev",__func__);
1184 return VOS_STATUS_E_FAILURE;
1185 }
1186 }
1187 else
1188 {
1189 if(register_netdev(pWlanDev))
1190 {
1191 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed:register_netdev",__func__);
1192 return VOS_STATUS_E_FAILURE;
1193 }
1194 }
1195 set_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags);
1196
1197 return VOS_STATUS_SUCCESS;
1198}
1199
1200eHalStatus hdd_smeCloseSessionCallback(void *pContext)
1201{
1202 if(pContext != NULL)
1203 {
1204 clear_bit(SME_SESSION_OPENED, &((hdd_adapter_t*)pContext)->event_flags);
1205
1206 /* need to make sure all of our scheduled work has completed.
1207 * This callback is called from MC thread context, so it is safe to
1208 * to call below flush workqueue API from here.
1209 */
1210 flush_scheduled_work();
1211 complete(&((hdd_adapter_t*)pContext)->session_close_comp_var);
1212 }
1213 return eHAL_STATUS_SUCCESS;
1214}
1215
1216VOS_STATUS hdd_init_station_mode( hdd_adapter_t *pAdapter )
1217{
1218 struct net_device *pWlanDev = pAdapter->dev;
1219 hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station;
1220 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX( pAdapter );
1221 eHalStatus halStatus = eHAL_STATUS_SUCCESS;
1222 VOS_STATUS status = VOS_STATUS_E_FAILURE;
1223 int rc = 0;
1224
1225 INIT_COMPLETION(pAdapter->session_open_comp_var);
1226 //Open a SME session for future operation
1227 halStatus = sme_OpenSession( pHddCtx->hHal, hdd_smeRoamCallback, pAdapter,
1228 (tANI_U8 *)&pAdapter->macAddressCurrent, &pAdapter->sessionId );
1229 if ( !HAL_STATUS_SUCCESS( halStatus ) )
1230 {
1231 hddLog(VOS_TRACE_LEVEL_FATAL,
1232 "sme_OpenSession() failed with status code %08d [x%08lx]",
1233 halStatus, halStatus );
1234 status = VOS_STATUS_E_FAILURE;
1235 goto error_sme_open;
1236 }
1237
1238 //Block on a completion variable. Can't wait forever though.
1239 rc = wait_for_completion_interruptible_timeout(
1240 &pAdapter->session_open_comp_var,
1241 msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
1242 if (!rc)
1243 {
1244 hddLog(VOS_TRACE_LEVEL_FATAL,
1245 "Session is not opened within timeout period code %08d", rc );
1246 status = VOS_STATUS_E_FAILURE;
1247 goto error_sme_open;
1248 }
1249
1250 // Register wireless extensions
1251 if( eHAL_STATUS_SUCCESS != (halStatus = hdd_register_wext(pWlanDev)))
1252 {
1253 hddLog(VOS_TRACE_LEVEL_FATAL,
1254 "hdd_register_wext() failed with status code %08d [x%08lx]",
1255 halStatus, halStatus );
1256 status = VOS_STATUS_E_FAILURE;
1257 goto error_register_wext;
1258 }
1259 //Safe to register the hard_start_xmit function again
1260#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29))
1261 wlan_drv_ops.ndo_start_xmit = hdd_hard_start_xmit;
1262#else
1263 pWlanDev->hard_start_xmit = hdd_hard_start_xmit;
1264#endif
1265
1266 //Set the Connection State to Not Connected
1267 pHddStaCtx->conn_info.connState = eConnectionState_NotConnected;
1268
1269 //Set the default operation channel
1270 pHddStaCtx->conn_info.operationChannel = pHddCtx->cfg_ini->OperatingChannel;
1271
1272 /* Make the default Auth Type as OPEN*/
1273 pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM;
1274
1275 if( VOS_STATUS_SUCCESS != ( status = hdd_init_tx_rx( pAdapter ) ) )
1276 {
1277 hddLog(VOS_TRACE_LEVEL_FATAL,
1278 "hdd_init_tx_rx() failed with status code %08d [x%08lx]",
1279 status, status );
1280 goto error_init_txrx;
1281 }
1282
1283 set_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1284
1285 if( VOS_STATUS_SUCCESS != ( status = hdd_wmm_adapter_init( pAdapter ) ) )
1286 {
1287 hddLog(VOS_TRACE_LEVEL_FATAL,
1288 "hdd_wmm_adapter_init() failed with status code %08d [x%08lx]",
1289 status, status );
1290 goto error_wmm_init;
1291 }
1292
1293 set_bit(WMM_INIT_DONE, &pAdapter->event_flags);
1294
1295 return VOS_STATUS_SUCCESS;
1296
1297error_wmm_init:
1298 clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1299 hdd_deinit_tx_rx(pAdapter);
1300error_init_txrx:
1301 hdd_UnregisterWext(pWlanDev);
1302error_register_wext:
1303 if(test_bit(SME_SESSION_OPENED, &pAdapter->event_flags))
1304 {
1305 INIT_COMPLETION(pAdapter->session_close_comp_var);
1306 if( eHAL_STATUS_SUCCESS == sme_CloseSession( pHddCtx->hHal,
1307 pAdapter->sessionId,
1308 hdd_smeCloseSessionCallback, pAdapter ) )
1309 {
1310 //Block on a completion variable. Can't wait forever though.
1311 wait_for_completion_interruptible_timeout(
1312 &pAdapter->session_close_comp_var,
1313 msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
1314 }
1315}
1316error_sme_open:
1317 return status;
1318}
1319
Jeff Johnson295189b2012-06-20 16:38:30 -07001320#ifdef CONFIG_CFG80211
1321void hdd_cleanup_actionframe( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
1322{
1323 hdd_cfg80211_state_t *cfgState;
1324
1325 cfgState = WLAN_HDD_GET_CFG_STATE_PTR( pAdapter );
1326
1327 if( NULL != cfgState->buf )
1328 {
1329 int rc;
1330 INIT_COMPLETION(pAdapter->tx_action_cnf_event);
1331 rc = wait_for_completion_interruptible_timeout(
1332 &pAdapter->tx_action_cnf_event,
1333 msecs_to_jiffies(ACTION_FRAME_TX_TIMEOUT));
1334 if(!rc)
1335 {
1336 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
1337 ("ERROR: HDD Wait for Action Confirmation Failed!!\n"));
1338 }
1339 }
1340 return;
1341}
1342#endif
1343
1344void hdd_deinit_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
1345{
1346 ENTER();
1347 switch ( pAdapter->device_mode )
1348 {
1349 case WLAN_HDD_INFRA_STATION:
1350 case WLAN_HDD_P2P_CLIENT:
Jeff Johnsone7245742012-09-05 17:12:55 -07001351 case WLAN_HDD_P2P_DEVICE:
Jeff Johnson295189b2012-06-20 16:38:30 -07001352 {
1353 if(test_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags))
1354 {
1355 hdd_deinit_tx_rx( pAdapter );
1356 clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1357 }
1358
1359 if(test_bit(WMM_INIT_DONE, &pAdapter->event_flags))
1360 {
1361 hdd_wmm_adapter_close( pAdapter );
1362 clear_bit(WMM_INIT_DONE, &pAdapter->event_flags);
1363 }
1364
1365#ifdef CONFIG_CFG80211
1366 hdd_cleanup_actionframe(pHddCtx, pAdapter);
1367#endif
1368
1369 break;
1370 }
1371
1372 case WLAN_HDD_SOFTAP:
1373 case WLAN_HDD_P2P_GO:
1374#ifdef WLAN_SOFTAP_FEATURE
1375 {
1376#ifdef CONFIG_CFG80211
1377 hdd_cleanup_actionframe(pHddCtx, pAdapter);
1378#endif
1379
1380 hdd_unregister_hostapd(pAdapter);
1381 hdd_set_conparam( 0 );
1382#ifdef CONFIG_CFG80211
1383 wlan_hdd_set_monitor_tx_adapter( WLAN_HDD_GET_CTX(pAdapter), NULL );
1384#endif
1385 break;
1386 }
1387
1388 case WLAN_HDD_MONITOR:
1389 {
1390#ifdef CONFIG_CFG80211
1391 hdd_adapter_t* pAdapterforTx = pAdapter->sessionCtx.monitor.pAdapterForTx;
1392#endif
1393 if(test_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags))
1394 {
1395 hdd_deinit_tx_rx( pAdapter );
1396 clear_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1397 }
1398#ifdef CONFIG_CFG80211
1399 if(NULL != pAdapterforTx)
1400 {
1401 hdd_cleanup_actionframe(pHddCtx, pAdapterforTx);
1402 }
1403#endif
1404#endif //WLAN_SOFTAP_FEATURE
1405 break;
1406 }
1407
1408
1409 default:
1410 break;
1411 }
1412
1413 EXIT();
1414}
1415
1416void hdd_cleanup_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, tANI_U8 rtnl_held )
1417{
1418 struct net_device *pWlanDev = pAdapter->dev;
1419
1420 if(test_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags)) {
1421 if( rtnl_held )
1422 {
1423 unregister_netdevice(pWlanDev);
1424 }
1425 else
1426 {
1427 unregister_netdev(pWlanDev);
1428 }
1429 // note that the pAdapter is no longer valid at this point
1430 // since the memory has been reclaimed
1431 }
1432
1433}
1434
1435VOS_STATUS hdd_enable_bmps_imps(hdd_context_t *pHddCtx)
1436{
1437 VOS_STATUS status = VOS_STATUS_SUCCESS;
1438
1439 if(pHddCtx->cfg_ini->fIsBmpsEnabled)
1440 {
1441 sme_EnablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE);
1442 }
1443
1444 if(pHddCtx->cfg_ini->fIsAutoBmpsTimerEnabled)
1445 {
1446 sme_StartAutoBmpsTimer(pHddCtx->hHal);
1447 }
1448
1449 if (pHddCtx->cfg_ini->fIsImpsEnabled)
1450 {
1451 sme_EnablePowerSave (pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE);
1452 }
1453
1454 return status;
1455}
1456
1457VOS_STATUS hdd_disable_bmps_imps(hdd_context_t *pHddCtx, tANI_U8 session_type)
1458{
1459 hdd_adapter_t *pAdapter = NULL;
1460 eHalStatus halStatus;
1461 VOS_STATUS status = VOS_STATUS_E_INVAL;
1462 v_BOOL_t disableBmps = FALSE;
1463 v_BOOL_t disableImps = FALSE;
1464
1465 switch(session_type)
1466 {
1467 case WLAN_HDD_INFRA_STATION:
1468 case WLAN_HDD_SOFTAP:
1469#ifdef WLAN_FEATURE_P2P
1470 case WLAN_HDD_P2P_CLIENT:
1471 case WLAN_HDD_P2P_GO:
1472#endif
1473 //Exit BMPS -> Is Sta/P2P Client is already connected
1474 pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_INFRA_STATION);
1475 if((NULL != pAdapter)&&
1476 hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
1477 {
1478 disableBmps = TRUE;
1479 }
1480
1481 pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_P2P_CLIENT);
1482 if((NULL != pAdapter)&&
1483 hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))
1484 {
1485 disableBmps = TRUE;
1486 }
1487
1488 //Exit both Bmps and Imps incase of Go/SAP Mode
1489 if((WLAN_HDD_SOFTAP == session_type) ||
1490 (WLAN_HDD_P2P_GO == session_type))
1491 {
1492 disableBmps = TRUE;
1493 disableImps = TRUE;
1494 }
1495
1496 if(TRUE == disableImps)
1497 {
1498 if (pHddCtx->cfg_ini->fIsImpsEnabled)
1499 {
1500 sme_DisablePowerSave (pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE);
1501 }
1502 }
1503
1504 if(TRUE == disableBmps)
1505 {
1506 if(pHddCtx->cfg_ini->fIsBmpsEnabled)
1507 {
1508 halStatus = sme_DisablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE);
1509
1510 if(eHAL_STATUS_SUCCESS != halStatus)
1511 {
1512 status = VOS_STATUS_E_FAILURE;
1513 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Fail to Disable Power Save\n", __func__);
1514 VOS_ASSERT(0);
1515 return status;
1516 }
1517 }
1518
1519 if(pHddCtx->cfg_ini->fIsAutoBmpsTimerEnabled)
1520 {
1521 halStatus = sme_StopAutoBmpsTimer(pHddCtx->hHal);
1522
1523 if(eHAL_STATUS_SUCCESS != halStatus)
1524 {
1525 status = VOS_STATUS_E_FAILURE;
1526 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Fail to Stop Auto Bmps Timer\n", __func__);
1527 VOS_ASSERT(0);
1528 return status;
1529 }
1530 }
1531 }
1532
1533 if((TRUE == disableBmps) ||
1534 (TRUE == disableImps))
1535 {
1536 /* Now, get the chip into Full Power now */
1537 INIT_COMPLETION(pHddCtx->full_pwr_comp_var);
1538 halStatus = sme_RequestFullPower(pHddCtx->hHal, hdd_full_pwr_cbk,
1539 pHddCtx, eSME_FULL_PWR_NEEDED_BY_HDD);
1540
1541 if(halStatus != eHAL_STATUS_SUCCESS)
1542 {
1543 if(halStatus == eHAL_STATUS_PMC_PENDING)
1544 {
1545 //Block on a completion variable. Can't wait forever though
1546 wait_for_completion_interruptible_timeout(
1547 &pHddCtx->full_pwr_comp_var, msecs_to_jiffies(1000));
1548 }
1549 else
1550 {
1551 status = VOS_STATUS_E_FAILURE;
1552 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Request for Full Power failed\n", __func__);
1553 VOS_ASSERT(0);
1554 return status;
1555 }
1556 }
1557
1558 status = VOS_STATUS_SUCCESS;
1559 }
1560
1561 break;
1562 }
1563 return status;
1564}
1565
1566hdd_adapter_t* hdd_open_adapter( hdd_context_t *pHddCtx, tANI_U8 session_type,
1567 char *iface_name, tSirMacAddr macAddr,
1568 tANI_U8 rtnl_held )
1569{
1570 hdd_adapter_t *pAdapter = NULL;
1571 hdd_adapter_list_node_t *pHddAdapterNode = NULL;
1572 VOS_STATUS status = VOS_STATUS_E_FAILURE;
1573 VOS_STATUS exitbmpsStatus;
1574
1575 hddLog(VOS_TRACE_LEVEL_INFO_HIGH, "%s iface =%s type = %d\n",__func__,iface_name,session_type);
1576
1577 //Disable BMPS incase of Concurrency
1578 exitbmpsStatus = hdd_disable_bmps_imps(pHddCtx, session_type);
1579
1580 if(VOS_STATUS_E_FAILURE == exitbmpsStatus)
1581 {
1582 //Fail to Exit BMPS
1583 VOS_ASSERT(0);
1584 return NULL;
1585 }
1586
1587 switch(session_type)
1588 {
1589 case WLAN_HDD_INFRA_STATION:
1590#ifdef WLAN_FEATURE_P2P
1591 case WLAN_HDD_P2P_CLIENT:
Jeff Johnsone7245742012-09-05 17:12:55 -07001592 case WLAN_HDD_P2P_DEVICE:
Jeff Johnson295189b2012-06-20 16:38:30 -07001593#endif
1594 {
1595 pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );
1596
1597 if( NULL == pAdapter )
1598 return NULL;
1599
1600#ifdef CONFIG_CFG80211
Jeff Johnsone7245742012-09-05 17:12:55 -07001601 pAdapter->wdev.iftype = (session_type == WLAN_HDD_P2P_CLIENT) ?
1602 NL80211_IFTYPE_P2P_CLIENT:
1603 NL80211_IFTYPE_STATION;
Jeff Johnson295189b2012-06-20 16:38:30 -07001604#endif
1605
Jeff Johnson295189b2012-06-20 16:38:30 -07001606 pAdapter->device_mode = session_type;
1607
1608 status = hdd_init_station_mode( pAdapter );
1609 if( VOS_STATUS_SUCCESS != status )
1610 goto err_free_netdev;
1611
1612 status = hdd_register_interface( pAdapter, rtnl_held );
1613 if( VOS_STATUS_SUCCESS != status )
1614 {
1615 hdd_deinit_adapter(pHddCtx, pAdapter);
1616 goto err_free_netdev;
1617 }
1618 //Stop the Interface TX queue.
1619 netif_tx_disable(pAdapter->dev);
1620 //netif_tx_disable(pWlanDev);
1621 netif_carrier_off(pAdapter->dev);
1622
1623 break;
1624 }
1625
1626#ifdef WLAN_FEATURE_P2P
1627 case WLAN_HDD_P2P_GO:
1628#endif
1629 case WLAN_HDD_SOFTAP:
1630 {
1631 pAdapter = hdd_wlan_create_ap_dev( pHddCtx, macAddr, (tANI_U8 *)iface_name );
1632 if( NULL == pAdapter )
1633 return NULL;
1634
1635#ifdef CONFIG_CFG80211
1636 pAdapter->wdev.iftype = (session_type == WLAN_HDD_SOFTAP) ?
1637 NL80211_IFTYPE_AP:
1638 NL80211_IFTYPE_P2P_GO;
1639#endif
1640 pAdapter->device_mode = session_type;
1641
1642 status = hdd_init_ap_mode(pAdapter);
1643 if( VOS_STATUS_SUCCESS != status )
1644 goto err_free_netdev;
1645
1646 status = hdd_register_hostapd( pAdapter, rtnl_held );
1647 if( VOS_STATUS_SUCCESS != status )
1648 {
1649 hdd_deinit_adapter(pHddCtx, pAdapter);
1650 goto err_free_netdev;
1651 }
1652
1653 netif_tx_disable(pAdapter->dev);
1654 netif_carrier_off(pAdapter->dev);
1655
1656 hdd_set_conparam( 1 );
1657 break;
1658 }
1659 case WLAN_HDD_MONITOR:
1660 {
1661#ifdef CONFIG_CFG80211
1662 pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );
1663 if( NULL == pAdapter )
1664 return NULL;
1665
1666 pAdapter->wdev.iftype = NL80211_IFTYPE_MONITOR;
1667 pAdapter->device_mode = session_type;
1668 status = hdd_register_interface( pAdapter, rtnl_held );
1669#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)
1670 pAdapter->dev->netdev_ops = &wlan_mon_drv_ops;
1671#else
1672 pAdapter->dev->open = hdd_mon_open;
1673 pAdapter->dev->hard_start_xmit = hdd_mon_hard_start_xmit;
1674#endif
1675 hdd_init_tx_rx( pAdapter );
1676 set_bit(INIT_TX_RX_SUCCESS, &pAdapter->event_flags);
1677 //Set adapter to be used for data tx. It will use either GO or softap.
1678 pAdapter->sessionCtx.monitor.pAdapterForTx =
1679 hdd_get_adapter(pAdapter->pHddCtx, WLAN_HDD_SOFTAP);
1680#ifdef WLAN_FEATURE_P2P
1681 if (NULL == pAdapter->sessionCtx.monitor.pAdapterForTx)
1682 {
1683 pAdapter->sessionCtx.monitor.pAdapterForTx =
1684 hdd_get_adapter(pAdapter->pHddCtx, WLAN_HDD_P2P_GO);
1685 }
1686#endif
1687 /* This workqueue will be used to transmit management packet over
1688 * monitor interface. */
Madan Mohan Koyyalamudic75be962012-10-18 19:19:03 -07001689 if (NULL == pAdapter->sessionCtx.monitor.pAdapterForTx) {
1690 hddLog(VOS_TRACE_LEVEL_ERROR,"%s:Failed:hdd_get_adapter",__func__);
1691 return NULL;
1692 }
Madan Mohan Koyyalamudi9f40ceb2012-10-18 19:22:56 -07001693
Jeff Johnson295189b2012-06-20 16:38:30 -07001694 INIT_WORK(&pAdapter->sessionCtx.monitor.pAdapterForTx->monTxWorkQueue,
1695 hdd_mon_tx_work_queue);
1696#endif
1697 }
1698 break;
1699#ifdef ANI_MANF_DIAG
1700 case WLAN_HDD_FTM:
1701 {
1702 pAdapter = hdd_alloc_station_adapter( pHddCtx, macAddr, iface_name );
1703
1704 if( NULL == pAdapter )
1705 return NULL;
1706 /* Assign NL80211_IFTYPE_STATION as interface type to resolve Kernel Warning
1707 * message while loading driver in FTM mode. */
1708 pAdapter->wdev.iftype = NL80211_IFTYPE_STATION;
1709 pAdapter->device_mode = session_type;
1710 status = hdd_register_interface( pAdapter, rtnl_held );
1711 }
1712 break;
1713#endif
1714 default:
1715 {
1716 VOS_ASSERT(0);
1717 return NULL;
1718 }
1719 }
1720
1721
1722 if( VOS_STATUS_SUCCESS == status )
1723 {
1724 //Add it to the hdd's session list.
1725 pHddAdapterNode = vos_mem_malloc( sizeof( hdd_adapter_list_node_t ) );
1726 if( NULL == pHddAdapterNode )
1727 {
1728 status = VOS_STATUS_E_NOMEM;
1729 }
1730 else
1731 {
1732 pHddAdapterNode->pAdapter = pAdapter;
1733 status = hdd_add_adapter_back ( pHddCtx,
1734 pHddAdapterNode );
1735 }
1736 }
1737
1738 if( VOS_STATUS_SUCCESS != status )
1739 {
1740 if( NULL != pAdapter )
1741 {
1742 hdd_cleanup_adapter( pHddCtx, pAdapter, rtnl_held );
1743 pAdapter = NULL;
1744 }
1745 if( NULL != pHddAdapterNode )
1746 {
1747 vos_mem_free( pHddAdapterNode );
1748 }
1749
1750 goto resume_bmps;
1751 }
1752
1753 if(VOS_STATUS_SUCCESS == status)
1754 {
1755 wlan_hdd_set_concurrency_mode(pHddCtx, session_type);
1756
1757#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
1758 /* If there are concurrent session enable SW frame translation
1759 * for all registered STA
1760 * This is not required in case of PRIMA as HW frame translation
1761 * is disabled in PRIMA*/
1762 if (vos_concurrent_sessions_running())
1763 {
1764 WLANTL_ConfigureSwFrameTXXlationForAll(pHddCtx->pvosContext, TRUE);
1765 }
1766#endif
Madan Mohan Koyyalamudi96dd30d2012-10-05 17:24:51 -07001767 //Initialize the WoWL service
1768 if(!hdd_init_wowl(pAdapter))
1769 {
1770 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hdd_init_wowl failed",__func__);
1771 goto err_free_netdev;
1772 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001773 }
Jeff Johnson295189b2012-06-20 16:38:30 -07001774 return pAdapter;
1775
1776err_free_netdev:
1777 free_netdev(pAdapter->dev);
1778 wlan_hdd_release_intf_addr( pHddCtx,
1779 pAdapter->macAddressCurrent.bytes );
1780
1781resume_bmps:
1782 //If bmps disabled enable it
1783 if(VOS_STATUS_SUCCESS == exitbmpsStatus)
1784 {
1785 hdd_enable_bmps_imps(pHddCtx);
1786 }
1787 return NULL;
1788}
1789
1790VOS_STATUS hdd_close_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter,
1791 tANI_U8 rtnl_held )
1792{
1793 hdd_adapter_list_node_t *pAdapterNode, *pCurrent, *pNext;
1794 VOS_STATUS status;
1795
1796 status = hdd_get_front_adapter ( pHddCtx, &pCurrent );
1797 if( VOS_STATUS_SUCCESS != status )
1798 return status;
1799
1800 while ( pCurrent->pAdapter != pAdapter )
1801 {
1802 status = hdd_get_next_adapter ( pHddCtx, pCurrent, &pNext );
1803 if( VOS_STATUS_SUCCESS != status )
1804 break;
1805
1806 pCurrent = pNext;
1807 }
1808 pAdapterNode = pCurrent;
1809 if( VOS_STATUS_SUCCESS == status )
1810 {
1811 wlan_hdd_clear_concurrency_mode(pHddCtx, pAdapter->device_mode);
1812 hdd_cleanup_adapter( pHddCtx, pAdapterNode->pAdapter, rtnl_held );
1813 hdd_remove_adapter( pHddCtx, pAdapterNode );
1814 vos_mem_free( pAdapterNode );
1815
1816#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
1817 /* If there is no concurrent session disable SW frame translation
1818 * for all registered STA */
1819 /* This is not required in case of PRIMA as HW frame translation
1820 * is disabled in PRIMA*/
1821 if (!vos_concurrent_sessions_running())
1822 {
1823 WLANTL_ConfigureSwFrameTXXlationForAll(pHddCtx->pvosContext, FALSE);
1824 }
1825#endif
1826
1827 /* If there is a single session of STA/P2P client, re-enable BMPS */
1828 if ((!vos_concurrent_sessions_running()) &&
1829 ((pHddCtx->no_of_sessions[VOS_STA_MODE] >= 1) ||
1830 (pHddCtx->no_of_sessions[VOS_P2P_CLIENT_MODE] >= 1)))
1831 {
1832 hdd_enable_bmps_imps(pHddCtx);
1833 }
1834
1835 return VOS_STATUS_SUCCESS;
1836 }
1837
1838 return VOS_STATUS_E_FAILURE;
1839}
1840
1841VOS_STATUS hdd_close_all_adapters( hdd_context_t *pHddCtx )
1842{
1843 hdd_adapter_list_node_t *pHddAdapterNode;
1844 VOS_STATUS status;
1845
1846 ENTER();
1847
1848 do
1849 {
1850 status = hdd_remove_front_adapter( pHddCtx, &pHddAdapterNode );
1851 if( pHddAdapterNode && VOS_STATUS_SUCCESS == status )
1852 {
1853 hdd_cleanup_adapter( pHddCtx, pHddAdapterNode->pAdapter, FALSE );
1854 vos_mem_free( pHddAdapterNode );
1855 }
1856 }while( NULL != pHddAdapterNode && VOS_STATUS_E_EMPTY != status );
1857
1858 EXIT();
1859
1860 return VOS_STATUS_SUCCESS;
1861}
1862
1863void wlan_hdd_reset_prob_rspies(hdd_adapter_t* pHostapdAdapter)
1864{
1865 v_U8_t addIE[1] = {0};
1866
1867 if ( eHAL_STATUS_FAILURE == ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal,
1868 WNI_CFG_PROBE_RSP_ADDNIE_DATA1,(tANI_U8*)addIE, 0, NULL,
1869 eANI_BOOLEAN_FALSE) )
1870 {
1871 hddLog(LOGE,
1872 "Could not pass on WNI_CFG_PROBE_RSP_ADDNIE_DATA1 to CCM\n");
1873 }
1874
1875 if ( eHAL_STATUS_FAILURE == ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal,
1876 WNI_CFG_PROBE_RSP_ADDNIE_DATA2, (tANI_U8*)addIE, 0, NULL,
1877 eANI_BOOLEAN_FALSE) )
1878 {
1879 hddLog(LOGE,
1880 "Could not pass on WNI_CFG_PROBE_RSP_ADDNIE_DATA2 to CCM\n");
1881 }
1882
1883 if ( eHAL_STATUS_FAILURE == ccmCfgSetStr((WLAN_HDD_GET_CTX(pHostapdAdapter))->hHal,
1884 WNI_CFG_PROBE_RSP_ADDNIE_DATA3, (tANI_U8*)addIE, 0, NULL,
1885 eANI_BOOLEAN_FALSE) )
1886 {
1887 hddLog(LOGE,
1888 "Could not pass on WNI_CFG_PROBE_RSP_ADDNIE_DATA3 to CCM\n");
1889 }
1890}
1891
1892VOS_STATUS hdd_stop_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
1893{
1894 eHalStatus halStatus = eHAL_STATUS_SUCCESS;
1895 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
1896 union iwreq_data wrqu;
1897
1898 ENTER();
1899
1900 switch(pAdapter->device_mode)
1901 {
1902 case WLAN_HDD_INFRA_STATION:
1903 case WLAN_HDD_P2P_CLIENT:
Jeff Johnsone7245742012-09-05 17:12:55 -07001904 case WLAN_HDD_P2P_DEVICE:
Jeff Johnson295189b2012-06-20 16:38:30 -07001905 if( hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR( pAdapter )) )
1906 {
1907 if (pWextState->roamProfile.BSSType == eCSR_BSS_TYPE_START_IBSS)
1908 halStatus = sme_RoamDisconnect(pHddCtx->hHal,
1909 pAdapter->sessionId,
1910 eCSR_DISCONNECT_REASON_IBSS_LEAVE);
1911 else
1912 halStatus = sme_RoamDisconnect(pHddCtx->hHal,
1913 pAdapter->sessionId,
1914 eCSR_DISCONNECT_REASON_UNSPECIFIED);
1915 //success implies disconnect command got queued up successfully
1916 if(halStatus == eHAL_STATUS_SUCCESS)
1917 {
1918 wait_for_completion_interruptible_timeout(&pAdapter->disconnect_comp_var,
1919 msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT));
1920 }
1921 memset(&wrqu, '\0', sizeof(wrqu));
1922 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
1923 memset(wrqu.ap_addr.sa_data,'\0',ETH_ALEN);
1924 wireless_send_event(pAdapter->dev, SIOCGIWAP, &wrqu, NULL);
1925 }
1926 else
1927 {
1928 hdd_abort_mac_scan(pHddCtx);
1929 }
1930
1931 if (test_bit(SME_SESSION_OPENED, &pAdapter->event_flags))
1932 {
1933 INIT_COMPLETION(pAdapter->session_close_comp_var);
1934 if (eHAL_STATUS_SUCCESS ==
1935 sme_CloseSession(pHddCtx->hHal, pAdapter->sessionId,
1936 hdd_smeCloseSessionCallback, pAdapter))
1937 {
1938 //Block on a completion variable. Can't wait forever though.
1939 wait_for_completion_interruptible_timeout(
1940 &pAdapter->session_close_comp_var,
1941 msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE));
1942 }
1943 }
1944
1945 break;
1946
1947 case WLAN_HDD_SOFTAP:
1948 case WLAN_HDD_P2P_GO:
1949 //Any softap specific cleanup here...
1950 mutex_lock(&pHddCtx->sap_lock);
1951 if (test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags))
1952 {
1953 VOS_STATUS status;
1954 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
1955
1956 //Stop Bss.
1957 status = WLANSAP_StopBss(pHddCtx->pvosContext);
1958 if (VOS_IS_STATUS_SUCCESS(status))
1959 {
1960 hdd_hostapd_state_t *pHostapdState =
1961 WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter);
1962
1963 status = vos_wait_single_event(&pHostapdState->vosEvent, 10000);
1964
1965 if (!VOS_IS_STATUS_SUCCESS(status))
1966 {
1967 hddLog(LOGE, "%s: failure waiting for WLANSAP_StopBss",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001968 __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001969 }
1970 }
1971 else
1972 {
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001973 hddLog(LOGE, "%s: failure in WLANSAP_StopBss", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001974 }
1975 clear_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags);
1976
1977 if (eHAL_STATUS_FAILURE ==
1978 ccmCfgSetInt(pHddCtx->hHal, WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG,
1979 0, NULL, eANI_BOOLEAN_FALSE))
1980 {
1981 hddLog(LOGE,
1982 "%s: Failed to set WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07001983 __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07001984 }
1985
1986 if ( eHAL_STATUS_FAILURE == ccmCfgSetInt((WLAN_HDD_GET_CTX(pAdapter))->hHal,
1987 WNI_CFG_ASSOC_RSP_ADDNIE_FLAG, 0, NULL,
1988 eANI_BOOLEAN_FALSE) )
1989 {
1990 hddLog(LOGE,
1991 "Could not pass on WNI_CFG_ASSOC_RSP_ADDNIE_FLAG to CCM");
1992 }
1993
1994 // Reset WNI_CFG_PROBE_RSP Flags
1995 wlan_hdd_reset_prob_rspies(pAdapter);
1996 kfree(pAdapter->sessionCtx.ap.beacon);
1997 pAdapter->sessionCtx.ap.beacon = NULL;
1998 }
1999 mutex_unlock(&pHddCtx->sap_lock);
2000 break;
2001 case WLAN_HDD_MONITOR:
2002 break;
2003 default:
2004 break;
2005 }
2006
2007 EXIT();
2008 return VOS_STATUS_SUCCESS;
2009}
2010
2011VOS_STATUS hdd_stop_all_adapters( hdd_context_t *pHddCtx )
2012{
2013 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2014 VOS_STATUS status;
2015 hdd_adapter_t *pAdapter;
2016
2017 ENTER();
2018
2019 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2020
2021 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2022 {
2023 pAdapter = pAdapterNode->pAdapter;
2024 netif_tx_disable(pAdapter->dev);
2025 netif_carrier_off(pAdapter->dev);
2026
2027 hdd_stop_adapter( pHddCtx, pAdapter );
2028
2029 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2030 pAdapterNode = pNext;
2031 }
2032
2033 EXIT();
2034
2035 return VOS_STATUS_SUCCESS;
2036}
2037
2038VOS_STATUS hdd_reset_all_adapters( hdd_context_t *pHddCtx )
2039{
2040 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2041 VOS_STATUS status;
2042 hdd_adapter_t *pAdapter;
2043
2044 ENTER();
2045
2046 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2047
2048 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2049 {
2050 pAdapter = pAdapterNode->pAdapter;
2051 netif_tx_disable(pAdapter->dev);
2052 netif_carrier_off(pAdapter->dev);
2053
2054 //Record whether STA is associated
2055 pAdapter->sessionCtx.station.bSendDisconnect =
2056 hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR( pAdapter )) ?
2057 VOS_TRUE : VOS_FALSE;
2058
2059 hdd_deinit_tx_rx(pAdapter);
2060 hdd_wmm_adapter_close(pAdapter);
2061
2062 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2063 pAdapterNode = pNext;
2064 }
2065
2066 EXIT();
2067
2068 return VOS_STATUS_SUCCESS;
2069}
2070
2071VOS_STATUS hdd_start_all_adapters( hdd_context_t *pHddCtx )
2072{
2073 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2074 VOS_STATUS status;
2075 hdd_adapter_t *pAdapter;
2076 v_MACADDR_t bcastMac = VOS_MAC_ADDR_BROADCAST_INITIALIZER;
2077
2078 ENTER();
2079
2080 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2081
2082 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2083 {
2084 pAdapter = pAdapterNode->pAdapter;
2085
2086 switch(pAdapter->device_mode)
2087 {
2088 case WLAN_HDD_INFRA_STATION:
2089 case WLAN_HDD_P2P_CLIENT:
Jeff Johnsone7245742012-09-05 17:12:55 -07002090 case WLAN_HDD_P2P_DEVICE:
Jeff Johnson295189b2012-06-20 16:38:30 -07002091 hdd_init_station_mode(pAdapter);
2092 /* Open the gates for HDD to receive Wext commands */
2093 pAdapter->isLinkUpSvcNeeded = FALSE;
Madan Mohan Koyyalamudi2a1ba772012-10-11 14:59:06 -07002094 pHddCtx->scan_info.mScanPending = FALSE;
2095 pHddCtx->scan_info.waitScanResult = FALSE;
Jeff Johnson295189b2012-06-20 16:38:30 -07002096
2097 //Trigger the initial scan
2098 hdd_wlan_initial_scan(pAdapter);
2099
2100 //Indicate disconnect event to supplicant if associated previously
2101 if(pAdapter->sessionCtx.station.bSendDisconnect)
2102 {
2103 union iwreq_data wrqu;
2104 memset(&wrqu, '\0', sizeof(wrqu));
2105 wrqu.ap_addr.sa_family = ARPHRD_ETHER;
2106 memset(wrqu.ap_addr.sa_data,'\0',ETH_ALEN);
2107 wireless_send_event(pAdapter->dev, SIOCGIWAP, &wrqu, NULL);
2108 pAdapter->sessionCtx.station.bSendDisconnect = VOS_FALSE;
2109
2110#ifdef CONFIG_CFG80211
2111 /* indicate disconnected event to nl80211 */
2112 cfg80211_disconnected(pAdapter->dev, WLAN_REASON_UNSPECIFIED,
2113 NULL, 0, GFP_KERNEL);
2114#endif
2115 }
2116 break;
2117
2118 case WLAN_HDD_SOFTAP:
2119 /* softAP can handle SSR */
2120 break;
2121
2122 case WLAN_HDD_P2P_GO:
2123#ifdef CONFIG_CFG80211
2124 hddLog(VOS_TRACE_LEVEL_ERROR, "%s [SSR] send restart supplicant",
2125 __func__);
2126 /* event supplicant to restart */
2127 cfg80211_del_sta(pAdapter->dev,
2128 (const u8 *)&bcastMac.bytes[0], GFP_KERNEL);
2129#endif
2130 break;
2131
2132 case WLAN_HDD_MONITOR:
2133 /* monitor interface start */
2134 break;
2135 default:
2136 break;
2137 }
2138
2139 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2140 pAdapterNode = pNext;
2141 }
2142
2143 EXIT();
2144
2145 return VOS_STATUS_SUCCESS;
2146}
2147
2148VOS_STATUS hdd_reconnect_all_adapters( hdd_context_t *pHddCtx )
2149{
2150 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2151 hdd_adapter_t *pAdapter;
2152 VOS_STATUS status;
2153 v_U32_t roamId;
2154
2155 ENTER();
2156
2157 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2158
2159 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2160 {
2161 pAdapter = pAdapterNode->pAdapter;
2162
2163 if( (WLAN_HDD_INFRA_STATION == pAdapter->device_mode) ||
2164 (WLAN_HDD_P2P_CLIENT == pAdapter->device_mode) )
2165 {
2166 hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
2167 hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
2168
2169 pHddStaCtx->conn_info.connState = eConnectionState_NotConnected;
2170 init_completion(&pAdapter->disconnect_comp_var);
2171 sme_RoamDisconnect(pHddCtx->hHal, pAdapter->sessionId,
2172 eCSR_DISCONNECT_REASON_UNSPECIFIED);
2173
2174 wait_for_completion_interruptible_timeout(
2175 &pAdapter->disconnect_comp_var,
2176 msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT));
2177
2178 pWextState->roamProfile.csrPersona = pAdapter->device_mode;
2179 pHddCtx->isAmpAllowed = VOS_FALSE;
2180 sme_RoamConnect(pHddCtx->hHal,
2181 pAdapter->sessionId, &(pWextState->roamProfile),
2182 &roamId);
2183 }
2184
2185 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2186 pAdapterNode = pNext;
2187 }
2188
2189 EXIT();
2190
2191 return VOS_STATUS_SUCCESS;
2192}
2193
Madan Mohan Koyyalamudib5da5332012-10-15 17:23:21 -07002194bool hdd_is_ssr_required( void)
Jeff Johnson295189b2012-06-20 16:38:30 -07002195{
Madan Mohan Koyyalamudib5da5332012-10-15 17:23:21 -07002196 return (isSsrRequired == HDD_SSR_REQUIRED);
Jeff Johnson295189b2012-06-20 16:38:30 -07002197}
2198
Madan Mohan Koyyalamudib5da5332012-10-15 17:23:21 -07002199/* Once SSR is disabled then it cannot be set. */
2200void hdd_set_ssr_required( e_hdd_ssr_required value)
Jeff Johnson295189b2012-06-20 16:38:30 -07002201{
Madan Mohan Koyyalamudib5da5332012-10-15 17:23:21 -07002202 if (HDD_SSR_DISABLED == isSsrRequired)
2203 return;
2204
Jeff Johnson295189b2012-06-20 16:38:30 -07002205 isSsrRequired = value;
2206}
2207
2208VOS_STATUS hdd_get_front_adapter( hdd_context_t *pHddCtx,
2209 hdd_adapter_list_node_t** ppAdapterNode)
2210{
2211 VOS_STATUS status;
2212 spin_lock(&pHddCtx->hddAdapters.lock);
2213 status = hdd_list_peek_front ( &pHddCtx->hddAdapters,
2214 (hdd_list_node_t**) ppAdapterNode );
2215 spin_unlock(&pHddCtx->hddAdapters.lock);
2216 return status;
2217}
2218
2219VOS_STATUS hdd_get_next_adapter( hdd_context_t *pHddCtx,
2220 hdd_adapter_list_node_t* pAdapterNode,
2221 hdd_adapter_list_node_t** pNextAdapterNode)
2222{
2223 VOS_STATUS status;
2224 spin_lock(&pHddCtx->hddAdapters.lock);
2225 status = hdd_list_peek_next ( &pHddCtx->hddAdapters,
2226 (hdd_list_node_t*) pAdapterNode,
2227 (hdd_list_node_t**)pNextAdapterNode );
2228
2229 spin_unlock(&pHddCtx->hddAdapters.lock);
2230 return status;
2231}
2232
2233VOS_STATUS hdd_remove_adapter( hdd_context_t *pHddCtx,
2234 hdd_adapter_list_node_t* pAdapterNode)
2235{
2236 VOS_STATUS status;
2237 spin_lock(&pHddCtx->hddAdapters.lock);
2238 status = hdd_list_remove_node ( &pHddCtx->hddAdapters,
2239 &pAdapterNode->node );
2240 spin_unlock(&pHddCtx->hddAdapters.lock);
2241 return status;
2242}
2243
2244VOS_STATUS hdd_remove_front_adapter( hdd_context_t *pHddCtx,
2245 hdd_adapter_list_node_t** ppAdapterNode)
2246{
2247 VOS_STATUS status;
2248 spin_lock(&pHddCtx->hddAdapters.lock);
2249 status = hdd_list_remove_front( &pHddCtx->hddAdapters,
2250 (hdd_list_node_t**) ppAdapterNode );
2251 spin_unlock(&pHddCtx->hddAdapters.lock);
2252 return status;
2253}
2254
2255VOS_STATUS hdd_add_adapter_back( hdd_context_t *pHddCtx,
2256 hdd_adapter_list_node_t* pAdapterNode)
2257{
2258 VOS_STATUS status;
2259 spin_lock(&pHddCtx->hddAdapters.lock);
2260 status = hdd_list_insert_back ( &pHddCtx->hddAdapters,
2261 (hdd_list_node_t*) pAdapterNode );
2262 spin_unlock(&pHddCtx->hddAdapters.lock);
2263 return status;
2264}
2265
2266VOS_STATUS hdd_add_adapter_front( hdd_context_t *pHddCtx,
2267 hdd_adapter_list_node_t* pAdapterNode)
2268{
2269 VOS_STATUS status;
2270 spin_lock(&pHddCtx->hddAdapters.lock);
2271 status = hdd_list_insert_front ( &pHddCtx->hddAdapters,
2272 (hdd_list_node_t*) pAdapterNode );
2273 spin_unlock(&pHddCtx->hddAdapters.lock);
2274 return status;
2275}
2276
2277hdd_adapter_t * hdd_get_adapter_by_macaddr( hdd_context_t *pHddCtx,
2278 tSirMacAddr macAddr )
2279{
2280 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2281 hdd_adapter_t *pAdapter;
2282 VOS_STATUS status;
2283
2284 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2285
2286 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2287 {
2288 pAdapter = pAdapterNode->pAdapter;
2289
2290 if( pAdapter && vos_mem_compare( pAdapter->macAddressCurrent.bytes,
2291 macAddr, sizeof(tSirMacAddr) ) )
2292 {
2293 return pAdapter;
2294 }
2295 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2296 pAdapterNode = pNext;
2297 }
2298
2299 return NULL;
2300
2301}
2302
2303hdd_adapter_t * hdd_get_adapter_by_name( hdd_context_t *pHddCtx, tANI_U8 *name )
2304{
2305 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2306 hdd_adapter_t *pAdapter;
2307 VOS_STATUS status;
2308
2309 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2310
2311 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2312 {
2313 pAdapter = pAdapterNode->pAdapter;
2314
2315 if( pAdapter && !strncmp( pAdapter->dev->name, (const char *)name,
2316 IFNAMSIZ ) )
2317 {
2318 return pAdapter;
2319 }
2320 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2321 pAdapterNode = pNext;
2322 }
2323
2324 return NULL;
2325
2326}
2327
2328hdd_adapter_t * hdd_get_adapter( hdd_context_t *pHddCtx, device_mode_t mode )
2329{
2330 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2331 hdd_adapter_t *pAdapter;
2332 VOS_STATUS status;
2333
2334 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2335
2336 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2337 {
2338 pAdapter = pAdapterNode->pAdapter;
2339
2340 if( pAdapter && (mode == pAdapter->device_mode) )
2341 {
2342 return pAdapter;
2343 }
2344 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2345 pAdapterNode = pNext;
2346 }
2347
2348 return NULL;
2349
2350}
2351
2352//Remove this function later
2353hdd_adapter_t * hdd_get_mon_adapter( hdd_context_t *pHddCtx )
2354{
2355 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2356 hdd_adapter_t *pAdapter;
2357 VOS_STATUS status;
2358
2359 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2360
2361 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2362 {
2363 pAdapter = pAdapterNode->pAdapter;
2364
2365 if( pAdapter && WLAN_HDD_MONITOR == pAdapter->device_mode )
2366 {
2367 return pAdapter;
2368 }
2369
2370 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2371 pAdapterNode = pNext;
2372 }
2373
2374 return NULL;
2375
2376}
2377
2378#ifdef CONFIG_CFG80211
2379/**---------------------------------------------------------------------------
2380
2381 \brief hdd_set_monitor_tx_adapter() -
2382
2383 This API initializes the adapter to be used while transmitting on monitor
2384 adapter.
2385
2386 \param - pHddCtx - Pointer to the HDD context.
2387 pAdapter - Adapter that will used for TX. This can be NULL.
2388 \return - None.
2389 --------------------------------------------------------------------------*/
2390void wlan_hdd_set_monitor_tx_adapter( hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter )
2391{
2392 hdd_adapter_t *pMonAdapter;
2393
2394 pMonAdapter = hdd_get_adapter( pHddCtx, WLAN_HDD_MONITOR );
2395
2396 if( NULL != pMonAdapter )
2397 {
2398 pMonAdapter->sessionCtx.monitor.pAdapterForTx = pAdapter;
2399 }
2400}
2401#endif
2402/**---------------------------------------------------------------------------
2403
2404 \brief hdd_select_queue() -
2405
2406 This API returns the operating channel of the requested device mode
2407
2408 \param - pHddCtx - Pointer to the HDD context.
2409 - mode - Device mode for which operating channel is required
2410 suported modes - WLAN_HDD_INFRA_STATION, WLAN_HDD_P2P_CLIENT
2411 WLAN_HDD_SOFTAP, WLAN_HDD_P2P_GO.
2412 \return - channel number. "0" id the requested device is not found OR it is not connected.
2413 --------------------------------------------------------------------------*/
2414v_U8_t hdd_get_operating_channel( hdd_context_t *pHddCtx, device_mode_t mode )
2415{
2416 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
2417 VOS_STATUS status;
2418 hdd_adapter_t *pAdapter;
2419 v_U8_t operatingChannel = 0;
2420
2421 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
2422
2423 while ( NULL != pAdapterNode && VOS_STATUS_SUCCESS == status )
2424 {
2425 pAdapter = pAdapterNode->pAdapter;
2426
2427 if( mode == pAdapter->device_mode )
2428 {
2429 switch(pAdapter->device_mode)
2430 {
2431 case WLAN_HDD_INFRA_STATION:
2432 case WLAN_HDD_P2P_CLIENT:
2433 if( hdd_connIsConnected( WLAN_HDD_GET_STATION_CTX_PTR( pAdapter )) )
2434 operatingChannel = (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.operationChannel;
2435 break;
2436 case WLAN_HDD_SOFTAP:
2437 case WLAN_HDD_P2P_GO:
2438 /*softap connection info */
2439 if(test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags))
2440 operatingChannel = (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->operatingChannel;
2441 break;
2442 default:
2443 break;
2444 }
2445
2446 break; //Found the device of interest. break the loop
2447 }
2448
2449 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
2450 pAdapterNode = pNext;
2451 }
2452 return operatingChannel;
2453}
2454
2455#ifdef WLAN_FEATURE_PACKET_FILTERING
2456/**---------------------------------------------------------------------------
2457
2458 \brief hdd_set_multicast_list() -
2459
2460 This used to set the multicast address list.
2461
2462 \param - dev - Pointer to the WLAN device.
2463 - skb - Pointer to OS packet (sk_buff).
2464 \return - success/fail
2465
2466 --------------------------------------------------------------------------*/
2467static void hdd_set_multicast_list(struct net_device *dev)
2468{
2469 hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
2470 hdd_context_t *pHddCtx;
2471 int mc_count;
2472 int i = 0;
2473 struct netdev_hw_addr *ha;
2474 pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
2475 if (NULL == pHddCtx)
2476 {
2477 hddLog(VOS_TRACE_LEVEL_ERROR,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002478 "%s: HDD context is Null", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07002479 return;
2480 }
2481
2482 if (dev->flags & IFF_ALLMULTI)
2483 {
2484 hddLog(VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002485 "%s: allow all multicast frames", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07002486 pHddCtx->mc_addr_list.mc_cnt = 0;
2487 }
2488 else
2489 {
2490 mc_count = netdev_mc_count(dev);
2491 hddLog(VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002492 "%s: mc_count = %u", __func__, mc_count);
Jeff Johnson295189b2012-06-20 16:38:30 -07002493 if (mc_count > WLAN_HDD_MAX_MC_ADDR_LIST)
2494 {
2495 hddLog(VOS_TRACE_LEVEL_INFO,
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002496 "%s: No free filter available; allow all multicast frames", __func__);
Jeff Johnson295189b2012-06-20 16:38:30 -07002497 pHddCtx->mc_addr_list.mc_cnt = 0;
2498 return;
2499 }
2500
2501 pHddCtx->mc_addr_list.mc_cnt = mc_count;
2502
2503 netdev_for_each_mc_addr(ha, dev) {
2504 if (i == mc_count)
2505 break;
2506 memset(&(pHddCtx->mc_addr_list.addr[i][0]), 0, ETH_ALEN);
2507 memcpy(&(pHddCtx->mc_addr_list.addr[i][0]), ha->addr, ETH_ALEN);
2508 hddLog(VOS_TRACE_LEVEL_INFO, "\n%s: mlist[%d] = %02x:%02x:%02x:%02x:%02x:%02x",
2509 __func__, i,
2510 pHddCtx->mc_addr_list.addr[i][0], pHddCtx->mc_addr_list.addr[i][1],
2511 pHddCtx->mc_addr_list.addr[i][2], pHddCtx->mc_addr_list.addr[i][3],
2512 pHddCtx->mc_addr_list.addr[i][4], pHddCtx->mc_addr_list.addr[i][5]);
2513 i++;
2514 }
2515 }
2516 return;
2517}
2518#endif
2519
2520/**---------------------------------------------------------------------------
2521
2522 \brief hdd_select_queue() -
2523
2524 This function is registered with the Linux OS for network
2525 core to decide which queue to use first.
2526
2527 \param - dev - Pointer to the WLAN device.
2528 - skb - Pointer to OS packet (sk_buff).
2529 \return - ac, Queue Index/access category corresponding to UP in IP header
2530
2531 --------------------------------------------------------------------------*/
2532v_U16_t hdd_select_queue(struct net_device *dev,
2533 struct sk_buff *skb)
2534{
2535 return hdd_wmm_select_queue(dev, skb);
2536}
2537
2538
2539/**---------------------------------------------------------------------------
2540
2541 \brief hdd_wlan_initial_scan() -
2542
2543 This function triggers the initial scan
2544
2545 \param - pAdapter - Pointer to the HDD adapter.
2546
2547 --------------------------------------------------------------------------*/
2548void hdd_wlan_initial_scan(hdd_adapter_t *pAdapter)
2549{
2550 tCsrScanRequest scanReq;
2551 tCsrChannelInfo channelInfo;
2552 eHalStatus halStatus;
2553 unsigned long scanId;
2554 hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
2555
2556 vos_mem_zero(&scanReq, sizeof(tCsrScanRequest));
2557 vos_mem_set(&scanReq.bssid, sizeof(tCsrBssid), 0xff);
2558 scanReq.BSSType = eCSR_BSS_TYPE_ANY;
2559
2560 if(sme_Is11dSupported(pHddCtx->hHal))
2561 {
2562 halStatus = sme_ScanGetBaseChannels( pHddCtx->hHal, &channelInfo );
2563 if ( HAL_STATUS_SUCCESS( halStatus ) )
2564 {
2565 scanReq.ChannelInfo.ChannelList = vos_mem_malloc(channelInfo.numOfChannels);
2566 if( !scanReq.ChannelInfo.ChannelList )
2567 {
2568 hddLog(VOS_TRACE_LEVEL_ERROR, "%s kmalloc failed", __func__);
2569 vos_mem_free(channelInfo.ChannelList);
2570 return;
2571 }
2572 vos_mem_copy(scanReq.ChannelInfo.ChannelList, channelInfo.ChannelList,
2573 channelInfo.numOfChannels);
2574 scanReq.ChannelInfo.numOfChannels = channelInfo.numOfChannels;
2575 vos_mem_free(channelInfo.ChannelList);
2576 }
2577
2578 scanReq.scanType = eSIR_PASSIVE_SCAN;
2579 scanReq.requestType = eCSR_SCAN_REQUEST_11D_SCAN;
2580 scanReq.maxChnTime = pHddCtx->cfg_ini->nPassiveMaxChnTime;
2581 scanReq.minChnTime = pHddCtx->cfg_ini->nPassiveMinChnTime;
2582 }
2583 else
2584 {
2585 scanReq.scanType = eSIR_ACTIVE_SCAN;
2586 scanReq.requestType = eCSR_SCAN_REQUEST_FULL_SCAN;
2587 scanReq.maxChnTime = pHddCtx->cfg_ini->nActiveMaxChnTime;
2588 scanReq.minChnTime = pHddCtx->cfg_ini->nActiveMinChnTime;
2589 }
2590
2591 halStatus = sme_ScanRequest(pHddCtx->hHal, pAdapter->sessionId, &scanReq, &scanId, NULL, NULL);
2592 if ( !HAL_STATUS_SUCCESS( halStatus ) )
2593 {
2594 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: sme_ScanRequest failed status code %d",
2595 __func__, halStatus );
2596 }
2597
2598 if(sme_Is11dSupported(pHddCtx->hHal))
2599 vos_mem_free(scanReq.ChannelInfo.ChannelList);
2600}
2601
2602struct fullPowerContext
2603{
2604 struct completion completion;
2605 unsigned int magic;
2606};
2607#define POWER_CONTEXT_MAGIC 0x504F5752 //POWR
2608
2609/**---------------------------------------------------------------------------
2610
2611 \brief hdd_full_power_callback() - HDD full power callback function
2612
2613 This is the function invoked by SME to inform the result of a full power
2614 request issued by HDD
2615
2616 \param - callbackcontext - Pointer to cookie
2617 \param - status - result of request
2618
2619 \return - None
2620
2621 --------------------------------------------------------------------------*/
2622static void hdd_full_power_callback(void *callbackContext, eHalStatus status)
2623{
2624 struct fullPowerContext *pContext = callbackContext;
2625
2626 hddLog(VOS_TRACE_LEVEL_INFO,
2627 "%s: context = %p, status = %d", pContext, status);
2628
2629 if (NULL == callbackContext)
2630 {
2631 hddLog(VOS_TRACE_LEVEL_ERROR,
2632 "%s: Bad param, context [%p]",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002633 __func__, callbackContext);
Jeff Johnson295189b2012-06-20 16:38:30 -07002634 return;
2635 }
2636
2637 /* there is a race condition that exists between this callback function
2638 and the caller since the caller could time out either before or
2639 while this code is executing. we'll assume the timeout hasn't
2640 occurred, but we'll verify that right before we save our work */
2641
2642 if (POWER_CONTEXT_MAGIC != pContext->magic)
2643 {
2644 /* the caller presumably timed out so there is nothing we can do */
2645 hddLog(VOS_TRACE_LEVEL_WARN,
2646 "%s: Invalid context, magic [%08x]",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002647 __func__, pContext->magic);
Jeff Johnson295189b2012-06-20 16:38:30 -07002648 return;
2649 }
2650
2651 /* the race is on. caller could have timed out immediately after
2652 we verified the magic, but if so, caller will wait a short time
2653 for us to notify the caller, so the context will stay valid */
2654 complete(&pContext->completion);
2655}
2656
2657/**---------------------------------------------------------------------------
2658
2659 \brief hdd_wlan_exit() - HDD WLAN exit function
2660
2661 This is the driver exit point (invoked during rmmod)
2662
2663 \param - pHddCtx - Pointer to the HDD Context
2664
2665 \return - None
2666
2667 --------------------------------------------------------------------------*/
2668void hdd_wlan_exit(hdd_context_t *pHddCtx)
2669{
2670 eHalStatus halStatus;
2671 v_CONTEXT_t pVosContext = pHddCtx->pvosContext;
2672 VOS_STATUS vosStatus;
2673#ifdef ANI_BUS_TYPE_SDIO
2674 struct sdio_func *sdio_func_dev = NULL;
2675#endif // ANI_BUS_TYPE_SDIO
2676#ifdef CONFIG_CFG80211
2677 struct wiphy *wiphy = pHddCtx->wiphy;
2678#endif
2679#ifdef FEATURE_WLAN_INTEGRATED_SOC
2680 hdd_adapter_t* pAdapter;
2681#endif
2682 struct fullPowerContext powerContext;
2683 long lrc;
2684
2685 ENTER();
2686
Jeff Johnsone7245742012-09-05 17:12:55 -07002687 // Unloading, restart logic is no more required.
2688 wlan_hdd_restart_deinit(pHddCtx);
2689
Jeff Johnson295189b2012-06-20 16:38:30 -07002690#ifdef CONFIG_CFG80211
2691#ifdef WLAN_SOFTAP_FEATURE
2692 if (VOS_STA_SAP_MODE != hdd_get_conparam())
2693#endif
2694 {
2695#ifdef ANI_MANF_DIAG
2696 if (VOS_FTM_MODE != hdd_get_conparam())
2697#endif /* ANI_MANF_DIAG */
2698 {
2699 hdd_adapter_t* pAdapter = hdd_get_adapter(pHddCtx,
2700 WLAN_HDD_INFRA_STATION);
2701 if (pAdapter == NULL)
2702 pAdapter = hdd_get_adapter(pHddCtx, WLAN_HDD_P2P_CLIENT);
2703
2704 if (pAdapter != NULL)
2705 {
2706 wlan_hdd_cfg80211_pre_voss_stop(pAdapter);
2707 hdd_UnregisterWext(pAdapter->dev);
2708 }
2709 }
2710 }
2711#endif
2712
2713#ifdef ANI_MANF_DIAG
2714 if (VOS_FTM_MODE == hdd_get_conparam())
2715 {
2716 wlan_hdd_ftm_close(pHddCtx);
2717 goto free_hdd_ctx;
2718 }
2719#endif
2720 //Stop the Interface TX queue.
2721 //netif_tx_disable(pWlanDev);
2722 //netif_carrier_off(pWlanDev);
2723
2724#ifdef CONFIG_HAS_EARLYSUSPEND
2725 // unregister suspend/resume callbacks
2726 if(pHddCtx->cfg_ini->nEnableSuspend)
2727 {
2728 unregister_wlan_suspend();
2729 }
2730#endif
2731
2732#ifdef FEATURE_WLAN_INTEGRATED_SOC
2733#ifdef WLAN_SOFTAP_FEATURE
2734 if (VOS_STA_SAP_MODE == hdd_get_conparam())
2735 {
2736 pAdapter = hdd_get_adapter(pHddCtx,
2737 WLAN_HDD_SOFTAP);
2738 }
2739 else
2740 {
2741#endif
2742#ifdef ANI_MANF_DIAG
2743 if (VOS_FTM_MODE != hdd_get_conparam())
2744#endif /* ANI_MANF_DIAG */
2745 {
2746 pAdapter = hdd_get_adapter(pHddCtx,
2747 WLAN_HDD_INFRA_STATION);
2748 }
2749#ifdef WLAN_SOFTAP_FEATURE
2750 }
2751#endif
2752 /* DeRegister with platform driver as client for Suspend/Resume */
2753 vosStatus = hddDeregisterPmOps(pHddCtx);
2754 if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) )
2755 {
2756 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDeregisterPmOps failed",__func__);
2757 VOS_ASSERT(0);
2758 }
2759
2760 vosStatus = hddDevTmUnregisterNotifyCallback(pHddCtx);
2761 if ( !VOS_IS_STATUS_SUCCESS( vosStatus ) )
2762 {
2763 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: hddDevTmUnregisterNotifyCallback failed",__func__);
2764 }
2765#endif //FEATURE_WLAN_INTEGRATED_SOC
2766
2767 // Cancel any outstanding scan requests. We are about to close all
2768 // of our adapters, but an adapter structure is what SME passes back
2769 // to our callback function. Hence if there are any outstanding scan
2770 // requests then there is a race condition between when the adapter
2771 // is closed and when the callback is invoked. We try to resolve that
2772 // race condition here by canceling any outstanding scans before we
2773 // close the adapters.
2774 // Note that the scans may be cancelled in an asynchronous manner, so
2775 // ideally there needs to be some kind of synchronization. Rather than
2776 // introduce a new synchronization here, we will utilize the fact that
2777 // we are about to Request Full Power, and since that is synchronized,
2778 // the expectation is that by the time Request Full Power has completed,
2779 // all scans will be cancelled.
2780 hdd_abort_mac_scan( pHddCtx );
2781
2782 //Disable IMPS/BMPS as we do not want the device to enter any power
2783 //save mode during shutdown
2784 sme_DisablePowerSave(pHddCtx->hHal, ePMC_IDLE_MODE_POWER_SAVE);
2785 sme_DisablePowerSave(pHddCtx->hHal, ePMC_BEACON_MODE_POWER_SAVE);
2786 sme_DisablePowerSave(pHddCtx->hHal, ePMC_UAPSD_MODE_POWER_SAVE);
2787
2788 //Ensure that device is in full power as we will touch H/W during vos_Stop
2789 init_completion(&powerContext.completion);
2790 powerContext.magic = POWER_CONTEXT_MAGIC;
2791
2792 halStatus = sme_RequestFullPower(pHddCtx->hHal, hdd_full_power_callback,
2793 &powerContext, eSME_FULL_PWR_NEEDED_BY_HDD);
2794
2795 if (eHAL_STATUS_SUCCESS != halStatus)
2796 {
2797 if (eHAL_STATUS_PMC_PENDING == halStatus)
2798 {
2799 /* request was sent -- wait for the response */
2800 lrc = wait_for_completion_interruptible_timeout(
2801 &powerContext.completion,
2802 msecs_to_jiffies(WLAN_WAIT_TIME_POWER));
2803 /* either we have a response or we timed out
2804 either way, first invalidate our magic */
2805 powerContext.magic = 0;
2806 if (lrc <= 0)
2807 {
2808 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: %s while requesting full power",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002809 __func__, (0 == lrc) ? "timeout" : "interrupt");
Jeff Johnson295189b2012-06-20 16:38:30 -07002810 /* there is a race condition such that the callback
2811 function could be executing at the same time we are. of
2812 primary concern is if the callback function had already
2813 verified the "magic" but hasn't yet set the completion
2814 variable. Since the completion variable is on our
2815 stack, we'll delay just a bit to make sure the data is
2816 still valid if that is the case */
2817 msleep(50);
2818 }
2819 }
2820 else
2821 {
2822 hddLog(VOS_TRACE_LEVEL_ERROR,
2823 "%s: Request for Full Power failed, status %d",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07002824 __func__, halStatus);
Jeff Johnson295189b2012-06-20 16:38:30 -07002825 VOS_ASSERT(0);
2826 /* continue -- need to clean up as much as possible */
2827 }
2828 }
2829
2830 // Unregister the Net Device Notifier
2831 unregister_netdevice_notifier(&hdd_netdev_notifier);
2832
Jeff Johnson295189b2012-06-20 16:38:30 -07002833 hdd_stop_all_adapters( pHddCtx );
2834
2835#ifdef ANI_BUS_TYPE_SDIO
2836 sdio_func_dev = libra_getsdio_funcdev();
2837
2838 if(sdio_func_dev == NULL)
2839 {
2840 hddLog(VOS_TRACE_LEVEL_FATAL, "%s: sdio_func_dev is NULL!",__func__);
2841 VOS_ASSERT(0);
2842 return;
2843 }
2844
2845 sd_claim_host(sdio_func_dev);
2846
2847 /* Disable SDIO IRQ since we are exiting */
2848 libra_enable_sdio_irq(sdio_func_dev, 0);
2849
2850 sd_release_host(sdio_func_dev);
2851#endif // ANI_BUS_TYPE_SDIO
2852
2853#ifdef WLAN_BTAMP_FEATURE
2854 vosStatus = WLANBAP_Stop(pVosContext);
2855 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2856 {
2857 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR,
2858 "%s: Failed to stop BAP",__func__);
2859 }
2860#endif //WLAN_BTAMP_FEATURE
2861
2862 //Stop all the modules
2863 vosStatus = vos_stop( pVosContext );
2864 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2865 {
2866 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2867 "%s: Failed to stop VOSS",__func__);
2868 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2869 }
2870
2871#ifdef ANI_BUS_TYPE_SDIO
2872 vosStatus = WLANBAL_Stop( pVosContext );
2873
2874 hddLog(VOS_TRACE_LEVEL_ERROR,"WLAN BAL STOP\n");
2875 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2876 {
2877 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2878 "%s: Failed to stop BAL",__func__);
2879 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2880 }
2881
2882 msleep(50);
2883 //Put the chip is standby before asserting deep sleep
2884 vosStatus = WLANBAL_SuspendChip( pVosContext );
2885
2886 hddLog(VOS_TRACE_LEVEL_ERROR,"WLAN Suspend Chip\n");
2887
2888 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2889 {
2890 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2891 "%s: Failed to suspend chip ",__func__);
2892 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2893 }
2894 //Invoke SAL stop
2895 vosStatus = WLANSAL_Stop( pVosContext );
2896 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2897 {
2898 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2899 "%s: Failed to stop SAL",__func__);
2900 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2901 }
2902
2903#endif // ANI_BUS_TYPE_SDIO
2904
2905 //Assert Deep sleep signal now to put Libra HW in lowest power state
2906 vosStatus = vos_chipAssertDeepSleep( NULL, NULL, NULL );
2907 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2908
2909 //Vote off any PMIC voltage supplies
2910 vos_chipPowerDown(NULL, NULL, NULL);
2911
2912 vos_chipVoteOffXOBuffer(NULL, NULL, NULL);
2913
2914 //Clean up HDD Nlink Service
2915 send_btc_nlink_msg(WLAN_MODULE_DOWN_IND, 0);
2916 nl_srv_exit();
2917
2918 //This requires pMac access, Call this before vos_close().
2919#ifdef CONFIG_HAS_EARLYSUSPEND
2920 hdd_unregister_mcast_bcast_filter(pHddCtx);
2921#endif
2922
2923 //Close the scheduler before calling vos_close to make sure no thread is
2924 // scheduled after the each module close is called i.e after all the data
2925 // structures are freed.
2926 vosStatus = vos_sched_close( pVosContext );
2927 if (!VOS_IS_STATUS_SUCCESS(vosStatus)) {
2928 VOS_TRACE( VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL,
2929 "%s: Failed to close VOSS Scheduler",__func__);
2930 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2931 }
Jeff Johnsone7245742012-09-05 17:12:55 -07002932
2933#ifdef WLAN_FEATURE_HOLD_RX_WAKELOCK
2934 /* Destroy the wake lock */
2935 wake_lock_destroy(&pHddCtx->rx_wake_lock);
2936#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07002937
2938 //Close VOSS
2939 //This frees pMac(HAL) context. There should not be any call that requires pMac access after this.
2940 vos_close(pVosContext);
2941
2942#ifdef ANI_BUS_TYPE_SDIO
2943 vosStatus = WLANBAL_Close(pVosContext);
2944 if (!VOS_IS_STATUS_SUCCESS(vosStatus))
2945 {
2946 VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
2947 "%s: Failed to close BAL",__func__);
2948 VOS_ASSERT( VOS_IS_STATUS_SUCCESS( vosStatus ) );
2949 }
2950 hddLog(VOS_TRACE_LEVEL_ERROR,"Returned WLAN BAL CLOSE\n\n\n\n");
2951#endif // ANI_BUS_TYPE_SDIO
2952
2953 //Close Watchdog
2954 if(pHddCtx->cfg_ini->fIsLogpEnabled)
2955 vos_watchdog_close(pVosContext);
2956
2957 /* Cancel the vote for XO Core ON.
2958 * This is done here to ensure there is no race condition since MC, TX and WD threads have
2959 * exited at this point
2960 */
2961 hddLog(VOS_TRACE_LEVEL_WARN, "In module exit: Cancel the vote for XO Core ON"
2962 " when WLAN is turned OFF\n");
2963 if (vos_chipVoteXOCore(NULL, NULL, NULL, VOS_FALSE) != VOS_STATUS_SUCCESS)
2964 {
2965 hddLog(VOS_TRACE_LEVEL_ERROR, "Could not cancel the vote for XO Core ON."
2966 " Not returning failure."
2967 " Power consumed will be high\n");
2968 }
2969
2970 hdd_close_all_adapters( pHddCtx );
2971
2972
2973 //Free up dynamically allocated members inside HDD Adapter
2974 kfree(pHddCtx->cfg_ini);
2975 pHddCtx->cfg_ini= NULL;
2976
2977 /* free the power on lock from platform driver */
2978 if (free_riva_power_on_lock("wlan"))
2979 {
2980 hddLog(VOS_TRACE_LEVEL_ERROR, "%s: failed to free power on lock",
2981 __func__);
2982 }
2983
2984#ifdef ANI_MANF_DIAG
2985free_hdd_ctx:
2986#endif
2987#ifdef CONFIG_CFG80211
2988 wiphy_unregister(wiphy) ;
2989 wiphy_free(wiphy) ;
2990#else
2991 vos_mem_free( pHddCtx );
2992#endif
2993 if (hdd_is_ssr_required())
2994 {
2995 /* WDI timeout had happened during unload, so SSR is needed here */
Madan Mohan Koyyalamudi3246f5b2012-10-15 15:40:02 -07002996 subsystem_restart("wcnss");
Jeff Johnson295189b2012-06-20 16:38:30 -07002997 msleep(5000);
2998 }
2999 hdd_set_ssr_required (VOS_FALSE);
3000}
3001
3002
3003/**---------------------------------------------------------------------------
3004
3005 \brief hdd_update_config_from_nv() - Function to update the contents of
3006 the running configuration with parameters taken from NV storage
3007
3008 \param - pHddCtx - Pointer to the HDD global context
3009
3010 \return - VOS_STATUS_SUCCESS if successful
3011
3012 --------------------------------------------------------------------------*/
3013static VOS_STATUS hdd_update_config_from_nv(hdd_context_t* pHddCtx)
3014{
3015#ifndef FEATURE_WLAN_INTEGRATED_SOC
3016 eHalStatus halStatus;
3017#endif
3018
3019#ifdef FEATURE_WLAN_INTEGRATED_SOC
3020 v_BOOL_t itemIsValid = VOS_FALSE;
3021 VOS_STATUS status;
3022 v_MACADDR_t macFromNV[VOS_MAX_CONCURRENCY_PERSONA];
3023 v_U8_t macLoop;
3024
3025 /*If the NV is valid then get the macaddress from nv else get it from qcom_cfg.ini*/
3026 status = vos_nv_getValidity(VNV_FIELD_IMAGE, &itemIsValid);
3027 if(status != VOS_STATUS_SUCCESS)
3028 {
3029 hddLog(VOS_TRACE_LEVEL_ERROR," vos_nv_getValidity() failed\n ");
3030 return VOS_STATUS_E_FAILURE;
3031 }
3032
3033 if (itemIsValid == VOS_TRUE)
3034 {
3035 hddLog(VOS_TRACE_LEVEL_INFO_HIGH," Reading the Macaddress from NV\n ");
3036 status = vos_nv_readMultiMacAddress((v_U8_t *)&macFromNV[0].bytes[0],
3037 VOS_MAX_CONCURRENCY_PERSONA);
3038 if(status != VOS_STATUS_SUCCESS)
3039 {
3040 /* Get MAC from NV fail, not update CFG info
3041 * INI MAC value will be used for MAC setting */
3042 hddLog(VOS_TRACE_LEVEL_ERROR," vos_nv_readMacAddress() failed\n ");
3043 return VOS_STATUS_E_FAILURE;
3044 }
3045
3046 /* If first MAC is not valid, treat all others are not valid
3047 * Then all MACs will be got from ini file */
3048 if(vos_is_macaddr_zero(&macFromNV[0]))
3049 {
3050 /* MAC address in NV file is not configured yet */
3051 hddLog(VOS_TRACE_LEVEL_WARN, "Invalid MAC in NV file");
3052 return VOS_STATUS_E_INVAL;
3053 }
3054
3055 /* Get MAC address from NV, update CFG info */
3056 for(macLoop = 0; macLoop < VOS_MAX_CONCURRENCY_PERSONA; macLoop++)
3057 {
3058 if(vos_is_macaddr_zero(&macFromNV[macLoop]))
3059 {
3060 printk(KERN_ERR "not valid MAC from NV for %d", macLoop);
3061 /* This MAC is not valid, skip it
3062 * This MAC will be got from ini file */
3063 }
3064 else
3065 {
3066 vos_mem_copy((v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[macLoop].bytes[0],
3067 (v_U8_t *)&macFromNV[macLoop].bytes[0],
3068 VOS_MAC_ADDR_SIZE);
3069 }
3070 }
3071 }
3072 else
3073 {
3074 hddLog(VOS_TRACE_LEVEL_ERROR, "NV ITEM, MAC Not valid");
3075 return VOS_STATUS_E_FAILURE;
3076 }
3077#endif /* FEATURE_WLAN_INTEGRATED_SOC */
3078
3079#ifndef FEATURE_WLAN_INTEGRATED_SOC
3080#if 1 /* need to fix for concurrency */
3081 // Set the MAC Address
3082 // Currently this is used by HAL to add self sta. Remove this once self sta is added as part of session open.
3083 halStatus = ccmCfgSetStr( pHddCtx->hHal, WNI_CFG_STA_ID,
3084 (v_U8_t *)&pHddCtx->cfg_ini->intfMacAddr[0],
3085 sizeof( pHddCtx->cfg_ini->intfMacAddr[0]),
3086 hdd_set_mac_addr_cb, VOS_FALSE );
3087
3088 if (!HAL_STATUS_SUCCESS( halStatus ))
3089 {
3090 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Failed to set MAC Address. "
3091 "HALStatus is %08d [x%08x]",__func__, halStatus, halStatus );
3092 return VOS_STATUS_E_FAILURE;
3093 }
3094#endif
3095#endif
3096
3097 return VOS_STATUS_SUCCESS;
3098}
3099
3100/**---------------------------------------------------------------------------
3101
3102 \brief hdd_post_voss_start_config() - HDD post voss start config helper
3103
3104 \param - pAdapter - Pointer to the HDD
3105
3106 \return - None
3107
3108 --------------------------------------------------------------------------*/
3109VOS_STATUS hdd_post_voss_start_config(hdd_context_t* pHddCtx)
3110{
3111 eHalStatus halStatus;
3112 v_U32_t listenInterval;
3113
3114#ifdef FEATURE_WLAN_NON_INTEGRATED_SOC
3115 /* In the non-integrated architecture we update the configuration from
3116 the INI file and from NV after vOSS has been started
3117 */
3118
3119 // Apply the cfg.ini to cfg.dat
3120 if (FALSE == hdd_update_config_dat(pHddCtx))
3121 {
3122 hddLog(VOS_TRACE_LEVEL_FATAL,"%s: config update failed",__func__ );
3123 return VOS_STATUS_E_FAILURE;
3124 }
3125
3126 // Apply the NV to cfg.dat
3127 if (VOS_STATUS_SUCCESS != hdd_update_config_from_nv(pHddCtx))
3128 {
3129 hddLog(VOS_TRACE_LEVEL_FATAL,
3130 "%s: config update from NV failed", __func__ );
3131 return VOS_STATUS_E_FAILURE;
3132 }
3133#endif // FEATURE_WLAN_NON_INTEGRATED_SOC
3134
3135 // Send ready indication to the HDD. This will kick off the MAC
3136 // into a 'running' state and should kick off an initial scan.
3137 halStatus = sme_HDDReadyInd( pHddCtx->hHal );
3138 if ( !HAL_STATUS_SUCCESS( halStatus ) )
3139 {
3140 hddLog(VOS_TRACE_LEVEL_ERROR,"%S: sme_HDDReadyInd() failed with status "
3141 "code %08d [x%08x]",__func__, halStatus, halStatus );
3142 return VOS_STATUS_E_FAILURE;
3143 }
3144
3145 // Set default LI into HDD context,
3146 // otherwise under some race condition, HDD will set 0 LI value into RIVA,
3147 // And RIVA will crash
3148 wlan_cfgGetInt(pHddCtx->hHal, WNI_CFG_LISTEN_INTERVAL, &listenInterval);
3149 pHddCtx->hdd_actual_LI_value = listenInterval;
3150
3151 return VOS_STATUS_SUCCESS;
3152}
3153
3154#ifdef ANI_BUS_TYPE_SDIO
3155
3156#ifndef ANI_MANF_DIAG
3157// Routine to initialize the PMU
3158void wlan_hdd_enable_deepsleep(v_VOID_t * pVosContext)
3159{
3160/*-------------- Need to fix this correctly while doing Deepsleep testing
3161 tANI_U32 regValue = 0;
3162
3163 regValue = QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_DEEP_SLEEP_EN_MASK |
3164 QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_1P23_LPM_AON_MASK_MASK |
3165 QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_1P23_LPM_SW_MASK_MASK |
3166 QWLAN_PMU_LDO_CTRL_REG_PMU_ANA_2P3_LPM_MASK_MASK;
3167
3168 WLANBAL_WriteRegister(pVosContext, QWLAN_PMU_LDO_CTRL_REG_REG, regValue);
3169---------------------*/
3170
3171 return;
3172}
3173#endif
3174#endif
3175
3176/* wake lock APIs for HDD */
3177void hdd_prevent_suspend(void)
3178{
Jeff Johnsone7245742012-09-05 17:12:55 -07003179#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07003180 wake_lock(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07003181#else
3182 wcnss_prevent_suspend();
3183#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07003184}
3185
3186void hdd_allow_suspend(void)
3187{
Jeff Johnsone7245742012-09-05 17:12:55 -07003188#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
Jeff Johnson295189b2012-06-20 16:38:30 -07003189 wake_unlock(&wlan_wake_lock);
Jeff Johnsone7245742012-09-05 17:12:55 -07003190#else
3191 wcnss_allow_suspend();
3192#endif
Jeff Johnson295189b2012-06-20 16:38:30 -07003193}
3194
Madan Mohan Koyyalamudi10d83a92012-09-28 15:47:05 -07003195void hdd_allow_suspend_timeout(v_U32_t timeout)
3196{
3197#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,5))
3198 wake_lock_timeout(&wlan_wake_lock, timeout);
3199#else
3200 /* Do nothing as there is no API in wcnss for timeout*/
3201#endif
3202}
3203
Jeff Johnson295189b2012-06-20 16:38:30 -07003204/**---------------------------------------------------------------------------
3205
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003206 \brief hdd_exchange_version_and_caps() - HDD function to exchange version and capability
3207 information between Host and Riva
3208
3209 This function gets reported version of FW
3210 It also finds the version of Riva headers used to compile the host
3211 It compares the above two and prints a warning if they are different
3212 It gets the SW and HW version string
3213 Finally, it exchanges capabilities between host and Riva i.e. host and riva exchange a msg
3214 indicating the features they support through a bitmap
3215
3216 \param - pHddCtx - Pointer to HDD context
3217
3218 \return - void
3219
3220 --------------------------------------------------------------------------*/
3221
3222void hdd_exchange_version_and_caps(hdd_context_t *pHddCtx)
3223{
3224
3225 tSirVersionType versionCompiled;
3226 tSirVersionType versionReported;
3227 tSirVersionString versionString;
3228 tANI_U8 fwFeatCapsMsgSupported = 0;
3229 VOS_STATUS vstatus;
3230
3231 /* retrieve and display WCNSS version information */
3232 do {
3233
3234 vstatus = sme_GetWcnssWlanCompiledVersion(pHddCtx->hHal,
3235 &versionCompiled);
3236 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3237 {
3238 hddLog(VOS_TRACE_LEVEL_FATAL,
3239 "%s: unable to retrieve WCNSS WLAN compiled version",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003240 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003241 break;
3242 }
3243
3244 vstatus = sme_GetWcnssWlanReportedVersion(pHddCtx->hHal,
3245 &versionReported);
3246 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3247 {
3248 hddLog(VOS_TRACE_LEVEL_FATAL,
3249 "%s: unable to retrieve WCNSS WLAN reported version",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003250 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003251 break;
3252 }
3253
3254 if ((versionCompiled.major != versionReported.major) ||
3255 (versionCompiled.minor != versionReported.minor) ||
3256 (versionCompiled.version != versionReported.version) ||
3257 (versionCompiled.revision != versionReported.revision))
3258 {
3259 pr_err("%s: WCNSS WLAN Version %u.%u.%u.%u, "
3260 "Host expected %u.%u.%u.%u\n",
3261 WLAN_MODULE_NAME,
3262 (int)versionReported.major,
3263 (int)versionReported.minor,
3264 (int)versionReported.version,
3265 (int)versionReported.revision,
3266 (int)versionCompiled.major,
3267 (int)versionCompiled.minor,
3268 (int)versionCompiled.version,
3269 (int)versionCompiled.revision);
3270 }
3271 else
3272 {
3273 pr_info("%s: WCNSS WLAN version %u.%u.%u.%u\n",
3274 WLAN_MODULE_NAME,
3275 (int)versionReported.major,
3276 (int)versionReported.minor,
3277 (int)versionReported.version,
3278 (int)versionReported.revision);
3279 }
3280
3281 vstatus = sme_GetWcnssSoftwareVersion(pHddCtx->hHal,
3282 versionString,
3283 sizeof(versionString));
3284 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3285 {
3286 hddLog(VOS_TRACE_LEVEL_FATAL,
3287 "%s: unable to retrieve WCNSS software version string",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003288 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003289 break;
3290 }
3291
3292 pr_info("%s: WCNSS software version %s\n",
3293 WLAN_MODULE_NAME, versionString);
3294
3295 vstatus = sme_GetWcnssHardwareVersion(pHddCtx->hHal,
3296 versionString,
3297 sizeof(versionString));
3298 if (!VOS_IS_STATUS_SUCCESS(vstatus))
3299 {
3300 hddLog(VOS_TRACE_LEVEL_FATAL,
3301 "%s: unable to retrieve WCNSS hardware version string",
Madan Mohan Koyyalamudi87054ba2012-11-02 13:24:12 -07003302 __func__);
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003303 break;
3304 }
3305
3306 pr_info("%s: WCNSS hardware version %s\n",
3307 WLAN_MODULE_NAME, versionString);
3308
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07003309 /* 1.Check if FW version is greater than 0.1.1.0. Only then send host-FW capability exchange message
3310 2.Host-FW capability exchange message is only present on riva 1.1 so
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003311 send the message only if it the riva is 1.1
3312 minor numbers for different riva branches:
3313 0 -> (1.0)Mainline Build
3314 1 -> (1.1)Mainline Build
3315 2->(1.04) Stability Build
3316 */
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07003317 if (((versionReported.major>0) || (versionReported.minor>1) ||
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003318 ((versionReported.minor>=1) && (versionReported.version>=1)))
3319 && ((versionReported.major == 1) && (versionReported.minor >= 1)))
3320 fwFeatCapsMsgSupported = 1;
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07003321
Madan Mohan Koyyalamudi8612ec92012-09-28 15:53:07 -07003322 if (fwFeatCapsMsgSupported)
3323 sme_featureCapsExchange(pHddCtx->hHal);
3324
3325 } while (0);
3326
3327}
3328
3329/**---------------------------------------------------------------------------
3330
Jeff Johnson295189b2012-06-20 16:38:30 -07003331 \brief hdd_wlan_startup() - HDD init function
3332
3333 This is the driver startup code executed once a WLAN device has been detected
3334
3335 \param - dev - Pointer to the underlying device
3336
3337 \return - 0 for success -1 for failure
3338
3339 --------------------------------------------------------------------------*/
3340
3341int hdd_wlan_startup(struct device *dev )
3342{
3343 VOS_STATUS status;
3344 hdd_adapter_t *pAdapter = NULL;
Jeff Johnsone7245742012-09-05 17:12:55 -07003345 hdd_adapter_t *pP2pAdapter = NULL;
Jeff Johnson295189b2012-06-20 16:38:30 -07003346 hdd_context_t *pHddCtx = NULL;
3347 v_CONTEXT_t pVosContext= NULL;
3348#ifdef WLAN_BTAMP_FEATURE
3349 VOS_STATUS vStatus = VOS_STATUS_SUCCESS;
3350 WLANBAP_ConfigType btAmpConfig;
3351 hdd_config_t *pConfig;
3352#endif
3353 int ret;
3354#ifdef CONFIG_CFG80211
3355 struct wiphy *wiphy;
3356#endif
3357#ifdef ANI_BUS_TYPE_SDIO
3358 struct sdio_func *sdio_func_dev = dev_to_sdio_func(dev);
3359#endif //ANI_BUS_TYPE_SDIO
3360
3361 ENTER();
3362#ifdef CONFIG_CFG80211
3363 /*
3364 * cfg80211: wiphy allocation
3365 */
3366 wiphy = wlan_hdd_cfg80211_init(sizeof(hdd_context_t)) ;
3367
3368 if(wiphy == NULL)
3369 {
3370 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
3371 return -1;
3372 }
3373
3374 pHddCtx = wiphy_priv(wiphy);
3375
3376#else
3377
3378 pHddCtx = vos_mem_malloc ( sizeof( hdd_context_t ) );
3379 if(pHddCtx == NULL)
3380 {
3381 hddLog(VOS_TRACE_LEVEL_ERROR,"%s: cfg80211 init failed", __func__);
3382 return -1;
3383 }
3384
3385#endif
3386 //Initialize the adapter context to zeros.
3387 vos_mem_zero(pHddCtx, sizeof( hdd_context_t ));
3388
3389#ifdef CONFIG_CFG80211
3390 pHddCtx->wiphy = wiphy;
3391#endif
3392 hdd_prevent_suspend();
3393 pHddCtx->isLoadUnloadInProgress = TRUE;
3394
3395 vos_set_load_unload_in_progress(VOS_MODULE_ID_VOSS, TRUE);
3396
3397 /*Get vos context here bcoz vos_open requires it*/
3398 pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
3399
3400 //Save the Global VOSS context in adapter context for future.
3401 pHddCtx->pvosContext = pVosContext;
3402
3403 //Save the adapter context in global context for future.
3404 ((VosContextType*)(pVosContext))->pHDDContext = (v_VOID_t*)pHddCtx;
3405
3406#ifdef ANI_BUS_TYPE_SDIO
3407 // Set the private data for the device to our adapter.
3408 libra_sdio_setprivdata (sdio_func_dev, pHddCtx);
3409 atomic_set(&pHddCtx->sdio_claim_count, 0);
3410#endif // ANI_BUS_TYPE_SDIO
3411
3412 pHddCtx->parent_dev = dev;
3413
3414 init_completion(&pHddCtx->full_pwr_comp_var);
3415 init_completion(&pHddCtx->standby_comp_var);
3416 init_completion(&pHddCtx->req_bmps_comp_var);
Madan Mohan Koyyalamudi2a1ba772012-10-11 14:59:06 -07003417 init_completion(&pHddCtx->scan_info.scan_req_completion_event);
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
Jeff Johnson295189b2012-06-20 16:38:30 -07003990 return -1;
3991
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__);
4035 return -1;
4036 }
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__);
4078 return -1;
4079 }
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
4587void wlan_hdd_set_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
4588{
4589 switch(mode)
4590 {
4591 case WLAN_HDD_INFRA_STATION:
4592#ifdef WLAN_FEATURE_P2P
4593 case WLAN_HDD_P2P_CLIENT:
4594 case WLAN_HDD_P2P_GO:
4595#endif
4596 case WLAN_HDD_SOFTAP:
Jeff Johnsone7245742012-09-05 17:12:55 -07004597 pHddCtx->concurrency_mode |= (1 << mode);
4598 pHddCtx->no_of_sessions[mode]++;
Jeff Johnson295189b2012-06-20 16:38:30 -07004599 break;
4600 default:
4601 break;
4602
4603 }
4604 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
4605 __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
4606}
4607
4608
4609void wlan_hdd_clear_concurrency_mode(hdd_context_t *pHddCtx, tVOS_CON_MODE mode)
4610{
4611 switch(mode)
4612 {
4613 case WLAN_HDD_INFRA_STATION:
4614#ifdef WLAN_FEATURE_P2P
4615 case WLAN_HDD_P2P_CLIENT:
4616 case WLAN_HDD_P2P_GO:
4617#endif
4618 case WLAN_HDD_SOFTAP:
4619 pHddCtx->no_of_sessions[mode]--;
4620 if (!(pHddCtx->no_of_sessions[mode]))
4621 pHddCtx->concurrency_mode &= (~(1 << mode));
4622 break;
4623 default:
4624 break;
4625 }
4626 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: concurrency_mode = 0x%x NumberofSessions for mode %d = %d",
4627 __func__,pHddCtx->concurrency_mode,mode,pHddCtx->no_of_sessions[mode]);
4628}
4629
Jeff Johnsone7245742012-09-05 17:12:55 -07004630/**---------------------------------------------------------------------------
4631 *
4632 * \brief wlan_hdd_restart_init
4633 *
4634 * This function initalizes restart timer/flag. An internal function.
4635 *
4636 * \param - pHddCtx
4637 *
4638 * \return - None
4639 *
4640 * --------------------------------------------------------------------------*/
4641
4642static void wlan_hdd_restart_init(hdd_context_t *pHddCtx)
4643{
4644 /* Initialize */
4645 pHddCtx->hdd_restart_retries = 0;
4646 atomic_set(&pHddCtx->isRestartInProgress, 0);
4647 vos_timer_init(&pHddCtx->hdd_restart_timer,
4648 VOS_TIMER_TYPE_SW,
4649 wlan_hdd_restart_timer_cb,
4650 pHddCtx);
4651}
4652/**---------------------------------------------------------------------------
4653 *
4654 * \brief wlan_hdd_restart_deinit
4655 *
4656 * This function cleans up the resources used. An internal function.
4657 *
4658 * \param - pHddCtx
4659 *
4660 * \return - None
4661 *
4662 * --------------------------------------------------------------------------*/
4663
4664static void wlan_hdd_restart_deinit(hdd_context_t* pHddCtx)
4665{
4666
4667 VOS_STATUS vos_status;
4668 /* Block any further calls */
4669 atomic_set(&pHddCtx->isRestartInProgress, 1);
4670 /* Cleanup */
4671 vos_status = vos_timer_stop( &pHddCtx->hdd_restart_timer );
4672 if (!VOS_IS_STATUS_SUCCESS(vos_status))
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004673 hddLog(LOGW, FL("Failed to stop HDD restart timer"));
Jeff Johnsone7245742012-09-05 17:12:55 -07004674 vos_status = vos_timer_destroy(&pHddCtx->hdd_restart_timer);
4675 if (!VOS_IS_STATUS_SUCCESS(vos_status))
Madan Mohan Koyyalamudi8b7f1e62012-10-05 14:56:51 -07004676 hddLog(LOGW, FL("Failed to destroy HDD restart timer"));
Jeff Johnsone7245742012-09-05 17:12:55 -07004677
4678}
4679
4680/**---------------------------------------------------------------------------
4681 *
4682 * \brief wlan_hdd_framework_restart
4683 *
4684 * This function uses a cfg80211 API to start a framework initiated WLAN
4685 * driver module unload/load.
4686 *
4687 * Also this API keep retrying (WLAN_HDD_RESTART_RETRY_MAX_CNT).
4688 *
4689 *
4690 * \param - pHddCtx
4691 *
4692 * \return - VOS_STATUS_SUCCESS: Success
4693 * VOS_STATUS_E_EMPTY: Adapter is Empty
4694 * VOS_STATUS_E_NOMEM: No memory
4695
4696 * --------------------------------------------------------------------------*/
4697
4698static VOS_STATUS wlan_hdd_framework_restart(hdd_context_t *pHddCtx)
4699{
4700 VOS_STATUS status = VOS_STATUS_SUCCESS;
4701 hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
4702 int len = (sizeof (struct ieee80211_mgmt));
4703 struct ieee80211_mgmt *mgmt = NULL;
4704
4705 /* Prepare the DEAUTH managment frame with reason code */
4706 mgmt = kzalloc(len, GFP_KERNEL);
4707 if(mgmt == NULL)
4708 {
4709 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
4710 "%s: memory allocatoin failed (%d bytes)", __func__, len);
4711 return VOS_STATUS_E_NOMEM;
4712 }
4713 mgmt->u.deauth.reason_code = WLAN_REASON_DISASSOC_LOW_ACK;
4714
4715 /* Iterate over all adapters/devices */
4716 status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
4717 do
4718 {
4719 if( (status == VOS_STATUS_SUCCESS) &&
4720 pAdapterNode &&
4721 pAdapterNode->pAdapter)
4722 {
4723 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
4724 "restarting the driver(intf:\'%s\' mode:%d :try %d)",
4725 pAdapterNode->pAdapter->dev->name,
4726 pAdapterNode->pAdapter->device_mode,
4727 pHddCtx->hdd_restart_retries + 1);
4728 /*
4729 * CFG80211 event to restart the driver
4730 *
4731 * 'cfg80211_send_unprot_deauth' sends a
4732 * NL80211_CMD_UNPROT_DEAUTHENTICATE event to supplicant at any state
4733 * of SME(Linux Kernel) state machine.
4734 *
4735 * Reason code WLAN_REASON_DISASSOC_LOW_ACK is currently used to restart
4736 * the driver.
4737 *
4738 */
4739
4740 cfg80211_send_unprot_deauth(pAdapterNode->pAdapter->dev, (u_int8_t*)mgmt, len );
4741 }
4742 status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
4743 pAdapterNode = pNext;
4744 } while((NULL != pAdapterNode) && (VOS_STATUS_SUCCESS == status));
4745
4746
4747 /* Free the allocated management frame */
4748 kfree(mgmt);
4749
4750 /* Retry until we unload or reach max count */
4751 if(++pHddCtx->hdd_restart_retries < WLAN_HDD_RESTART_RETRY_MAX_CNT)
4752 vos_timer_start(&pHddCtx->hdd_restart_timer, WLAN_HDD_RESTART_RETRY_DELAY_MS);
4753
4754 return status;
4755
4756}
4757/**---------------------------------------------------------------------------
4758 *
4759 * \brief wlan_hdd_restart_timer_cb
4760 *
4761 * Restart timer callback. An internal function.
4762 *
4763 * \param - User data:
4764 *
4765 * \return - None
4766 *
4767 * --------------------------------------------------------------------------*/
4768
4769void wlan_hdd_restart_timer_cb(v_PVOID_t usrDataForCallback)
4770{
4771 hdd_context_t *pHddCtx = usrDataForCallback;
4772 wlan_hdd_framework_restart(pHddCtx);
4773 return;
4774
4775}
4776
4777
4778/**---------------------------------------------------------------------------
4779 *
4780 * \brief wlan_hdd_restart_driver
4781 *
4782 * This function sends an event to supplicant to restart the WLAN driver.
4783 *
4784 * This function is called from vos_wlanRestart.
4785 *
4786 * \param - pHddCtx
4787 *
4788 * \return - VOS_STATUS_SUCCESS: Success
4789 * VOS_STATUS_E_EMPTY: Adapter is Empty
4790 * VOS_STATUS_E_ALREADY: Request already in progress
4791
4792 * --------------------------------------------------------------------------*/
4793VOS_STATUS wlan_hdd_restart_driver(hdd_context_t *pHddCtx)
4794{
4795 VOS_STATUS status = VOS_STATUS_SUCCESS;
4796
4797 /* A tight check to make sure reentrancy */
4798 if(atomic_xchg(&pHddCtx->isRestartInProgress, 1))
4799 {
4800 VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
4801 "%s: WLAN restart is already in progress", __func__);
4802
4803 return VOS_STATUS_E_ALREADY;
4804 }
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07004805 /* when WLAN driver is statically linked, then invoke SSR by sending
Madan Mohan Koyyalamudibb8f0172012-09-28 15:36:06 -07004806 * the reset interrupt. If it is DLKM, then use restart API
4807 */
4808#ifdef MODULE
Jeff Johnsone7245742012-09-05 17:12:55 -07004809 status = wlan_hdd_framework_restart(pHddCtx);
Madan Mohan Koyyalamudibb8f0172012-09-28 15:36:06 -07004810#else
4811 wcnss_reset_intr();
4812#endif
Madan Mohan Koyyalamudi5aef2af2012-10-05 11:56:27 -07004813
Jeff Johnsone7245742012-09-05 17:12:55 -07004814 return status;
4815}
4816
4817
Jeff Johnson295189b2012-06-20 16:38:30 -07004818//Register the module init/exit functions
4819module_init(hdd_module_init);
4820module_exit(hdd_module_exit);
4821
4822MODULE_LICENSE("Dual BSD/GPL");
4823MODULE_AUTHOR("Qualcomm Atheros, Inc.");
4824MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER");
4825
Madan Mohan Koyyalamudi2331c8a2012-09-18 18:14:48 -07004826module_param_call(con_mode, con_mode_handler, param_get_int, &con_mode,
4827 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
Jeff Johnson32d95a32012-09-10 13:15:23 -07004828
4829module_param_call(fwpath, fwpath_changed_handler, param_get_string, fwpath,
4830 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);