net: wireless: rockchip_wlan: add rtl8723cs support
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / rockchip_wlan / rtl8723cs / os_dep / linux / rtw_android.c
1 /******************************************************************************
2  *
3  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of version 2 of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17  *
18  *
19  ******************************************************************************/
20
21 #ifdef CONFIG_GPIO_WAKEUP
22 #include <linux/gpio.h>
23 #endif
24
25 #include <drv_types.h>
26
27 #if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
28 #include <linux/platform_device.h>
29 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
30         #include <linux/wlan_plat.h>
31 #else
32         #include <linux/wifi_tiwlan.h>
33 #endif
34 #endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */
35
36 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0))
37 #define strnicmp        strncasecmp
38 #endif /* Linux kernel >= 4.0.0 */
39
40 #ifdef CONFIG_GPIO_WAKEUP
41 #include <linux/interrupt.h>
42 #include <linux/irq.h>
43 #endif
44
45 #include "rtw_version.h"
46
47 extern void macstr2num(u8 *dst, u8 *src);
48
49 const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
50         "START",
51         "STOP",
52         "SCAN-ACTIVE",
53         "SCAN-PASSIVE",
54         "RSSI",
55         "LINKSPEED",
56         "RXFILTER-START",
57         "RXFILTER-STOP",
58         "RXFILTER-ADD",
59         "RXFILTER-REMOVE",
60         "BTCOEXSCAN-START",
61         "BTCOEXSCAN-STOP",
62         "BTCOEXMODE",
63         "SETSUSPENDOPT",
64         "P2P_DEV_ADDR",
65         "SETFWPATH",
66         "SETBAND",
67         "GETBAND",
68         "COUNTRY",
69         "P2P_SET_NOA",
70         "P2P_GET_NOA",
71         "P2P_SET_PS",
72         "SET_AP_WPS_P2P_IE",
73
74         "MIRACAST",
75
76 #ifdef CONFIG_PNO_SUPPORT
77         "PNOSSIDCLR",
78         "PNOSETUP",
79         "PNOFORCE",
80         "PNODEBUG",
81 #endif
82
83         "MACADDR",
84
85         "BLOCK_SCAN",
86         "BLOCK",
87         "WFD-ENABLE",
88         "WFD-DISABLE",
89         "WFD-SET-TCPPORT",
90         "WFD-SET-MAXTPUT",
91         "WFD-SET-DEVTYPE",
92         "SET_DTIM",
93         "HOSTAPD_SET_MACADDR_ACL",
94         "HOSTAPD_ACL_ADD_STA",
95         "HOSTAPD_ACL_REMOVE_STA",
96 #if defined(CONFIG_GTK_OL) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0))
97         "GTK_REKEY_OFFLOAD",
98 #endif /* CONFIG_GTK_OL */
99 /*      Private command for     P2P disable*/
100         "P2P_DISABLE",
101         "DRIVER_VERSION"
102 };
103
104 #ifdef CONFIG_PNO_SUPPORT
105 #define PNO_TLV_PREFIX                  'S'
106 #define PNO_TLV_VERSION                 '1'
107 #define PNO_TLV_SUBVERSION              '2'
108 #define PNO_TLV_RESERVED                '0'
109 #define PNO_TLV_TYPE_SSID_IE    'S'
110 #define PNO_TLV_TYPE_TIME               'T'
111 #define PNO_TLV_FREQ_REPEAT             'R'
112 #define PNO_TLV_FREQ_EXPO_MAX   'M'
113
114 typedef struct cmd_tlv {
115         char prefix;
116         char version;
117         char subver;
118         char reserved;
119 } cmd_tlv_t;
120
121 #ifdef CONFIG_PNO_SET_DEBUG
122 char pno_in_example[] = {
123         'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
124         'S', '1', '2', '0',
125         'S',    /* 1 */
126         0x05,
127         'd', 'l', 'i', 'n', 'k',
128         'S',    /* 2 */
129         0x06,
130         'B', 'U', 'F', 'B', 'U', 'F',
131         'S',    /* 3 */
132         0x20,
133         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '!', '@', '#', '$', '%', '^',
134         'S',    /* 4 */
135         0x0a,
136         '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
137         'T',
138         '0', '5',
139         'R',
140         '2',
141         'M',
142         '2',
143         0x00
144 };
145 #endif /* CONFIG_PNO_SET_DEBUG */
146 #endif /* PNO_SUPPORT */
147
148 typedef struct android_wifi_priv_cmd {
149         char *buf;
150         int used_len;
151         int total_len;
152 } android_wifi_priv_cmd;
153
154 #ifdef CONFIG_COMPAT
155 typedef struct compat_android_wifi_priv_cmd {
156         compat_uptr_t buf;
157         int used_len;
158         int total_len;
159 } compat_android_wifi_priv_cmd;
160 #endif /* CONFIG_COMPAT */
161
162 /**
163  * Local (static) functions and variables
164  */
165
166 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
167  * time (only) in dhd_open, subsequential wifi on will be handled by
168  * wl_android_wifi_on
169  */
170 static int g_wifi_on = _TRUE;
171
172 unsigned int oob_irq = 0;
173 unsigned int oob_gpio = 0;
174
175 #ifdef CONFIG_PNO_SUPPORT
176 /*
177  * rtw_android_pno_setup
178  * Description:
179  * This is used for private command.
180  *
181  * Parameter:
182  * net: net_device
183  * command: parameters from private command
184  * total_len: the length of the command.
185  *
186  * */
187 static int rtw_android_pno_setup(struct net_device *net, char *command, int total_len)
188 {
189         pno_ssid_t pno_ssids_local[MAX_PNO_LIST_COUNT];
190         int res = -1;
191         int nssid = 0;
192         cmd_tlv_t *cmd_tlv_temp;
193         char *str_ptr;
194         int tlv_size_left;
195         int pno_time = 0;
196         int pno_repeat = 0;
197         int pno_freq_expo_max = 0;
198         int cmdlen = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_PNOSETUP_SET]) + 1;
199
200 #ifdef CONFIG_PNO_SET_DEBUG
201         int i;
202         char *p;
203         p = pno_in_example;
204
205         total_len = sizeof(pno_in_example);
206         str_ptr = p + cmdlen;
207 #else
208         str_ptr = command + cmdlen;
209 #endif
210
211         if (total_len < (cmdlen + sizeof(cmd_tlv_t))) {
212                 RTW_INFO("%s argument=%d less min size\n", __func__, total_len);
213                 goto exit_proc;
214         }
215
216         tlv_size_left = total_len - cmdlen;
217
218         cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
219         memset(pno_ssids_local, 0, sizeof(pno_ssids_local));
220
221         if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
222             (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
223             (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) {
224
225                 str_ptr += sizeof(cmd_tlv_t);
226                 tlv_size_left -= sizeof(cmd_tlv_t);
227
228                 nssid = rtw_parse_ssid_list_tlv(&str_ptr, pno_ssids_local,
229                              MAX_PNO_LIST_COUNT, &tlv_size_left);
230                 if (nssid <= 0) {
231                         RTW_INFO("SSID is not presented or corrupted ret=%d\n", nssid);
232                         goto exit_proc;
233                 } else {
234                         if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
235                                 RTW_INFO("%s scan duration corrupted field size %d\n",
236                                          __func__, tlv_size_left);
237                                 goto exit_proc;
238                         }
239                         str_ptr++;
240                         pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
241                         RTW_INFO("%s: pno_time=%d\n", __func__, pno_time);
242
243                         if (str_ptr[0] != 0) {
244                                 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
245                                         RTW_INFO("%s pno repeat : corrupted field\n",
246                                                  __func__);
247                                         goto exit_proc;
248                                 }
249                                 str_ptr++;
250                                 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
251                                 RTW_INFO("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat);
252                                 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
253                                         RTW_INFO("%s FREQ_EXPO_MAX corrupted field size\n",
254                                                  __func__);
255                                         goto exit_proc;
256                                 }
257                                 str_ptr++;
258                                 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
259                                 RTW_INFO("%s: pno_freq_expo_max=%d\n",
260                                          __func__, pno_freq_expo_max);
261                         }
262                 }
263         } else {
264                 RTW_INFO("%s get wrong TLV command\n", __FUNCTION__);
265                 goto exit_proc;
266         }
267
268         res = rtw_dev_pno_set(net, pno_ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
269
270 #ifdef CONFIG_PNO_SET_DEBUG
271         rtw_dev_pno_debug(net);
272 #endif
273
274 exit_proc:
275         return res;
276 }
277
278 /*
279  * rtw_android_cfg80211_pno_setup
280  * Description:
281  * This is used for cfg80211 sched_scan.
282  *
283  * Parameter:
284  * net: net_device
285  * request: cfg80211_request
286  * */
287
288 int rtw_android_cfg80211_pno_setup(struct net_device *net,
289                    struct cfg80211_ssid *ssids, int n_ssids, int interval)
290 {
291         int res = -1;
292         int nssid = 0;
293         int pno_time = 0;
294         int pno_repeat = 0;
295         int pno_freq_expo_max = 0;
296         int index = 0;
297         pno_ssid_t pno_ssids_local[MAX_PNO_LIST_COUNT];
298
299         if (n_ssids > MAX_PNO_LIST_COUNT || n_ssids < 0) {
300                 RTW_INFO("%s: nssids(%d) is invalid.\n", __func__, n_ssids);
301                 return -EINVAL;
302         }
303
304         memset(pno_ssids_local, 0, sizeof(pno_ssids_local));
305
306         nssid = n_ssids;
307
308         for (index = 0 ; index < nssid ; index++) {
309                 pno_ssids_local[index].SSID_len = ssids[index].ssid_len;
310                 memcpy(pno_ssids_local[index].SSID, ssids[index].ssid,
311                        ssids[index].ssid_len);
312         }
313
314         pno_time = (interval / 1000);
315
316         RTW_INFO("%s: nssids: %d, pno_time=%d\n", __func__, nssid, pno_time);
317
318         res = rtw_dev_pno_set(net, pno_ssids_local, nssid, pno_time,
319                               pno_repeat, pno_freq_expo_max);
320
321 #ifdef CONFIG_PNO_SET_DEBUG
322         rtw_dev_pno_debug(net);
323 #endif
324 exit_proc:
325         return res;
326 }
327
328 int rtw_android_pno_enable(struct net_device *net, int pno_enable)
329 {
330         _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
331         struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter);
332
333         if (pwrctl) {
334                 pwrctl->wowlan_pno_enable = pno_enable;
335                 RTW_INFO("%s: wowlan_pno_enable: %d\n", __func__, pwrctl->wowlan_pno_enable);
336                 if (pwrctl->wowlan_pno_enable == 0) {
337                         if (pwrctl->pnlo_info != NULL) {
338                                 rtw_mfree((u8 *)pwrctl->pnlo_info, sizeof(pno_nlo_info_t));
339                                 pwrctl->pnlo_info = NULL;
340                         }
341                         if (pwrctl->pno_ssid_list != NULL) {
342                                 rtw_mfree((u8 *)pwrctl->pno_ssid_list, sizeof(pno_ssid_list_t));
343                                 pwrctl->pno_ssid_list = NULL;
344                         }
345                         if (pwrctl->pscan_info != NULL) {
346                                 rtw_mfree((u8 *)pwrctl->pscan_info, sizeof(pno_scan_info_t));
347                                 pwrctl->pscan_info = NULL;
348                         }
349                 }
350                 return 0;
351         } else
352                 return -1;
353 }
354 #endif /* CONFIG_PNO_SUPPORT */
355
356 int rtw_android_cmdstr_to_num(char *cmdstr)
357 {
358         int cmd_num;
359         for (cmd_num = 0 ; cmd_num < ANDROID_WIFI_CMD_MAX; cmd_num++)
360                 if (0 == strnicmp(cmdstr , android_wifi_cmd_str[cmd_num], strlen(android_wifi_cmd_str[cmd_num])))
361                         break;
362
363         return cmd_num;
364 }
365
366 int rtw_android_get_rssi(struct net_device *net, char *command, int total_len)
367 {
368         _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
369         struct  mlme_priv       *pmlmepriv = &(padapter->mlmepriv);
370         struct  wlan_network    *pcur_network = &pmlmepriv->cur_network;
371         int bytes_written = 0;
372
373         if (check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
374                 bytes_written += snprintf(&command[bytes_written], total_len, "%s rssi %d",
375                         pcur_network->network.Ssid.Ssid, padapter->recvpriv.rssi);
376         }
377
378         return bytes_written;
379 }
380
381 int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len)
382 {
383         _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
384         struct  mlme_priv       *pmlmepriv = &(padapter->mlmepriv);
385         struct  wlan_network    *pcur_network = &pmlmepriv->cur_network;
386         int bytes_written = 0;
387         u16 link_speed = 0;
388
389         link_speed = rtw_get_cur_max_rate(padapter) / 10;
390         bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
391
392         return bytes_written;
393 }
394
395 int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len)
396 {
397         _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
398         int bytes_written = 0;
399
400         bytes_written = snprintf(command, total_len, "Macaddr = "MAC_FMT, MAC_ARG(net->dev_addr));
401         return bytes_written;
402 }
403
404 int rtw_android_set_country(struct net_device *net, char *command, int total_len)
405 {
406         _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
407         char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1;
408         int ret = _FAIL;
409
410         ret = rtw_set_country(adapter, country_code);
411
412         return (ret == _SUCCESS) ? 0 : -1;
413 }
414
415 int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int total_len)
416 {
417         int bytes_written = 0;
418
419         /* We use the same address as our HW MAC address */
420         _rtw_memcpy(command, net->dev_addr, ETH_ALEN);
421
422         bytes_written = ETH_ALEN;
423         return bytes_written;
424 }
425
426 int rtw_android_set_block_scan(struct net_device *net, char *command, int total_len)
427 {
428         _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
429         char *block_value = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_BLOCK_SCAN]) + 1;
430
431 #ifdef CONFIG_IOCTL_CFG80211
432         adapter_wdev_data(adapter)->block_scan = (*block_value == '0') ? _FALSE : _TRUE;
433 #endif
434
435         return 0;
436 }
437
438 int rtw_android_set_block(struct net_device *net, char *command, int total_len)
439 {
440         _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
441         char *block_value = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_BLOCK]) + 1;
442
443 #ifdef CONFIG_IOCTL_CFG80211
444         adapter_wdev_data(adapter)->block = (*block_value == '0') ? _FALSE : _TRUE;
445 #endif
446
447         return 0;
448 }
449
450 int rtw_android_setband(struct net_device *net, char *command, int total_len)
451 {
452         _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
453         char *arg = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SETBAND]) + 1;
454         u32 band = WIFI_FREQUENCY_BAND_AUTO;
455         int ret = _FAIL;
456
457         if (sscanf(arg, "%u", &band) >= 1)
458                 ret = rtw_set_band(adapter, band);
459
460         return (ret == _SUCCESS) ? 0 : -1;
461 }
462
463 int rtw_android_getband(struct net_device *net, char *command, int total_len)
464 {
465         _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
466         int bytes_written = 0;
467
468         bytes_written = snprintf(command, total_len, "%u", adapter->setband);
469
470         return bytes_written;
471 }
472
473 #ifdef CONFIG_WFD
474 int rtw_android_set_miracast_mode(struct net_device *net, char *command, int total_len)
475 {
476         _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
477         struct wifi_display_info *wfd_info = &adapter->wfd_info;
478         char *arg = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_MIRACAST]) + 1;
479         u8 mode;
480         int num;
481         int ret = _FAIL;
482
483         num = sscanf(arg, "%hhu", &mode);
484
485         if (num < 1)
486                 goto exit;
487
488         switch (mode) {
489         case 1: /* soruce */
490                 mode = MIRACAST_SOURCE;
491                 break;
492         case 2: /* sink */
493                 mode = MIRACAST_SINK;
494                 break;
495         case 0: /* disabled */
496         default:
497                 mode = MIRACAST_DISABLED;
498                 break;
499         }
500         wfd_info->stack_wfd_mode = mode;
501         RTW_INFO("stack miracast mode: %s\n", get_miracast_mode_str(wfd_info->stack_wfd_mode));
502
503         ret = _SUCCESS;
504
505 exit:
506         return (ret == _SUCCESS) ? 0 : -1;
507 }
508 #endif /* CONFIG_WFD */
509
510 int get_int_from_command(char *pcmd)
511 {
512         int i = 0;
513
514         for (i = 0; i < strlen(pcmd); i++) {
515                 if (pcmd[i] == '=') {
516                         /*      Skip the '=' and space characters. */
517                         i += 2;
518                         break;
519                 }
520         }
521         return rtw_atoi(pcmd + i) ;
522 }
523
524 #if defined(CONFIG_GTK_OL) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0))
525 int rtw_gtk_offload(struct net_device *net, u8 *cmd_ptr)
526 {
527         int i;
528         /* u8 *cmd_ptr = priv_cmd.buf; */
529         struct sta_info *psta;
530         _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
531         struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
532         struct sta_priv *pstapriv = &padapter->stapriv;
533         struct security_priv *psecuritypriv = &(padapter->securitypriv);
534         psta = rtw_get_stainfo(pstapriv, get_bssid(pmlmepriv));
535
536
537         if (psta == NULL)
538                 RTW_INFO("%s, : Obtain Sta_info fail\n", __func__);
539         else {
540                 /* string command length of "GTK_REKEY_OFFLOAD" */
541                 cmd_ptr += 18;
542
543                 _rtw_memcpy(psta->kek, cmd_ptr, RTW_KEK_LEN);
544                 cmd_ptr += RTW_KEK_LEN;
545                 /*
546                 printk("supplicant KEK: ");
547                 for(i=0;i<RTW_KEK_LEN; i++)
548                         printk(" %02x ", psta->kek[i]);
549                 printk("\n supplicant KCK: ");
550                 */
551                 _rtw_memcpy(psta->kck, cmd_ptr, RTW_KCK_LEN);
552                 cmd_ptr += RTW_KCK_LEN;
553                 /*
554                 for(i=0;i<RTW_KEK_LEN; i++)
555                         printk(" %02x ", psta->kck[i]);
556                 */
557                 _rtw_memcpy(psta->replay_ctr, cmd_ptr, RTW_REPLAY_CTR_LEN);
558                 psecuritypriv->binstallKCK_KEK = _TRUE;
559
560                 /* printk("\nREPLAY_CTR: "); */
561                 /* for(i=0;i<RTW_REPLAY_CTR_LEN; i++) */
562                 /* printk(" %02x ", psta->replay_ctr[i]); */
563         }
564
565         return _SUCCESS;
566 }
567 #endif /* CONFIG_GTK_OL */
568
569 int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
570 {
571         int ret = 0;
572         char *command = NULL;
573         int cmd_num;
574         int bytes_written = 0;
575 #ifdef CONFIG_PNO_SUPPORT
576         uint cmdlen = 0;
577         uint pno_enable = 0;
578 #endif
579         android_wifi_priv_cmd priv_cmd;
580         _adapter        *padapter = (_adapter *) rtw_netdev_priv(net);
581 #ifdef CONFIG_WFD
582         struct wifi_display_info                *pwfd_info;
583 #endif
584
585         rtw_lock_suspend();
586
587         if (!ifr->ifr_data) {
588                 ret = -EINVAL;
589                 goto exit;
590         }
591         if (padapter->registrypriv.mp_mode == 1) {
592                 ret = -EINVAL;
593                 goto exit;
594         }
595 #ifdef CONFIG_COMPAT
596 #if (KERNEL_VERSION(4, 6, 0) > LINUX_VERSION_CODE)
597         if (is_compat_task()) {
598 #else
599         if (in_compat_syscall()) {
600 #endif
601                 /* User space is 32-bit, use compat ioctl */
602                 compat_android_wifi_priv_cmd compat_priv_cmd;
603
604                 if (copy_from_user(&compat_priv_cmd, ifr->ifr_data, sizeof(compat_android_wifi_priv_cmd))) {
605                         ret = -EFAULT;
606                         goto exit;
607                 }
608                 priv_cmd.buf = compat_ptr(compat_priv_cmd.buf);
609                 priv_cmd.used_len = compat_priv_cmd.used_len;
610                 priv_cmd.total_len = compat_priv_cmd.total_len;
611         } else
612 #endif /* CONFIG_COMPAT */
613                 if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
614                         ret = -EFAULT;
615                         goto exit;
616                 }
617         if (padapter->registrypriv.mp_mode == 1) {
618                 ret = -EFAULT;
619                 goto exit;
620         }
621         /*RTW_INFO("%s priv_cmd.buf=%p priv_cmd.total_len=%d  priv_cmd.used_len=%d\n",__func__,priv_cmd.buf,priv_cmd.total_len,priv_cmd.used_len);*/
622         command = rtw_zmalloc(priv_cmd.total_len);
623         if (!command) {
624                 RTW_INFO("%s: failed to allocate memory\n", __FUNCTION__);
625                 ret = -ENOMEM;
626                 goto exit;
627         }
628
629         if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)) {
630                 RTW_INFO("%s: failed to access memory\n", __FUNCTION__);
631                 ret = -EFAULT;
632                 goto exit;
633         }
634         if (copy_from_user(command, (void *)priv_cmd.buf, priv_cmd.total_len)) {
635                 ret = -EFAULT;
636                 goto exit;
637         }
638
639         RTW_INFO("%s: Android private cmd \"%s\" on %s\n"
640                  , __FUNCTION__, command, ifr->ifr_name);
641
642         cmd_num = rtw_android_cmdstr_to_num(command);
643
644         switch (cmd_num) {
645         case ANDROID_WIFI_CMD_START:
646                 /* bytes_written = wl_android_wifi_on(net); */
647                 goto response;
648         case ANDROID_WIFI_CMD_SETFWPATH:
649                 goto response;
650         }
651
652         if (!g_wifi_on) {
653                 RTW_INFO("%s: Ignore private cmd \"%s\" - iface %s is down\n"
654                          , __FUNCTION__, command, ifr->ifr_name);
655                 ret = 0;
656                 goto exit;
657         }
658
659         if (!hal_chk_wl_func(padapter, WL_FUNC_MIRACAST)) {
660                 switch (cmd_num) {
661                 case ANDROID_WIFI_CMD_WFD_ENABLE:
662                 case ANDROID_WIFI_CMD_WFD_DISABLE:
663                 case ANDROID_WIFI_CMD_WFD_SET_TCPPORT:
664                 case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT:
665                 case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE:
666                         goto response;
667                 }
668         }
669
670         switch (cmd_num) {
671
672         case ANDROID_WIFI_CMD_STOP:
673                 /* bytes_written = wl_android_wifi_off(net); */
674                 break;
675
676         case ANDROID_WIFI_CMD_SCAN_ACTIVE:
677                 /* rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE); */
678 #ifdef CONFIG_PLATFORM_MSTAR
679 #ifdef CONFIG_IOCTL_CFG80211
680                 adapter_wdev_data((_adapter *)rtw_netdev_priv(net))->bandroid_scan = _TRUE;
681 #endif /* CONFIG_IOCTL_CFG80211 */
682 #endif /* CONFIG_PLATFORM_MSTAR */
683                 break;
684         case ANDROID_WIFI_CMD_SCAN_PASSIVE:
685                 /* rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE); */
686                 break;
687
688         case ANDROID_WIFI_CMD_RSSI:
689                 bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len);
690                 break;
691         case ANDROID_WIFI_CMD_LINKSPEED:
692                 bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len);
693                 break;
694
695         case ANDROID_WIFI_CMD_MACADDR:
696                 bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len);
697                 break;
698
699         case ANDROID_WIFI_CMD_BLOCK_SCAN:
700                 bytes_written = rtw_android_set_block_scan(net, command, priv_cmd.total_len);
701                 break;
702
703         case ANDROID_WIFI_CMD_BLOCK:
704                 bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len);
705                 break;
706
707         case ANDROID_WIFI_CMD_RXFILTER_START:
708                 /* bytes_written = net_os_set_packet_filter(net, 1); */
709                 break;
710         case ANDROID_WIFI_CMD_RXFILTER_STOP:
711                 /* bytes_written = net_os_set_packet_filter(net, 0); */
712                 break;
713         case ANDROID_WIFI_CMD_RXFILTER_ADD:
714                 /* int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0'; */
715                 /* bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num); */
716                 break;
717         case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
718                 /* int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0'; */
719                 /* bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num); */
720                 break;
721
722         case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
723                 /* TBD: BTCOEXSCAN-START */
724                 break;
725         case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
726                 /* TBD: BTCOEXSCAN-STOP */
727                 break;
728         case ANDROID_WIFI_CMD_BTCOEXMODE:
729 #if 0
730                 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
731                 if (mode == 1)
732                         net_os_set_packet_filter(net, 0); /* DHCP starts */
733                 else
734                         net_os_set_packet_filter(net, 1); /* DHCP ends */
735 #ifdef WL_CFG80211
736                 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
737 #endif
738 #endif
739                 break;
740
741         case ANDROID_WIFI_CMD_SETSUSPENDOPT:
742                 /* bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); */
743                 break;
744
745         case ANDROID_WIFI_CMD_SETBAND:
746                 bytes_written = rtw_android_setband(net, command, priv_cmd.total_len);
747                 break;
748
749         case ANDROID_WIFI_CMD_GETBAND:
750                 bytes_written = rtw_android_getband(net, command, priv_cmd.total_len);
751                 break;
752
753         case ANDROID_WIFI_CMD_COUNTRY:
754                 bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len);
755                 break;
756
757 #ifdef CONFIG_PNO_SUPPORT
758         case ANDROID_WIFI_CMD_PNOSSIDCLR_SET:
759                 /* bytes_written = dhd_dev_pno_reset(net); */
760                 break;
761         case ANDROID_WIFI_CMD_PNOSETUP_SET:
762                 bytes_written = rtw_android_pno_setup(net, command, priv_cmd.total_len);
763                 break;
764         case ANDROID_WIFI_CMD_PNOENABLE_SET:
765                 cmdlen = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_PNOENABLE_SET]);
766                 pno_enable = *(command + cmdlen + 1) - '0';
767                 bytes_written = rtw_android_pno_enable(net, pno_enable);
768                 break;
769 #endif
770
771         case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
772                 bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
773                 break;
774         case ANDROID_WIFI_CMD_P2P_SET_NOA:
775                 /* int skip = strlen(CMD_P2P_SET_NOA) + 1; */
776                 /* bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip); */
777                 break;
778         case ANDROID_WIFI_CMD_P2P_GET_NOA:
779                 /* bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); */
780                 break;
781         case ANDROID_WIFI_CMD_P2P_SET_PS:
782                 /* int skip = strlen(CMD_P2P_SET_PS) + 1; */
783                 /* bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip); */
784                 break;
785
786 #ifdef CONFIG_IOCTL_CFG80211
787         case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE: {
788                 int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3;
789                 bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0');
790                 break;
791         }
792 #endif /* CONFIG_IOCTL_CFG80211 */
793
794 #ifdef CONFIG_WFD
795
796         case ANDROID_WIFI_CMD_MIRACAST:
797                 bytes_written = rtw_android_set_miracast_mode(net, command, priv_cmd.total_len);
798                 break;
799
800         case ANDROID_WIFI_CMD_WFD_ENABLE: {
801                 /*      Commented by Albert 2012/07/24 */
802                 /*      We can enable the WFD function by using the following command: */
803                 /*      wpa_cli driver wfd-enable */
804
805                 if (padapter->wdinfo.driver_interface == DRIVER_CFG80211)
806                         rtw_wfd_enable(padapter, 1);
807                 break;
808         }
809
810         case ANDROID_WIFI_CMD_WFD_DISABLE: {
811                 /*      Commented by Albert 2012/07/24 */
812                 /*      We can disable the WFD function by using the following command: */
813                 /*      wpa_cli driver wfd-disable */
814
815                 if (padapter->wdinfo.driver_interface == DRIVER_CFG80211)
816                         rtw_wfd_enable(padapter, 0);
817                 break;
818         }
819         case ANDROID_WIFI_CMD_WFD_SET_TCPPORT: {
820                 /*      Commented by Albert 2012/07/24 */
821                 /*      We can set the tcp port number by using the following command: */
822                 /*      wpa_cli driver wfd-set-tcpport = 554 */
823
824                 if (padapter->wdinfo.driver_interface == DRIVER_CFG80211)
825                         rtw_wfd_set_ctrl_port(padapter, (u16)get_int_from_command(priv_cmd.buf));
826                 break;
827         }
828         case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT: {
829                 break;
830         }
831         case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE: {
832                 /*      Commented by Albert 2012/08/28 */
833                 /*      Specify the WFD device type ( WFD source/primary sink ) */
834
835                 pwfd_info = &padapter->wfd_info;
836                 if (padapter->wdinfo.driver_interface == DRIVER_CFG80211) {
837                         pwfd_info->wfd_device_type = (u8) get_int_from_command(priv_cmd.buf);
838                         pwfd_info->wfd_device_type &= WFD_DEVINFO_DUAL;
839                 }
840                 break;
841         }
842 #endif
843         case ANDROID_WIFI_CMD_CHANGE_DTIM: {
844 #ifdef CONFIG_LPS
845                 u8 dtim;
846                 u8 *ptr = (u8 *) &priv_cmd.buf;
847
848                 ptr += 9;/* string command length of  "SET_DTIM"; */
849
850                 dtim = rtw_atoi(ptr);
851
852                 RTW_INFO("DTIM=%d\n", dtim);
853
854                 rtw_lps_change_dtim_cmd(padapter, dtim);
855 #endif
856         }
857         break;
858
859 #if CONFIG_RTW_MACADDR_ACL
860         case ANDROID_WIFI_CMD_HOSTAPD_SET_MACADDR_ACL: {
861                 rtw_set_macaddr_acl(padapter, get_int_from_command(command));
862                 break;
863         }
864         case ANDROID_WIFI_CMD_HOSTAPD_ACL_ADD_STA: {
865                 u8 addr[ETH_ALEN] = {0x00};
866                 macstr2num(addr, command + strlen("HOSTAPD_ACL_ADD_STA") + 3);  /* 3 is space bar + "=" + space bar these 3 chars */
867                 rtw_acl_add_sta(padapter, addr);
868                 break;
869         }
870         case ANDROID_WIFI_CMD_HOSTAPD_ACL_REMOVE_STA: {
871                 u8 addr[ETH_ALEN] = {0x00};
872                 macstr2num(addr, command + strlen("HOSTAPD_ACL_REMOVE_STA") + 3);       /* 3 is space bar + "=" + space bar these 3 chars */
873                 rtw_acl_remove_sta(padapter, addr);
874                 break;
875         }
876 #endif /* CONFIG_RTW_MACADDR_ACL */
877 #if defined(CONFIG_GTK_OL) && (LINUX_VERSION_CODE < KERNEL_VERSION(3, 1, 0))
878         case ANDROID_WIFI_CMD_GTK_REKEY_OFFLOAD:
879                 rtw_gtk_offload(net, (u8 *)command);
880                 break;
881 #endif /* CONFIG_GTK_OL          */
882         case ANDROID_WIFI_CMD_P2P_DISABLE: {
883 #ifdef CONFIG_P2P
884                 struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
885                 u8 channel, ch_offset;
886                 u16 bwmode;
887
888                 rtw_p2p_enable(padapter, P2P_ROLE_DISABLE);
889 #endif /* CONFIG_P2P */
890                 break;
891         }
892         case ANDROID_WIFI_CMD_DRIVERVERSION: {
893                 bytes_written = strlen(DRIVERVERSION);
894                 snprintf(command, bytes_written + 1, DRIVERVERSION);
895                 break;
896         }
897         default:
898                 RTW_INFO("Unknown PRIVATE command %s - ignored\n", command);
899                 snprintf(command, 3, "OK");
900                 bytes_written = strlen("OK");
901         }
902
903 response:
904         if (bytes_written >= 0) {
905                 if ((bytes_written == 0) && (priv_cmd.total_len > 0))
906                         command[0] = '\0';
907                 if (bytes_written >= priv_cmd.total_len) {
908                         RTW_INFO("%s: bytes_written = %d\n", __FUNCTION__, bytes_written);
909                         bytes_written = priv_cmd.total_len;
910                 } else
911                         bytes_written++;
912                 priv_cmd.used_len = bytes_written;
913                 if (copy_to_user((void *)priv_cmd.buf, command, bytes_written)) {
914                         RTW_INFO("%s: failed to copy data to user buffer\n", __FUNCTION__);
915                         ret = -EFAULT;
916                 }
917         } else
918                 ret = bytes_written;
919
920 exit:
921         rtw_unlock_suspend();
922         if (command)
923                 rtw_mfree(command, priv_cmd.total_len);
924
925         return ret;
926 }
927
928
929 /**
930  * Functions for Android WiFi card detection
931  */
932 #if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
933
934 static int g_wifidev_registered = 0;
935 static struct semaphore wifi_control_sem;
936 static struct wifi_platform_data *wifi_control_data = NULL;
937 static struct resource *wifi_irqres = NULL;
938
939 static int wifi_add_dev(void);
940 static void wifi_del_dev(void);
941
942 int rtw_android_wifictrl_func_add(void)
943 {
944         int ret = 0;
945         sema_init(&wifi_control_sem, 0);
946
947         ret = wifi_add_dev();
948         if (ret) {
949                 RTW_INFO("%s: platform_driver_register failed\n", __FUNCTION__);
950                 return ret;
951         }
952         g_wifidev_registered = 1;
953
954         /* Waiting callback after platform_driver_register is done or exit with error */
955         if (down_timeout(&wifi_control_sem,  msecs_to_jiffies(1000)) != 0) {
956                 ret = -EINVAL;
957                 RTW_INFO("%s: platform_driver_register timeout\n", __FUNCTION__);
958         }
959
960         return ret;
961 }
962
963 void rtw_android_wifictrl_func_del(void)
964 {
965         if (g_wifidev_registered) {
966                 wifi_del_dev();
967                 g_wifidev_registered = 0;
968         }
969 }
970
971 void *wl_android_prealloc(int section, unsigned long size)
972 {
973         void *alloc_ptr = NULL;
974         if (wifi_control_data && wifi_control_data->mem_prealloc) {
975                 alloc_ptr = wifi_control_data->mem_prealloc(section, size);
976                 if (alloc_ptr) {
977                         RTW_INFO("success alloc section %d\n", section);
978                         if (size != 0L)
979                                 memset(alloc_ptr, 0, size);
980                         return alloc_ptr;
981                 }
982         }
983
984         RTW_INFO("can't alloc section %d\n", section);
985         return NULL;
986 }
987
988 int wifi_get_irq_number(unsigned long *irq_flags_ptr)
989 {
990         if (wifi_irqres) {
991                 *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
992                 return (int)wifi_irqres->start;
993         }
994 #ifdef CUSTOM_OOB_GPIO_NUM
995         return CUSTOM_OOB_GPIO_NUM;
996 #else
997         return -1;
998 #endif
999 }
1000
1001 int wifi_set_power(int on, unsigned long msec)
1002 {
1003         RTW_INFO("%s = %d\n", __FUNCTION__, on);
1004         if (wifi_control_data && wifi_control_data->set_power)
1005                 wifi_control_data->set_power(on);
1006         if (msec)
1007                 msleep(msec);
1008         return 0;
1009 }
1010
1011 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
1012 int wifi_get_mac_addr(unsigned char *buf)
1013 {
1014         RTW_INFO("%s\n", __FUNCTION__);
1015         if (!buf)
1016                 return -EINVAL;
1017         if (wifi_control_data && wifi_control_data->get_mac_addr)
1018                 return wifi_control_data->get_mac_addr(buf);
1019         return -EOPNOTSUPP;
1020 }
1021 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
1022
1023 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) || defined(COMPAT_KERNEL_RELEASE)
1024 void *wifi_get_country_code(char *ccode, u32 flags)
1025 {
1026         RTW_INFO("%s\n", __FUNCTION__);
1027         if (!ccode)
1028                 return NULL;
1029         if (wifi_control_data && wifi_control_data->get_country_code)
1030                 return wifi_control_data->get_country_code(ccode, flags);
1031         return NULL;
1032 }
1033 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
1034
1035 static int wifi_set_carddetect(int on)
1036 {
1037         RTW_INFO("%s = %d\n", __FUNCTION__, on);
1038         if (wifi_control_data && wifi_control_data->set_carddetect)
1039                 wifi_control_data->set_carddetect(on);
1040         return 0;
1041 }
1042
1043 static int wifi_probe(struct platform_device *pdev)
1044 {
1045         struct wifi_platform_data *wifi_ctrl =
1046                 (struct wifi_platform_data *)(pdev->dev.platform_data);
1047         int wifi_wake_gpio = 0;
1048
1049         RTW_INFO("## %s\n", __FUNCTION__);
1050         wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
1051
1052         if (wifi_irqres == NULL)
1053                 wifi_irqres = platform_get_resource_byname(pdev,
1054                                 IORESOURCE_IRQ, "bcm4329_wlan_irq");
1055         else
1056                 wifi_wake_gpio = wifi_irqres->start;
1057
1058 #ifdef CONFIG_GPIO_WAKEUP
1059         printk("%s: gpio:%d wifi_wake_gpio:%d\n", __func__,
1060                wifi_irqres->start, wifi_wake_gpio);
1061
1062         if (wifi_wake_gpio > 0) {
1063 #ifdef CONFIG_PLATFORM_INTEL_BYT
1064                 wifi_configure_gpio();
1065 #else /* CONFIG_PLATFORM_INTEL_BYT */
1066                 gpio_request(wifi_wake_gpio, "oob_irq");
1067                 gpio_direction_input(wifi_wake_gpio);
1068                 oob_irq = gpio_to_irq(wifi_wake_gpio);
1069 #endif /* CONFIG_PLATFORM_INTEL_BYT */
1070                 printk("%s oob_irq:%d\n", __func__, oob_irq);
1071         } else if (wifi_irqres) {
1072                 oob_irq = wifi_irqres->start;
1073                 printk("%s oob_irq:%d\n", __func__, oob_irq);
1074         }
1075 #endif
1076         wifi_control_data = wifi_ctrl;
1077
1078         wifi_set_power(1, 0);   /* Power On */
1079         wifi_set_carddetect(1); /* CardDetect (0->1) */
1080
1081         up(&wifi_control_sem);
1082         return 0;
1083 }
1084
1085 #ifdef RTW_SUPPORT_PLATFORM_SHUTDOWN
1086 extern PADAPTER g_test_adapter;
1087
1088 static void shutdown_card(void)
1089 {
1090         u32 addr;
1091         u8 tmp8, cnt = 0;
1092
1093         if (NULL == g_test_adapter) {
1094                 RTW_INFO("%s: padapter==NULL\n", __FUNCTION__);
1095                 return;
1096         }
1097
1098 #ifdef CONFIG_FWLPS_IN_IPS
1099         LeaveAllPowerSaveMode(g_test_adapter);
1100 #endif /* CONFIG_FWLPS_IN_IPS */
1101
1102         /* Leave SDIO HCI Suspend */
1103         addr = 0x10250086;
1104         rtw_write8(g_test_adapter, addr, 0);
1105         do {
1106                 tmp8 = rtw_read8(g_test_adapter, addr);
1107                 cnt++;
1108                 RTW_INFO(FUNC_ADPT_FMT ": polling SDIO_HSUS_CTRL(0x%x)=0x%x, cnt=%d\n",
1109                          FUNC_ADPT_ARG(g_test_adapter), addr, tmp8, cnt);
1110
1111                 if (tmp8 & BIT(1))
1112                         break;
1113
1114                 if (cnt >= 100) {
1115                         RTW_INFO(FUNC_ADPT_FMT ": polling 0x%x[1]==1 FAIL!!\n",
1116                                  FUNC_ADPT_ARG(g_test_adapter), addr);
1117                         break;
1118                 }
1119
1120                 rtw_mdelay_os(10);
1121         } while (1);
1122
1123         /* unlock register I/O */
1124         rtw_write8(g_test_adapter, 0x1C, 0);
1125
1126         /* enable power down function */
1127         /* 0x04[4] = 1 */
1128         /* 0x05[7] = 1 */
1129         addr = 0x04;
1130         tmp8 = rtw_read8(g_test_adapter, addr);
1131         tmp8 |= BIT(4);
1132         rtw_write8(g_test_adapter, addr, tmp8);
1133         RTW_INFO(FUNC_ADPT_FMT ": read after write 0x%x=0x%x\n",
1134                 FUNC_ADPT_ARG(g_test_adapter), addr, rtw_read8(g_test_adapter, addr));
1135
1136         addr = 0x05;
1137         tmp8 = rtw_read8(g_test_adapter, addr);
1138         tmp8 |= BIT(7);
1139         rtw_write8(g_test_adapter, addr, tmp8);
1140         RTW_INFO(FUNC_ADPT_FMT ": read after write 0x%x=0x%x\n",
1141                 FUNC_ADPT_ARG(g_test_adapter), addr, rtw_read8(g_test_adapter, addr));
1142
1143         /* lock register page0 0x0~0xB read/write */
1144         rtw_write8(g_test_adapter, 0x1C, 0x0E);
1145
1146         rtw_set_surprise_removed(g_test_adapter);
1147         RTW_INFO(FUNC_ADPT_FMT ": bSurpriseRemoved=%s\n",
1148                 FUNC_ADPT_ARG(g_test_adapter), rtw_is_surprise_removed(g_test_adapter) ? "True" : "False");
1149 }
1150 #endif /* RTW_SUPPORT_PLATFORM_SHUTDOWN */
1151
1152 static int wifi_remove(struct platform_device *pdev)
1153 {
1154         struct wifi_platform_data *wifi_ctrl =
1155                 (struct wifi_platform_data *)(pdev->dev.platform_data);
1156
1157         RTW_INFO("## %s\n", __FUNCTION__);
1158         wifi_control_data = wifi_ctrl;
1159
1160         wifi_set_power(0, 0);   /* Power Off */
1161         wifi_set_carddetect(0); /* CardDetect (1->0) */
1162
1163         up(&wifi_control_sem);
1164         return 0;
1165 }
1166
1167 #ifdef RTW_SUPPORT_PLATFORM_SHUTDOWN
1168 static void wifi_shutdown(struct platform_device *pdev)
1169 {
1170         struct wifi_platform_data *wifi_ctrl =
1171                 (struct wifi_platform_data *)(pdev->dev.platform_data);
1172
1173
1174         RTW_INFO("## %s\n", __FUNCTION__);
1175
1176         wifi_control_data = wifi_ctrl;
1177
1178         shutdown_card();
1179         wifi_set_power(0, 0);   /* Power Off */
1180         wifi_set_carddetect(0); /* CardDetect (1->0) */
1181 }
1182 #endif /* RTW_SUPPORT_PLATFORM_SHUTDOWN */
1183
1184 static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
1185 {
1186         RTW_INFO("##> %s\n", __FUNCTION__);
1187 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
1188         bcmsdh_oob_intr_set(0);
1189 #endif
1190         return 0;
1191 }
1192
1193 static int wifi_resume(struct platform_device *pdev)
1194 {
1195         RTW_INFO("##> %s\n", __FUNCTION__);
1196 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
1197         if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
1198                 bcmsdh_oob_intr_set(1);
1199 #endif
1200         return 0;
1201 }
1202
1203 /* temporarily use these two */
1204 static struct platform_driver wifi_device = {
1205         .probe          = wifi_probe,
1206         .remove         = wifi_remove,
1207         .suspend        = wifi_suspend,
1208         .resume         = wifi_resume,
1209 #ifdef RTW_SUPPORT_PLATFORM_SHUTDOWN
1210         .shutdown       = wifi_shutdown,
1211 #endif /* RTW_SUPPORT_PLATFORM_SHUTDOWN */
1212         .driver         = {
1213                 .name   = "bcmdhd_wlan",
1214         }
1215 };
1216
1217 static struct platform_driver wifi_device_legacy = {
1218         .probe          = wifi_probe,
1219         .remove         = wifi_remove,
1220         .suspend        = wifi_suspend,
1221         .resume         = wifi_resume,
1222         .driver         = {
1223                 .name   = "bcm4329_wlan",
1224         }
1225 };
1226
1227 static int wifi_add_dev(void)
1228 {
1229         RTW_INFO("## Calling platform_driver_register\n");
1230         platform_driver_register(&wifi_device);
1231         platform_driver_register(&wifi_device_legacy);
1232         return 0;
1233 }
1234
1235 static void wifi_del_dev(void)
1236 {
1237         RTW_INFO("## Unregister platform_driver_register\n");
1238         platform_driver_unregister(&wifi_device);
1239         platform_driver_unregister(&wifi_device_legacy);
1240 }
1241 #endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */
1242
1243 #ifdef CONFIG_GPIO_WAKEUP
1244 #ifdef CONFIG_PLATFORM_INTEL_BYT
1245 int wifi_configure_gpio(void)
1246 {
1247         if (gpio_request(oob_gpio, "oob_irq")) {
1248                 RTW_INFO("## %s Cannot request GPIO\n", __FUNCTION__);
1249                 return -1;
1250         }
1251         gpio_export(oob_gpio, 0);
1252         if (gpio_direction_input(oob_gpio)) {
1253                 RTW_INFO("## %s Cannot set GPIO direction input\n", __FUNCTION__);
1254                 return -1;
1255         }
1256         oob_irq = gpio_to_irq(oob_gpio);
1257         if (oob_irq < 0) {
1258                 RTW_INFO("## %s Cannot convert GPIO to IRQ\n", __FUNCTION__);
1259                 return -1;
1260         }
1261
1262         RTW_INFO("## %s OOB_IRQ=%d\n", __FUNCTION__, oob_irq);
1263
1264         return 0;
1265 }
1266 #endif /* CONFIG_PLATFORM_INTEL_BYT */
1267 void wifi_free_gpio(unsigned int gpio)
1268 {
1269 #ifdef CONFIG_PLATFORM_INTEL_BYT
1270         if (gpio)
1271                 gpio_free(gpio);
1272 #endif /* CONFIG_PLATFORM_INTEL_BYT */
1273 }
1274 #endif /* CONFIG_GPIO_WAKEUP */