• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Linux cfg80211 driver - Android related functions
3  *
4  * Copyright (C) 1999-2013, Broadcom Corporation
5  *
6  *      Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  *
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  *
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  * $Id: wl_android.c 420671 2013-08-28 11:37:19Z $
25  */
26 
27 #include <linux/module.h>
28 #include <linux/netdevice.h>
29 #include <linux/of_gpio.h>
30 #include <linux/regulator/consumer.h>
31 
32 #include <wl_android.h>
33 #include <wldev_common.h>
34 #include <wlioctl.h>
35 #include <bcmutils.h>
36 #include <linux_osl.h>
37 #include <dhd_dbg.h>
38 #include <dngl_stats.h>
39 #include <dhd.h>
40 #ifdef PNO_SUPPORT
41 #include <dhd_pno.h>
42 #endif
43 #include <bcmsdbus.h>
44 #ifdef WL_CFG80211
45 #include <wl_cfg80211.h>
46 #endif
47 #if defined(CONFIG_WIFI_CONTROL_FUNC)
48 #include <linux/platform_device.h>
49 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
50 #include <linux/wlan_plat.h>
51 #else
52 #include <linux/wifi_tiwlan.h>
53 #endif
54 #endif /* CONFIG_WIFI_CONTROL_FUNC */
55 
56 /*
57  * Android private command strings, PLEASE define new private commands here
58  * so they can be updated easily in the future (if needed)
59  */
60 
61 #define CMD_START		"START"
62 #define CMD_STOP		"STOP"
63 #define	CMD_SCAN_ACTIVE		"SCAN-ACTIVE"
64 #define	CMD_SCAN_PASSIVE	"SCAN-PASSIVE"
65 #define CMD_RSSI		"RSSI"
66 #define CMD_LINKSPEED		"LINKSPEED"
67 #define CMD_RXFILTER_START	"RXFILTER-START"
68 #define CMD_RXFILTER_STOP	"RXFILTER-STOP"
69 #define CMD_RXFILTER_ADD	"RXFILTER-ADD"
70 #define CMD_RXFILTER_REMOVE	"RXFILTER-REMOVE"
71 #define CMD_BTCOEXSCAN_START	"BTCOEXSCAN-START"
72 #define CMD_BTCOEXSCAN_STOP	"BTCOEXSCAN-STOP"
73 #define CMD_BTCOEXMODE		"BTCOEXMODE"
74 #define CMD_SETSUSPENDOPT	"SETSUSPENDOPT"
75 #define CMD_SETSUSPENDMODE      "SETSUSPENDMODE"
76 #define CMD_P2P_DEV_ADDR	"P2P_DEV_ADDR"
77 #define CMD_SETFWPATH		"SETFWPATH"
78 #define CMD_SETBAND		"SETBAND"
79 #define CMD_GETBAND		"GETBAND"
80 #define CMD_COUNTRY		"COUNTRY"
81 #define CMD_P2P_SET_NOA		"P2P_SET_NOA"
82 #if !defined WL_ENABLE_P2P_IF
83 #define CMD_P2P_GET_NOA			"P2P_GET_NOA"
84 #endif /* WL_ENABLE_P2P_IF */
85 #define CMD_P2P_SD_OFFLOAD		"P2P_SD_"
86 #define CMD_P2P_SET_PS		"P2P_SET_PS"
87 #define CMD_SET_AP_WPS_P2P_IE 		"SET_AP_WPS_P2P_IE"
88 #define CMD_SETROAMMODE 	"SETROAMMODE"
89 #define CMD_MIRACAST		"MIRACAST"
90 
91 
92 
93 /* CCX Private Commands */
94 
95 #ifdef PNO_SUPPORT
96 #define CMD_PNOSSIDCLR_SET	"PNOSSIDCLR"
97 #define CMD_PNOSETUP_SET	"PNOSETUP "
98 #define CMD_PNOENABLE_SET	"PNOFORCE"
99 #define CMD_PNODEBUG_SET	"PNODEBUG"
100 #define CMD_WLS_BATCHING	"WLS_BATCHING"
101 #endif /* PNO_SUPPORT */
102 
103 #define CMD_OKC_SET_PMK		"SET_PMK"
104 #define CMD_OKC_ENABLE		"OKC_ENABLE"
105 
106 
107 /* miracast related definition */
108 #define MIRACAST_MODE_OFF	0
109 #define MIRACAST_MODE_SOURCE	1
110 #define MIRACAST_MODE_SINK	2
111 
112 #ifndef MIRACAST_AMPDU_SIZE
113 #define MIRACAST_AMPDU_SIZE	8
114 #endif
115 
116 #ifndef MIRACAST_MCHAN_ALGO
117 #define MIRACAST_MCHAN_ALGO     1
118 #endif
119 
120 #ifndef MIRACAST_MCHAN_BW
121 #define MIRACAST_MCHAN_BW       25
122 #endif
123 
124 static LIST_HEAD(miracast_resume_list);
125 static u8 miracast_cur_mode;
126 
127 struct io_cfg {
128 	s8 *iovar;
129 	s32 param;
130 	u32 ioctl;
131 	void *arg;
132 	u32 len;
133 	struct list_head list;
134 };
135 
136 typedef struct android_wifi_priv_cmd {
137 	char *buf;
138 	int used_len;
139 	int total_len;
140 } android_wifi_priv_cmd;
141 
142 
143 /**
144  * Extern function declarations (TODO: move them to dhd_linux.h)
145  */
146 void dhd_customer_gpio_wlan_ctrl(int onoff);
147 int dhd_dev_reset(struct net_device *dev, uint8 flag);
148 int dhd_dev_init_ioctl(struct net_device *dev);
149 #ifdef WL_CFG80211
150 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
151 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command);
152 int wl_cfg80211_get_ioctl_version(void);
153 #else
wl_cfg80211_get_p2p_dev_addr(struct net_device * net,struct ether_addr * p2pdev_addr)154 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
155 { return 0; }
wl_cfg80211_set_p2p_noa(struct net_device * net,char * buf,int len)156 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
157 { return 0; }
wl_cfg80211_get_p2p_noa(struct net_device * net,char * buf,int len)158 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
159 { return 0; }
wl_cfg80211_set_p2p_ps(struct net_device * net,char * buf,int len)160 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
161 { return 0; }
162 #endif /* WK_CFG80211 */
163 extern int dhd_os_check_if_up(void *dhdp);
164 #ifdef BCMLXSDMMC
165 extern void *bcmsdh_get_drvdata(void);
166 #endif /* BCMLXSDMMC */
167 
168 
169 #ifdef ENABLE_4335BT_WAR
170 extern int bcm_bt_lock(int cookie);
171 extern void bcm_bt_unlock(int cookie);
172 static int lock_cookie_wifi = 'W' | 'i'<<8 | 'F'<<16 | 'i'<<24;	/* cookie is "WiFi" */
173 #endif /* ENABLE_4335BT_WAR */
174 
175 extern bool ap_fw_loaded;
176 #if defined(CUSTOMER_HW2)
177 extern char iface_name[IFNAMSIZ];
178 #endif
179 
180 /**
181  * Local (static) functions and variables
182  */
183 
184 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
185  * time (only) in dhd_open, subsequential wifi on will be handled by
186  * wl_android_wifi_on
187  */
188 static int g_wifi_on = TRUE;
189 
190 /**
191  * Local (static) function definitions
192  */
wl_android_get_link_speed(struct net_device * net,char * command,int total_len)193 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
194 {
195 	int link_speed;
196 	int bytes_written;
197 	int error;
198 
199 	error = wldev_get_link_speed(net, &link_speed);
200 	if (error)
201 		return -1;
202 
203 	/* Convert Kbps to Android Mbps */
204 	link_speed = link_speed / 1000;
205 	bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
206 	DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command));
207 	return bytes_written;
208 }
209 
wl_android_get_rssi(struct net_device * net,char * command,int total_len)210 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
211 {
212 	wlc_ssid_t ssid = {0};
213 	int rssi;
214 	int bytes_written = 0;
215 	int error;
216 
217 	error = wldev_get_rssi(net, &rssi);
218 	if (error)
219 		return -1;
220 
221 	error = wldev_get_ssid(net, &ssid);
222 	if (error)
223 		return -1;
224 	if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
225 		DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
226 	} else {
227 		memcpy(command, ssid.SSID, ssid.SSID_len);
228 		bytes_written = ssid.SSID_len;
229 	}
230 	bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi);
231 	DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
232 	return bytes_written;
233 }
234 
wl_android_set_suspendopt(struct net_device * dev,char * command,int total_len)235 static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len)
236 {
237 	int suspend_flag;
238 	int ret_now;
239 	int ret = 0;
240 
241 		suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
242 
243 		if (suspend_flag != 0)
244 			suspend_flag = 1;
245 		ret_now = net_os_set_suspend_disable(dev, suspend_flag);
246 
247 		if (ret_now != suspend_flag) {
248 			if (!(ret = net_os_set_suspend(dev, ret_now, 1)))
249 				DHD_INFO(("%s: Suspend Flag %d -> %d\n",
250 					__FUNCTION__, ret_now, suspend_flag));
251 			else
252 				DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
253 		}
254 	return ret;
255 }
256 
wl_android_set_suspendmode(struct net_device * dev,char * command,int total_len)257 static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len)
258 {
259 	int ret = 0;
260 
261 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
262 	int suspend_flag;
263 
264 	suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
265 	if (suspend_flag != 0)
266 		suspend_flag = 1;
267 
268 	if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
269 		DHD_INFO(("%s: Suspend Mode %d\n", __FUNCTION__, suspend_flag));
270 	else
271 		DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
272 #endif
273 
274 	return ret;
275 }
276 
wl_android_get_band(struct net_device * dev,char * command,int total_len)277 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
278 {
279 	uint band;
280 	int bytes_written;
281 	int error;
282 
283 	error = wldev_get_band(dev, &band);
284 	if (error)
285 		return -1;
286 	bytes_written = snprintf(command, total_len, "Band %d", band);
287 	return bytes_written;
288 }
289 
290 
291 #ifdef PNO_SUPPORT
292 #define PARAM_SIZE 50
293 #define VALUE_SIZE 50
294 static int
wls_parse_batching_cmd(struct net_device * dev,char * command,int total_len)295 wls_parse_batching_cmd(struct net_device *dev, char *command, int total_len)
296 {
297 	int err = BCME_OK;
298 	uint i, tokens;
299 	char *pos, *pos2, *token, *token2, *delim;
300 	char param[PARAM_SIZE], value[VALUE_SIZE];
301 	struct dhd_pno_batch_params batch_params;
302 	DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
303 	if (total_len < strlen(CMD_WLS_BATCHING)) {
304 		DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
305 		err = BCME_ERROR;
306 		goto exit;
307 	}
308 	pos = command + strlen(CMD_WLS_BATCHING) + 1;
309 	memset(&batch_params, 0, sizeof(struct dhd_pno_batch_params));
310 
311 	if (!strncmp(pos, PNO_BATCHING_SET, strlen(PNO_BATCHING_SET))) {
312 		pos += strlen(PNO_BATCHING_SET) + 1;
313 		while ((token = strsep(&pos, PNO_PARAMS_DELIMETER)) != NULL) {
314 			memset(param, 0, sizeof(param));
315 			memset(value, 0, sizeof(value));
316 			if (token == NULL || !*token)
317 				break;
318 			if (*token == '\0')
319 				continue;
320 			delim = strchr(token, PNO_PARAM_VALUE_DELLIMETER);
321 			if (delim != NULL)
322 				*delim = ' ';
323 
324 			tokens = sscanf(token, "%s %s", param, value);
325 			if (!strncmp(param, PNO_PARAM_SCANFREQ, strlen(PNO_PARAM_MSCAN))) {
326 				batch_params.scan_fr = simple_strtol(value, NULL, 0);
327 				DHD_PNO(("scan_freq : %d\n", batch_params.scan_fr));
328 			} else if (!strncmp(param, PNO_PARAM_BESTN, strlen(PNO_PARAM_MSCAN))) {
329 				batch_params.bestn = simple_strtol(value, NULL, 0);
330 				DHD_PNO(("bestn : %d\n", batch_params.bestn));
331 			} else if (!strncmp(param, PNO_PARAM_MSCAN, strlen(PNO_PARAM_MSCAN))) {
332 				batch_params.mscan = simple_strtol(value, NULL, 0);
333 				DHD_PNO(("mscan : %d\n", batch_params.mscan));
334 			} else if (!strncmp(param, PNO_PARAM_CHANNEL, strlen(PNO_PARAM_MSCAN))) {
335 				i = 0;
336 				pos2 = value;
337 				tokens = sscanf(value, "<%s>", value);
338 				if (tokens != 1) {
339 					err = BCME_ERROR;
340 					DHD_ERROR(("%s : invalid format for channel"
341 					" <> params\n", __FUNCTION__));
342 					goto exit;
343 				}
344 					while ((token2 = strsep(&pos2,
345 					PNO_PARAM_CHANNEL_DELIMETER)) != NULL) {
346 					if (token2 == NULL || !*token2)
347 						break;
348 					if (*token2 == '\0')
349 						continue;
350 					if (*token2 == 'A' || *token2 == 'B') {
351 						batch_params.band = (*token2 == 'A')?
352 							WLC_BAND_5G : WLC_BAND_2G;
353 						DHD_PNO(("band : %s\n",
354 							(*token2 == 'A')? "A" : "B"));
355 					} else {
356 						batch_params.chan_list[i++] =
357 						simple_strtol(token2, NULL, 0);
358 						batch_params.nchan++;
359 						DHD_PNO(("channel :%d\n",
360 						batch_params.chan_list[i-1]));
361 					}
362 				 }
363 			} else if (!strncmp(param, PNO_PARAM_RTT, strlen(PNO_PARAM_MSCAN))) {
364 				batch_params.rtt = simple_strtol(value, NULL, 0);
365 				DHD_PNO(("rtt : %d\n", batch_params.rtt));
366 			} else {
367 				DHD_ERROR(("%s : unknown param: %s\n", __FUNCTION__, param));
368 				err = BCME_ERROR;
369 				goto exit;
370 			}
371 		}
372 		err = dhd_dev_pno_set_for_batch(dev, &batch_params);
373 		if (err < 0) {
374 			DHD_ERROR(("failed to configure batch scan\n"));
375 		} else {
376 			memset(command, 0, total_len);
377 			err = sprintf(command, "%d", err);
378 		}
379 	} else if (!strncmp(pos, PNO_BATCHING_GET, strlen(PNO_BATCHING_GET))) {
380 		err = dhd_dev_pno_get_for_batch(dev, command, total_len);
381 		if (err < 0) {
382 			DHD_ERROR(("failed to getting batching results\n"));
383 		}
384 	} else if (!strncmp(pos, PNO_BATCHING_STOP, strlen(PNO_BATCHING_STOP))) {
385 		err = dhd_dev_pno_stop_for_batch(dev);
386 		if (err < 0) {
387 			DHD_ERROR(("failed to stop batching scan\n"));
388 		} else {
389 			memset(command, 0, total_len);
390 			err = sprintf(command, "OK");
391 		}
392 	} else {
393 		DHD_ERROR(("%s : unknown command\n", __FUNCTION__));
394 		err = BCME_ERROR;
395 		goto exit;
396 	}
397 exit:
398 	return err;
399 }
400 
401 #ifndef WL_SCHED_SCAN
wl_android_set_pno_setup(struct net_device * dev,char * command,int total_len)402 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
403 {
404 	wlc_ssid_ext_t ssids_local[MAX_PFN_LIST_COUNT];
405 	int res = -1;
406 	int nssid = 0;
407 	cmd_tlv_t *cmd_tlv_temp;
408 	char *str_ptr;
409 	int tlv_size_left;
410 	int pno_time = 0;
411 	int pno_repeat = 0;
412 	int pno_freq_expo_max = 0;
413 
414 #ifdef PNO_SET_DEBUG
415 	int i;
416 	char pno_in_example[] = {
417 		'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
418 		'S', '1', '2', '0',
419 		'S',
420 		0x05,
421 		'd', 'l', 'i', 'n', 'k',
422 		'S',
423 		0x04,
424 		'G', 'O', 'O', 'G',
425 		'T',
426 		'0', 'B',
427 		'R',
428 		'2',
429 		'M',
430 		'2',
431 		0x00
432 		};
433 #endif /* PNO_SET_DEBUG */
434 	DHD_PNO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
435 
436 	if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
437 		DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
438 		goto exit_proc;
439 	}
440 #ifdef PNO_SET_DEBUG
441 	memcpy(command, pno_in_example, sizeof(pno_in_example));
442 	total_len = sizeof(pno_in_example);
443 #endif
444 	str_ptr = command + strlen(CMD_PNOSETUP_SET);
445 	tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
446 
447 	cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
448 	memset(ssids_local, 0, sizeof(ssids_local));
449 
450 	if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
451 		(cmd_tlv_temp->version == PNO_TLV_VERSION) &&
452 		(cmd_tlv_temp->subtype == PNO_TLV_SUBTYPE_LEGACY_PNO)) {
453 
454 		str_ptr += sizeof(cmd_tlv_t);
455 		tlv_size_left -= sizeof(cmd_tlv_t);
456 
457 		if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
458 			MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
459 			DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
460 			goto exit_proc;
461 		} else {
462 			if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
463 				DHD_ERROR(("%s scan duration corrupted field size %d\n",
464 					__FUNCTION__, tlv_size_left));
465 				goto exit_proc;
466 			}
467 			str_ptr++;
468 			pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
469 			DHD_PNO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
470 
471 			if (str_ptr[0] != 0) {
472 				if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
473 					DHD_ERROR(("%s pno repeat : corrupted field\n",
474 						__FUNCTION__));
475 					goto exit_proc;
476 				}
477 				str_ptr++;
478 				pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
479 				DHD_PNO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
480 				if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
481 					DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
482 						__FUNCTION__));
483 					goto exit_proc;
484 				}
485 				str_ptr++;
486 				pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
487 				DHD_PNO(("%s: pno_freq_expo_max=%d\n",
488 					__FUNCTION__, pno_freq_expo_max));
489 			}
490 		}
491 	} else {
492 		DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
493 		goto exit_proc;
494 	}
495 
496 	res = dhd_dev_pno_set_for_ssid(dev, ssids_local, nssid, pno_time, pno_repeat,
497 		pno_freq_expo_max, NULL, 0);
498 exit_proc:
499 	return res;
500 }
501 #endif /* !WL_SCHED_SCAN */
502 #endif /* PNO_SUPPORT  */
503 
wl_android_get_p2p_dev_addr(struct net_device * ndev,char * command,int total_len)504 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
505 {
506 	int ret;
507 	int bytes_written = 0;
508 
509 	ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command);
510 	if (ret)
511 		return 0;
512 	bytes_written = sizeof(struct ether_addr);
513 	return bytes_written;
514 }
515 
516 
517 /**
518  * Global function definitions (declared in wl_android.h)
519  */
520 
wl_android_wifi_on(struct net_device * dev)521 int wl_android_wifi_on(struct net_device *dev)
522 {
523 	int ret = 0;
524 	int retry = POWERUP_MAX_RETRY;
525 
526 	printk("%s in\n", __FUNCTION__);
527 	if (!dev) {
528 		DHD_ERROR(("%s: dev is null\n", __FUNCTION__));
529 		return -EINVAL;
530 	}
531 
532 	dhd_net_if_lock(dev);
533 	if (!g_wifi_on) {
534 		do {
535 			dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
536 			ret = sdioh_start(NULL, 0);
537 			if (ret == 0)
538 				break;
539 			DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n",
540 				retry+1));
541 			dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
542 		} while (retry-- >= 0);
543 		if (ret != 0) {
544 			DHD_ERROR(("\nfailed to power up wifi chip, max retry reached **\n\n"));
545 			goto exit;
546 		}
547 		ret = dhd_dev_reset(dev, FALSE);
548 		sdioh_start(NULL, 1);
549 		if (!ret) {
550 			if (dhd_dev_init_ioctl(dev) < 0)
551 				ret = -EFAULT;
552 		}
553 		g_wifi_on = TRUE;
554 	}
555 
556 exit:
557 	dhd_net_if_unlock(dev);
558 
559 	return ret;
560 }
561 
wl_android_wifi_off(struct net_device * dev)562 int wl_android_wifi_off(struct net_device *dev)
563 {
564 	int ret = 0;
565 
566 	printk("%s in\n", __FUNCTION__);
567 	if (!dev) {
568 		DHD_TRACE(("%s: dev is null\n", __FUNCTION__));
569 		return -EINVAL;
570 	}
571 
572 	dhd_net_if_lock(dev);
573 	if (g_wifi_on) {
574 		ret = dhd_dev_reset(dev, TRUE);
575 		sdioh_stop(NULL);
576 		dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
577 		g_wifi_on = FALSE;
578 	}
579 	dhd_net_if_unlock(dev);
580 
581 	return ret;
582 }
583 
wl_android_set_fwpath(struct net_device * net,char * command,int total_len)584 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
585 {
586 	if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
587 		return -1;
588 	bcm_strncpy_s(fw_path, sizeof(fw_path),
589 		command + strlen(CMD_SETFWPATH) + 1, MOD_PARAM_PATHLEN - 1);
590 	if (strstr(fw_path, "apsta") != NULL) {
591 		DHD_INFO(("GOT APSTA FIRMWARE\n"));
592 		ap_fw_loaded = TRUE;
593 	} else {
594 		DHD_INFO(("GOT STA FIRMWARE\n"));
595 		ap_fw_loaded = FALSE;
596 	}
597 	return 0;
598 }
599 
600 
601 static int
wl_android_set_pmk(struct net_device * dev,char * command,int total_len)602 wl_android_set_pmk(struct net_device *dev, char *command, int total_len)
603 {
604 	uchar pmk[33];
605 	int error = 0;
606 	char smbuf[WLC_IOCTL_SMLEN];
607 #ifdef OKC_DEBUG
608 	int i = 0;
609 #endif
610 
611 	bzero(pmk, sizeof(pmk));
612 	memcpy((char *)pmk, command + strlen("SET_PMK "), 32);
613 	error = wldev_iovar_setbuf(dev, "okc_info_pmk", pmk, 32, smbuf, sizeof(smbuf), NULL);
614 	if (error) {
615 		DHD_ERROR(("Failed to set PMK for OKC, error = %d\n", error));
616 	}
617 #ifdef OKC_DEBUG
618 	DHD_ERROR(("PMK is "));
619 	for (i = 0; i < 32; i++)
620 		DHD_ERROR(("%02X ", pmk[i]));
621 
622 	DHD_ERROR(("\n"));
623 #endif
624 	return error;
625 }
626 
627 static int
wl_android_okc_enable(struct net_device * dev,char * command,int total_len)628 wl_android_okc_enable(struct net_device *dev, char *command, int total_len)
629 {
630 	int error = 0;
631 	char okc_enable = 0;
632 
633 	okc_enable = command[strlen(CMD_OKC_ENABLE) + 1] - '0';
634 	error = wldev_iovar_setint(dev, "okc_enable", okc_enable);
635 	if (error) {
636 		DHD_ERROR(("Failed to %s OKC, error = %d\n",
637 			okc_enable ? "enable" : "disable", error));
638 	}
639 
640 	wldev_iovar_setint(dev, "ccx_enable", 0);
641 
642 	return error;
643 }
644 
645 
646 
wl_android_set_roam_mode(struct net_device * dev,char * command,int total_len)647 int wl_android_set_roam_mode(struct net_device *dev, char *command, int total_len)
648 {
649 	int error = 0;
650 	int mode = 0;
651 
652 	if (sscanf(command, "%*s %d", &mode) != 1) {
653 		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
654 		return -1;
655 	}
656 
657 	error = wldev_iovar_setint(dev, "roam_off", mode);
658 	if (error) {
659 		DHD_ERROR(("%s: Failed to set roaming Mode %d, error = %d\n",
660 		__FUNCTION__, mode, error));
661 		return -1;
662 	}
663 	else
664 		DHD_ERROR(("%s: succeeded to set roaming Mode %d, error = %d\n",
665 		__FUNCTION__, mode, error));
666 	return 0;
667 }
668 
669 static int
wl_android_iolist_add(struct net_device * dev,struct list_head * head,struct io_cfg * config)670 wl_android_iolist_add(struct net_device *dev, struct list_head *head, struct io_cfg *config)
671 {
672 	struct io_cfg *resume_cfg;
673 	s32 ret;
674 
675 	resume_cfg = kzalloc(sizeof(struct io_cfg), GFP_KERNEL);
676 	if (!resume_cfg)
677 		return -ENOMEM;
678 
679 	if (config->iovar) {
680 		ret = wldev_iovar_getint(dev, config->iovar, &resume_cfg->param);
681 		if (ret) {
682 			DHD_ERROR(("%s: Failed to get current %s value\n",
683 				__FUNCTION__, config->iovar));
684 			goto error;
685 		}
686 
687 		ret = wldev_iovar_setint(dev, config->iovar, config->param);
688 		if (ret) {
689 			DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
690 				config->iovar, config->param));
691 			goto error;
692 		}
693 
694 		resume_cfg->iovar = config->iovar;
695 	} else {
696 		resume_cfg->arg = kzalloc(config->len, GFP_KERNEL);
697 		if (!resume_cfg->arg) {
698 			ret = -ENOMEM;
699 			goto error;
700 		}
701 		ret = wldev_ioctl(dev, config->ioctl, resume_cfg->arg, config->len, false);
702 		if (ret) {
703 			DHD_ERROR(("%s: Failed to get ioctl %d\n", __FUNCTION__,
704 				config->ioctl));
705 			goto error;
706 		}
707 		ret = wldev_ioctl(dev, config->ioctl + 1, config->arg, config->len, true);
708 		if (ret) {
709 			DHD_ERROR(("%s: Failed to set %s to %d\n", __FUNCTION__,
710 				config->iovar, config->param));
711 			goto error;
712 		}
713 		if (config->ioctl + 1 == WLC_SET_PM)
714 			wl_cfg80211_update_power_mode(dev);
715 		resume_cfg->ioctl = config->ioctl;
716 		resume_cfg->len = config->len;
717 	}
718 
719 	list_add(&resume_cfg->list, head);
720 
721 	return 0;
722 error:
723 	kfree(resume_cfg->arg);
724 	kfree(resume_cfg);
725 	return ret;
726 }
727 
728 static void
wl_android_iolist_resume(struct net_device * dev,struct list_head * head)729 wl_android_iolist_resume(struct net_device *dev, struct list_head *head)
730 {
731 	struct io_cfg *config;
732 	struct list_head *cur, *q;
733 	s32 ret = 0;
734 
735 	list_for_each_safe(cur, q, head) {
736 		config = list_entry(cur, struct io_cfg, list);
737 		if (config->iovar) {
738 			if (!ret)
739 				ret = wldev_iovar_setint(dev, config->iovar,
740 					config->param);
741 		} else {
742 			if (!ret)
743 				ret = wldev_ioctl(dev, config->ioctl + 1,
744 					config->arg, config->len, true);
745 			if (config->ioctl + 1 == WLC_SET_PM)
746 				wl_cfg80211_update_power_mode(dev);
747 			kfree(config->arg);
748 		}
749 		list_del(cur);
750 		kfree(config);
751 	}
752 }
753 
754 static int
wl_android_set_miracast(struct net_device * dev,char * command,int total_len)755 wl_android_set_miracast(struct net_device *dev, char *command, int total_len)
756 {
757 	int mode, val;
758 	int ret = 0;
759 	struct io_cfg config;
760 
761 	if (sscanf(command, "%*s %d", &mode) != 1) {
762 		DHD_ERROR(("%s: Failed to get Parameter\n", __FUNCTION__));
763 		return -1;
764 	}
765 
766 	DHD_INFO(("%s: enter miracast mode %d\n", __FUNCTION__, mode));
767 
768 	if (miracast_cur_mode == mode)
769 		return 0;
770 
771 	wl_android_iolist_resume(dev, &miracast_resume_list);
772 	miracast_cur_mode = MIRACAST_MODE_OFF;
773 
774 	switch (mode) {
775 	case MIRACAST_MODE_SOURCE:
776 		/* setting mchan_algo to platform specific value */
777 		config.iovar = "mchan_algo";
778 		config.param = MIRACAST_MCHAN_ALGO;
779 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
780 		if (ret)
781 			goto resume;
782 
783 		/* setting mchan_bw to platform specific value */
784 		config.iovar = "mchan_bw";
785 		config.param = MIRACAST_MCHAN_BW;
786 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
787 		if (ret)
788 			goto resume;
789 
790 		/* setting apmdu to platform specific value */
791 		config.iovar = "ampdu_mpdu";
792 		config.param = MIRACAST_AMPDU_SIZE;
793 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
794 		if (ret)
795 			goto resume;
796 		/* FALLTROUGH */
797 		/* Source mode shares most configurations with sink mode.
798 		 * Fall through here to avoid code duplication
799 		 */
800 	case MIRACAST_MODE_SINK:
801 		/* disable internal roaming */
802 		config.iovar = "roam_off";
803 		config.param = 1;
804 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
805 		if (ret)
806 			goto resume;
807 		/* tunr off pm */
808 		val = 0;
809 		config.iovar = NULL;
810 		config.ioctl = WLC_GET_PM;
811 		config.arg = &val;
812 		config.len = sizeof(int);
813 		ret = wl_android_iolist_add(dev, &miracast_resume_list, &config);
814 		if (ret)
815 			goto resume;
816 
817 		break;
818 	case MIRACAST_MODE_OFF:
819 	default:
820 		break;
821 	}
822 	miracast_cur_mode = mode;
823 
824 	return 0;
825 
826 resume:
827 	DHD_ERROR(("%s: turnoff miracast mode because of err %d\n", __FUNCTION__, ret));
828 	wl_android_iolist_resume(dev, &miracast_resume_list);
829 	return ret;
830 }
831 
wl_android_priv_cmd(struct net_device * net,struct ifreq * ifr,int cmd)832 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
833 {
834 #define PRIVATE_COMMAND_MAX_LEN 8192
835 	int ret = 0;
836 	char *command = NULL;
837 	int bytes_written = 0;
838 	android_wifi_priv_cmd priv_cmd;
839 
840 	net_os_wake_lock(net);
841 
842 	if (!ifr->ifr_data) {
843 		ret = -EINVAL;
844 		goto exit;
845 	}
846 	if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
847 		ret = -EFAULT;
848 		goto exit;
849 	}
850 	if (priv_cmd.total_len > PRIVATE_COMMAND_MAX_LEN)
851 	{
852 		DHD_ERROR(("%s: too long priavte command\n", __FUNCTION__));
853 		ret = -EINVAL;
854 		goto exit;
855 	}
856 	command = kmalloc((priv_cmd.total_len + 1), GFP_KERNEL);
857 	if (!command)
858 	{
859 		DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
860 		ret = -ENOMEM;
861 		goto exit;
862 	}
863 	if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
864 		ret = -EFAULT;
865 		goto exit;
866 	}
867 	command[priv_cmd.total_len] = '\0';
868 
869 	DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
870 
871 	if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
872 		DHD_INFO(("%s, Received regular START command\n", __FUNCTION__));
873 		bytes_written = wl_android_wifi_on(net);
874 	}
875 	else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
876 		bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
877 	}
878 
879 	if (!g_wifi_on) {
880 		DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n",
881 			__FUNCTION__, command, ifr->ifr_name));
882 		ret = 0;
883 		goto exit;
884 	}
885 
886 	if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
887 		bytes_written = wl_android_wifi_off(net);
888 	}
889 	else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
890 		/* TBD: SCAN-ACTIVE */
891 	}
892 	else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
893 		/* TBD: SCAN-PASSIVE */
894 	}
895 	else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
896 		bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
897 	}
898 	else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
899 		bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
900 	}
901 #ifdef PKT_FILTER_SUPPORT
902 	else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
903 		bytes_written = net_os_enable_packet_filter(net, 1);
904 	}
905 	else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
906 		bytes_written = net_os_enable_packet_filter(net, 0);
907 	}
908 	else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
909 		int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
910 		bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
911 	}
912 	else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
913 		int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
914 		bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
915 	}
916 #endif /* PKT_FILTER_SUPPORT */
917 	else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
918 		/* TBD: BTCOEXSCAN-START */
919 	}
920 	else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
921 		/* TBD: BTCOEXSCAN-STOP */
922 	}
923 	else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
924 #ifdef WL_CFG80211
925 		bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
926 #else
927 #ifdef PKT_FILTER_SUPPORT
928 		uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
929 
930 		if (mode == 1)
931 			net_os_enable_packet_filter(net, 0); /* DHCP starts */
932 		else
933 			net_os_enable_packet_filter(net, 1); /* DHCP ends */
934 #endif /* PKT_FILTER_SUPPORT */
935 #endif /* WL_CFG80211 */
936 	}
937 	else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
938 		bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
939 	}
940 	else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
941 		bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len);
942 	}
943 	else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
944 		uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
945 		bytes_written = wldev_set_band(net, band);
946 	}
947 	else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
948 		bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
949 	}
950 #ifdef WL_CFG80211
951 	/* CUSTOMER_SET_COUNTRY feature is define for only GGSM model */
952 	else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
953 		char *country_code = command + strlen(CMD_COUNTRY) + 1;
954 		bytes_written = wldev_set_country(net, country_code, true, true);
955 	}
956 #endif /* WL_CFG80211 */
957 
958 
959 #ifdef PNO_SUPPORT
960 #ifndef WL_SCHED_SCAN
961 	else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
962 		bytes_written = dhd_dev_pno_stop_for_ssid(net);
963 	}
964 	else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
965 		bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
966 	}
967 	else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
968 		int enable = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
969 		bytes_written = (enable)? 0 : dhd_dev_pno_stop_for_ssid(net);
970 	}
971 #endif
972 	else if (strnicmp(command, CMD_WLS_BATCHING, strlen(CMD_WLS_BATCHING)) == 0) {
973 		bytes_written = wls_parse_batching_cmd(net, command, priv_cmd.total_len);
974 	}
975 #endif /* PNO_SUPPORT */
976 	else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
977 		bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
978 	}
979 	else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
980 		int skip = strlen(CMD_P2P_SET_NOA) + 1;
981 		bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
982 			priv_cmd.total_len - skip);
983 	}
984 #if !defined WL_ENABLE_P2P_IF
985 	else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
986 		bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
987 	}
988 #endif /* WL_ENABLE_P2P_IF */
989 	else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
990 		int skip = strlen(CMD_P2P_SET_PS) + 1;
991 		bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
992 			priv_cmd.total_len - skip);
993 	}
994 #ifdef WL_CFG80211
995 	else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
996 		strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
997 		int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
998 		bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
999 			priv_cmd.total_len - skip, *(command + skip - 2) - '0');
1000 	}
1001 #endif /* WL_CFG80211 */
1002 	else if (strnicmp(command, CMD_OKC_SET_PMK, strlen(CMD_OKC_SET_PMK)) == 0)
1003 		bytes_written = wl_android_set_pmk(net, command, priv_cmd.total_len);
1004 	else if (strnicmp(command, CMD_OKC_ENABLE, strlen(CMD_OKC_ENABLE)) == 0)
1005 		bytes_written = wl_android_okc_enable(net, command, priv_cmd.total_len);
1006 	else if (strnicmp(command, CMD_SETROAMMODE, strlen(CMD_SETROAMMODE)) == 0)
1007 		bytes_written = wl_android_set_roam_mode(net, command, priv_cmd.total_len);
1008 	else if (strnicmp(command, CMD_MIRACAST, strlen(CMD_MIRACAST)) == 0)
1009 		bytes_written = wl_android_set_miracast(net, command, priv_cmd.total_len);
1010 	else {
1011 		DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
1012 		snprintf(command, 3, "OK");
1013 		bytes_written = strlen("OK");
1014 	}
1015 
1016 	if (bytes_written >= 0) {
1017 		if ((bytes_written == 0) && (priv_cmd.total_len > 0))
1018 			command[0] = '\0';
1019 		if (bytes_written >= priv_cmd.total_len) {
1020 			DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
1021 			bytes_written = priv_cmd.total_len;
1022 		} else {
1023 			bytes_written++;
1024 		}
1025 		priv_cmd.used_len = bytes_written;
1026 		if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
1027 			DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
1028 			ret = -EFAULT;
1029 		}
1030 	}
1031 	else {
1032 		ret = bytes_written;
1033 	}
1034 
1035 exit:
1036 	net_os_wake_unlock(net);
1037 	if (command) {
1038 		kfree(command);
1039 	}
1040 
1041 	return ret;
1042 }
1043 
wl_android_init(void)1044 int wl_android_init(void)
1045 {
1046 	int ret = 0;
1047 
1048 #ifdef ENABLE_INSMOD_NO_FW_LOAD
1049 	dhd_download_fw_on_driverload = FALSE;
1050 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
1051 #if defined(CUSTOMER_HW2)
1052 	if (!iface_name[0]) {
1053 		memset(iface_name, 0, IFNAMSIZ);
1054 		bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
1055 	}
1056 #endif
1057 
1058 
1059 	return ret;
1060 }
1061 
wl_android_exit(void)1062 int wl_android_exit(void)
1063 {
1064 	int ret = 0;
1065 
1066 
1067 	return ret;
1068 }
1069 
wl_android_post_init(void)1070 void wl_android_post_init(void)
1071 {
1072 
1073 #ifdef ENABLE_4335BT_WAR
1074 	bcm_bt_unlock(lock_cookie_wifi);
1075 	printk("%s: btlock released\n", __FUNCTION__);
1076 #endif /* ENABLE_4335BT_WAR */
1077 
1078 	if (!dhd_download_fw_on_driverload) {
1079 		/* Call customer gpio to turn off power with WL_REG_ON signal */
1080 		dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
1081 		g_wifi_on = FALSE;
1082 	}
1083 }
1084 
1085 
1086 /**
1087  * Functions for Android WiFi card detection
1088  */
1089 #if defined(CONFIG_WIFI_CONTROL_FUNC)
1090 
1091 bool g_wifi_poweron = FALSE;
1092 static int g_wifidev_registered = 0;
1093 static struct semaphore wifi_control_sem;
1094 static struct wifi_platform_data *wifi_control_data = NULL;
1095 static struct resource *wifi_irqres = NULL;
1096 static struct regulator *wifi_regulator = NULL;
1097 
1098 static int wifi_add_dev(void);
1099 static void wifi_del_dev(void);
1100 
wl_android_wifictrl_func_add(void)1101 int wl_android_wifictrl_func_add(void)
1102 {
1103 	int ret = 0;
1104 	sema_init(&wifi_control_sem, 0);
1105 
1106 	ret = wifi_add_dev();
1107 	if (ret) {
1108 		DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__));
1109 		return ret;
1110 	}
1111 	g_wifidev_registered = 1;
1112 
1113 	/* Waiting callback after platform_driver_register is done or exit with error */
1114 	if (down_timeout(&wifi_control_sem,  msecs_to_jiffies(1000)) != 0) {
1115 		ret = -EINVAL;
1116 		DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__));
1117 	}
1118 
1119 	return ret;
1120 }
1121 
wl_android_wifictrl_func_del(void)1122 void wl_android_wifictrl_func_del(void)
1123 {
1124 	if (g_wifidev_registered)
1125 	{
1126 		wifi_del_dev();
1127 		g_wifidev_registered = 0;
1128 	}
1129 }
1130 
wl_android_prealloc(int section,unsigned long size)1131 void* wl_android_prealloc(int section, unsigned long size)
1132 {
1133 	void *alloc_ptr = NULL;
1134 	if (wifi_control_data && wifi_control_data->mem_prealloc) {
1135 		alloc_ptr = wifi_control_data->mem_prealloc(section, size);
1136 		if (alloc_ptr) {
1137 			DHD_INFO(("success alloc section %d\n", section));
1138 			if (size != 0L)
1139 				bzero(alloc_ptr, size);
1140 			return alloc_ptr;
1141 		}
1142 	}
1143 
1144 	DHD_ERROR(("can't alloc section %d\n", section));
1145 	return NULL;
1146 }
1147 
wifi_get_irq_number(unsigned long * irq_flags_ptr)1148 int wifi_get_irq_number(unsigned long *irq_flags_ptr)
1149 {
1150 	if (wifi_irqres) {
1151 		*irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
1152 		return (int)wifi_irqres->start;
1153 	}
1154 #ifdef CUSTOM_OOB_GPIO_NUM
1155 	return CUSTOM_OOB_GPIO_NUM;
1156 #else
1157 	return -1;
1158 #endif
1159 }
1160 
wifi_set_power(int on,unsigned long msec)1161 int wifi_set_power(int on, unsigned long msec)
1162 {
1163 	int ret = 0;
1164 	DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
1165 	if (wifi_regulator && on)
1166 		ret = regulator_enable(wifi_regulator);
1167 	if (wifi_control_data && wifi_control_data->set_power) {
1168 #ifdef ENABLE_4335BT_WAR
1169 		if (on) {
1170 			printk("WiFi: trying to acquire BT lock\n");
1171 			if (bcm_bt_lock(lock_cookie_wifi) != 0)
1172 				printk("** WiFi: timeout in acquiring bt lock**\n");
1173 			printk("%s: btlock acquired\n", __FUNCTION__);
1174 		}
1175 		else {
1176 			/* For a exceptional case, release btlock */
1177 			bcm_bt_unlock(lock_cookie_wifi);
1178 		}
1179 #endif /* ENABLE_4335BT_WAR */
1180 		ret = wifi_control_data->set_power(on);
1181 	}
1182 
1183 	if (wifi_regulator && !on)
1184 		ret = regulator_disable(wifi_regulator);
1185 
1186 	if (msec && !ret)
1187 		OSL_SLEEP(msec);
1188 	return ret;
1189 }
1190 
1191 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
wifi_get_mac_addr(unsigned char * buf)1192 int wifi_get_mac_addr(unsigned char *buf)
1193 {
1194 	DHD_ERROR(("%s\n", __FUNCTION__));
1195 	if (!buf)
1196 		return -EINVAL;
1197 	if (wifi_control_data && wifi_control_data->get_mac_addr) {
1198 		return wifi_control_data->get_mac_addr(buf);
1199 	}
1200 	return -EOPNOTSUPP;
1201 }
1202 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
1203 
1204 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
wifi_get_country_code(char * ccode)1205 void *wifi_get_country_code(char *ccode)
1206 {
1207 	DHD_TRACE(("%s\n", __FUNCTION__));
1208 	if (!ccode)
1209 		return NULL;
1210 	if (wifi_control_data && wifi_control_data->get_country_code) {
1211 		return wifi_control_data->get_country_code(ccode);
1212 	}
1213 	return NULL;
1214 }
1215 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
1216 
wifi_set_carddetect(int on)1217 static int wifi_set_carddetect(int on)
1218 {
1219 	DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
1220 	if (wifi_control_data && wifi_control_data->set_carddetect) {
1221 		wifi_control_data->set_carddetect(on);
1222 	}
1223 	return 0;
1224 }
1225 
get_wifi_irqres_from_of(struct platform_device * pdev)1226 static struct resource *get_wifi_irqres_from_of(struct platform_device *pdev)
1227 {
1228 	static struct resource gpio_wifi_irqres;
1229 	int irq;
1230 	int gpio = of_get_gpio(pdev->dev.of_node, 0);
1231 	if (gpio < 0)
1232 		return NULL;
1233 	irq = gpio_to_irq(gpio);
1234 	if (irq < 0)
1235 		return NULL;
1236 
1237 	gpio_wifi_irqres.name = "bcmdhd_wlan_irq";
1238 	gpio_wifi_irqres.start = irq;
1239 	gpio_wifi_irqres.end = irq;
1240 	gpio_wifi_irqres.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL |
1241 		IORESOURCE_IRQ_SHAREABLE;
1242 
1243 	return &gpio_wifi_irqres;
1244 }
1245 
wifi_probe(struct platform_device * pdev)1246 static int wifi_probe(struct platform_device *pdev)
1247 {
1248 	int err;
1249 	struct regulator *regulator;
1250 	struct wifi_platform_data *wifi_ctrl =
1251 		(struct wifi_platform_data *)(pdev->dev.platform_data);
1252 
1253 	if (!wifi_ctrl) {
1254 		regulator = regulator_get(&pdev->dev, "wlreg_on");
1255 		if (IS_ERR(regulator))
1256 			return PTR_ERR(regulator);
1257 		wifi_regulator = regulator;
1258 	}
1259 
1260 	wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
1261 	if (wifi_irqres == NULL)
1262 		wifi_irqres = platform_get_resource_byname(pdev,
1263 			IORESOURCE_IRQ, "bcm4329_wlan_irq");
1264 	if (wifi_irqres == NULL)
1265 		wifi_irqres = get_wifi_irqres_from_of(pdev);
1266 	wifi_control_data = wifi_ctrl;
1267 	err = wifi_set_power(1, 0);	/* Power On */
1268 	if (unlikely(err)) {
1269 		DHD_ERROR(("%s: set_power failed. err=%d\n", __FUNCTION__, err));
1270 		wifi_set_power(0, WIFI_TURNOFF_DELAY);
1271 		/* WL_REG_ON state unknown, Power off forcely */
1272 	} else {
1273 		wifi_set_carddetect(1);	/* CardDetect (0->1) */
1274 		g_wifi_poweron = TRUE;
1275 	}
1276 
1277 	up(&wifi_control_sem);
1278 	return 0;
1279 }
1280 
wifi_remove(struct platform_device * pdev)1281 static int wifi_remove(struct platform_device *pdev)
1282 {
1283 	struct wifi_platform_data *wifi_ctrl =
1284 		(struct wifi_platform_data *)(pdev->dev.platform_data);
1285 	struct io_cfg *cur, *q;
1286 
1287 	DHD_ERROR(("## %s\n", __FUNCTION__));
1288 	wifi_control_data = wifi_ctrl;
1289 
1290 	if (g_wifi_poweron) {
1291 	wifi_set_power(0, WIFI_TURNOFF_DELAY);	/* Power Off */
1292 	wifi_set_carddetect(0);	/* CardDetect (1->0) */
1293 		g_wifi_poweron = FALSE;
1294 		list_for_each_entry_safe(cur, q, &miracast_resume_list, list) {
1295 			list_del(&cur->list);
1296 			kfree(cur);
1297 		}
1298 	}
1299 	if (wifi_regulator) {
1300 		regulator_put(wifi_regulator);
1301 		wifi_regulator = NULL;
1302 	}
1303 
1304 	up(&wifi_control_sem);
1305 	return 0;
1306 }
1307 
wifi_suspend(struct platform_device * pdev,pm_message_t state)1308 static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
1309 {
1310 	DHD_TRACE(("##> %s\n", __FUNCTION__));
1311 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1
1312 	bcmsdh_oob_intr_set(0);
1313 #endif /* (OOB_INTR_ONLY) */
1314 	return 0;
1315 }
1316 
wifi_resume(struct platform_device * pdev)1317 static int wifi_resume(struct platform_device *pdev)
1318 {
1319 	DHD_TRACE(("##> %s\n", __FUNCTION__));
1320 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) && 1
1321 	if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
1322 		bcmsdh_oob_intr_set(1);
1323 #endif /* (OOB_INTR_ONLY) */
1324 	return 0;
1325 }
1326 
1327 static const struct of_device_id wifi_device_dt_match[] = {
1328 	{ .compatible = "android,bcmdhd_wlan", },
1329 	{},
1330 };
1331 MODULE_DEVICE_TABLE(of, wifi_device_dt_match);
1332 
1333 static struct platform_driver wifi_device = {
1334 	.probe          = wifi_probe,
1335 	.remove         = wifi_remove,
1336 	.suspend        = wifi_suspend,
1337 	.resume         = wifi_resume,
1338 	.driver         = {
1339 	.name   = "bcmdhd_wlan",
1340 	.of_match_table = wifi_device_dt_match,
1341 	}
1342 };
1343 
1344 static struct platform_driver wifi_device_legacy = {
1345 	.probe          = wifi_probe,
1346 	.remove         = wifi_remove,
1347 	.suspend        = wifi_suspend,
1348 	.resume         = wifi_resume,
1349 	.driver         = {
1350 	.name   = "bcm4329_wlan",
1351 	}
1352 };
1353 
wifi_add_dev(void)1354 static int wifi_add_dev(void)
1355 {
1356 	int ret = 0;
1357 	DHD_TRACE(("## Calling platform_driver_register\n"));
1358 	ret = platform_driver_register(&wifi_device);
1359 	if (ret)
1360 		return ret;
1361 
1362 	ret = platform_driver_register(&wifi_device_legacy);
1363 	return ret;
1364 }
1365 
wifi_del_dev(void)1366 static void wifi_del_dev(void)
1367 {
1368 	DHD_TRACE(("## Unregister platform_driver_register\n"));
1369 	platform_driver_unregister(&wifi_device);
1370 	platform_driver_unregister(&wifi_device_legacy);
1371 }
1372 #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */
1373