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