]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - drivers/net/wireless/realtek/rtl8192cu/os_dep/linux/rtw_android.c
net: Add non-mainline source for rtl8192cu wlan
[mirror_ubuntu-bionic-kernel.git] / drivers / net / wireless / realtek / rtl8192cu / 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 #include <linux/module.h>
22 #include <linux/netdevice.h>
23
24 #include <rtw_android.h>
25 #include <osdep_service.h>
26 #include <rtw_debug.h>
27 #include <ioctl_cfg80211.h>
28 #include <rtw_ioctl_set.h>
29
30 #if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
31 #include <linux/platform_device.h>
32 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
33 #include <linux/wlan_plat.h>
34 #else
35 #include <linux/wifi_tiwlan.h>
36 #endif
37 #endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */
38
39 const char *android_wifi_cmd_str[ANDROID_WIFI_CMD_MAX] = {
40 "START",
41 "STOP",
42 "SCAN-ACTIVE",
43 "SCAN-PASSIVE",
44 "RSSI",
45 "LINKSPEED",
46 "RXFILTER-START",
47 "RXFILTER-STOP",
48 "RXFILTER-ADD",
49 "RXFILTER-REMOVE",
50 "BTCOEXSCAN-START",
51 "BTCOEXSCAN-STOP",
52 "BTCOEXMODE",
53 "SETSUSPENDOPT",
54 "P2P_DEV_ADDR",
55 "SETFWPATH",
56 "SETBAND",
57 "GETBAND",
58 "COUNTRY",
59 "P2P_SET_NOA",
60 "P2P_GET_NOA",
61 "P2P_SET_PS",
62 "SET_AP_WPS_P2P_IE",
63 #ifdef PNO_SUPPORT
64 "PNOSSIDCLR",
65 "PNOSETUP ",
66 "PNOFORCE",
67 "PNODEBUG",
68 #endif
69
70 "MACADDR",
71
72 "BLOCK",
73 "WFD-ENABLE",
74 "WFD-DISABLE",
75 "WFD-SET-TCPPORT",
76 "WFD-SET-MAXTPUT",
77 "WFD-SET-DEVTYPE",
78 };
79
80 #ifdef PNO_SUPPORT
81 #define PNO_TLV_PREFIX 'S'
82 #define PNO_TLV_VERSION '1'
83 #define PNO_TLV_SUBVERSION '2'
84 #define PNO_TLV_RESERVED '0'
85 #define PNO_TLV_TYPE_SSID_IE 'S'
86 #define PNO_TLV_TYPE_TIME 'T'
87 #define PNO_TLV_FREQ_REPEAT 'R'
88 #define PNO_TLV_FREQ_EXPO_MAX 'M'
89
90 typedef struct cmd_tlv {
91 char prefix;
92 char version;
93 char subver;
94 char reserved;
95 } cmd_tlv_t;
96 #endif /* PNO_SUPPORT */
97
98 typedef struct android_wifi_priv_cmd {
99
100 #ifdef CONFIG_COMPAT
101 compat_uptr_t buf;
102 #else
103 char *buf;
104 #endif
105
106 int used_len;
107 int total_len;
108 } android_wifi_priv_cmd;
109
110 /**
111 * Local (static) functions and variables
112 */
113
114 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
115 * time (only) in dhd_open, subsequential wifi on will be handled by
116 * wl_android_wifi_on
117 */
118 static int g_wifi_on = _TRUE;
119
120
121 #ifdef PNO_SUPPORT
122 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
123 {
124 wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
125 int res = -1;
126 int nssid = 0;
127 cmd_tlv_t *cmd_tlv_temp;
128 char *str_ptr;
129 int tlv_size_left;
130 int pno_time = 0;
131 int pno_repeat = 0;
132 int pno_freq_expo_max = 0;
133
134 #ifdef PNO_SET_DEBUG
135 int i;
136 char pno_in_example[] = {
137 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
138 'S', '1', '2', '0',
139 'S',
140 0x05,
141 'd', 'l', 'i', 'n', 'k',
142 'S',
143 0x04,
144 'G', 'O', 'O', 'G',
145 'T',
146 '0', 'B',
147 'R',
148 '2',
149 'M',
150 '2',
151 0x00
152 };
153 #endif /* PNO_SET_DEBUG */
154
155 DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
156
157 if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
158 DBG_871X("%s argument=%d less min size\n", __FUNCTION__, total_len);
159 goto exit_proc;
160 }
161
162 #ifdef PNO_SET_DEBUG
163 memcpy(command, pno_in_example, sizeof(pno_in_example));
164 for (i = 0; i < sizeof(pno_in_example); i++)
165 printf("%02X ", command[i]);
166 printf("\n");
167 total_len = sizeof(pno_in_example);
168 #endif
169
170 str_ptr = command + strlen(CMD_PNOSETUP_SET);
171 tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
172
173 cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
174 memset(ssids_local, 0, sizeof(ssids_local));
175
176 if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
177 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
178 (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) {
179
180 str_ptr += sizeof(cmd_tlv_t);
181 tlv_size_left -= sizeof(cmd_tlv_t);
182
183 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
184 MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
185 DBG_871X("SSID is not presented or corrupted ret=%d\n", nssid);
186 goto exit_proc;
187 } else {
188 if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
189 DBG_871X("%s scan duration corrupted field size %d\n",
190 __FUNCTION__, tlv_size_left);
191 goto exit_proc;
192 }
193 str_ptr++;
194 pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
195 DHD_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
196
197 if (str_ptr[0] != 0) {
198 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
199 DBG_871X("%s pno repeat : corrupted field\n",
200 __FUNCTION__);
201 goto exit_proc;
202 }
203 str_ptr++;
204 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
205 DHD_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
206 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
207 DBG_871X("%s FREQ_EXPO_MAX corrupted field size\n",
208 __FUNCTION__);
209 goto exit_proc;
210 }
211 str_ptr++;
212 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
213 DHD_INFO(("%s: pno_freq_expo_max=%d\n",
214 __FUNCTION__, pno_freq_expo_max));
215 }
216 }
217 } else {
218 DBG_871X("%s get wrong TLV command\n", __FUNCTION__);
219 goto exit_proc;
220 }
221
222 res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
223
224 exit_proc:
225 return res;
226 }
227 #endif /* PNO_SUPPORT */
228
229 int rtw_android_cmdstr_to_num(char *cmdstr)
230 {
231 int cmd_num;
232 for(cmd_num=0 ; cmd_num<ANDROID_WIFI_CMD_MAX; cmd_num++)
233 if(0 == strncasecmp(cmdstr , android_wifi_cmd_str[cmd_num], strlen(android_wifi_cmd_str[cmd_num])) )
234 break;
235
236 return cmd_num;
237 }
238
239 int rtw_android_get_rssi(struct net_device *net, char *command, int total_len)
240 {
241 _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
242 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
243 struct wlan_network *pcur_network = &pmlmepriv->cur_network;
244 int bytes_written = 0;
245
246 if(check_fwstate(pmlmepriv, _FW_LINKED) == _TRUE) {
247 bytes_written += snprintf(&command[bytes_written], total_len, "%s rssi %d",
248 pcur_network->network.Ssid.Ssid, padapter->recvpriv.rssi);
249 }
250
251 return bytes_written;
252 }
253
254 int rtw_android_get_link_speed(struct net_device *net, char *command, int total_len)
255 {
256 _adapter *padapter = (_adapter *)rtw_netdev_priv(net);
257 struct mlme_priv *pmlmepriv = &(padapter->mlmepriv);
258 struct wlan_network *pcur_network = &pmlmepriv->cur_network;
259 int bytes_written = 0;
260 u16 link_speed = 0;
261
262 link_speed = rtw_get_cur_max_rate(padapter)/10;
263 bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
264
265 return bytes_written;
266 }
267
268 int rtw_android_get_macaddr(struct net_device *net, char *command, int total_len)
269 {
270 _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
271 int bytes_written = 0;
272
273 bytes_written = snprintf(command, total_len, "Macaddr = "MAC_FMT, MAC_ARG(net->dev_addr));
274 return bytes_written;
275 }
276
277 int rtw_android_set_country(struct net_device *net, char *command, int total_len)
278 {
279 _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
280 char *country_code = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_COUNTRY]) + 1;
281 int ret = _FAIL;
282
283 ret = rtw_set_country(adapter, country_code);
284
285 return (ret==_SUCCESS)?0:-1;
286 }
287
288 int rtw_android_get_p2p_dev_addr(struct net_device *net, char *command, int total_len)
289 {
290 int bytes_written = 0;
291
292 //We use the same address as our HW MAC address
293 _rtw_memcpy(command, net->dev_addr, ETH_ALEN);
294
295 bytes_written = ETH_ALEN;
296 return bytes_written;
297 }
298
299 int rtw_android_set_block(struct net_device *net, char *command, int total_len)
300 {
301 _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
302 char *block_value = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_BLOCK]) + 1;
303
304 #ifdef CONFIG_IOCTL_CFG80211
305 wdev_to_priv(adapter->rtw_wdev)->block = (*block_value=='0')?_FALSE:_TRUE;
306 #endif
307
308 return 0;
309 }
310
311 int rtw_android_setband(struct net_device *net, char *command, int total_len)
312 {
313 _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
314 char *arg = command + strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SETBAND]) + 1;
315 u32 band = GHZ_MAX;
316 int ret = _FAIL;
317
318 sscanf(arg, "%u", &band);
319 ret = rtw_set_band(adapter, band);
320
321 return (ret==_SUCCESS)?0:-1;
322 }
323
324 int rtw_android_getband(struct net_device *net, char *command, int total_len)
325 {
326 _adapter *adapter = (_adapter *)rtw_netdev_priv(net);
327 int bytes_written = 0;
328
329 bytes_written = snprintf(command, total_len, "%u", adapter->setband);
330
331 return bytes_written;
332 }
333
334 int get_int_from_command( char* pcmd )
335 {
336 int i = 0;
337
338 for( i = 0; i < strlen( pcmd ); i++ )
339 {
340 if ( pcmd[ i ] == '=' )
341 {
342 // Skip the '=' and space characters.
343 i += 2;
344 break;
345 }
346 }
347 return ( rtw_atoi( pcmd + i ) );
348 }
349
350 int rtw_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
351 {
352 int ret = 0;
353 char *command = NULL;
354 int cmd_num;
355 int bytes_written = 0;
356 android_wifi_priv_cmd priv_cmd;
357
358 rtw_lock_suspend();
359
360 if (!ifr->ifr_data) {
361 ret = -EINVAL;
362 goto exit;
363 }
364 if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
365 ret = -EFAULT;
366 goto exit;
367 }
368
369 command = rtw_zmalloc(priv_cmd.total_len);
370 if (!command)
371 {
372 DBG_871X("%s: failed to allocate memory\n", __FUNCTION__);
373 ret = -ENOMEM;
374 goto exit;
375 }
376
377 if (!access_ok(VERIFY_READ, priv_cmd.buf, priv_cmd.total_len)){
378 DBG_871X("%s: failed to access memory\n", __FUNCTION__);
379 ret = -EFAULT;
380 goto exit;
381 }
382 if (copy_from_user(command, (void *)priv_cmd.buf, priv_cmd.total_len)) {
383 ret = -EFAULT;
384 goto exit;
385 }
386
387 DBG_871X("%s: Android private cmd \"%s\" on %s\n"
388 , __FUNCTION__, command, ifr->ifr_name);
389
390 cmd_num = rtw_android_cmdstr_to_num(command);
391
392 switch(cmd_num) {
393 case ANDROID_WIFI_CMD_START:
394 //bytes_written = wl_android_wifi_on(net);
395 goto response;
396 case ANDROID_WIFI_CMD_SETFWPATH:
397 goto response;
398 }
399
400 if (!g_wifi_on) {
401 DBG_871X("%s: Ignore private cmd \"%s\" - iface %s is down\n"
402 ,__FUNCTION__, command, ifr->ifr_name);
403 ret = 0;
404 goto exit;
405 }
406
407 switch(cmd_num) {
408
409 case ANDROID_WIFI_CMD_STOP:
410 //bytes_written = wl_android_wifi_off(net);
411 break;
412
413 case ANDROID_WIFI_CMD_SCAN_ACTIVE:
414 //rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_ACTIVE);
415 #ifdef CONFIG_PLATFORM_MSTAR
416 #ifdef CONFIG_IOCTL_CFG80211
417 (wdev_to_priv(net->ieee80211_ptr))->bandroid_scan = _TRUE;
418 #endif //CONFIG_IOCTL_CFG80211
419 #endif //CONFIG_PLATFORM_MSTAR
420 break;
421 case ANDROID_WIFI_CMD_SCAN_PASSIVE:
422 //rtw_set_scan_mode((_adapter *)rtw_netdev_priv(net), SCAN_PASSIVE);
423 break;
424
425 case ANDROID_WIFI_CMD_RSSI:
426 bytes_written = rtw_android_get_rssi(net, command, priv_cmd.total_len);
427 break;
428 case ANDROID_WIFI_CMD_LINKSPEED:
429 bytes_written = rtw_android_get_link_speed(net, command, priv_cmd.total_len);
430 break;
431
432 case ANDROID_WIFI_CMD_MACADDR:
433 bytes_written = rtw_android_get_macaddr(net, command, priv_cmd.total_len);
434 break;
435
436 case ANDROID_WIFI_CMD_BLOCK:
437 bytes_written = rtw_android_set_block(net, command, priv_cmd.total_len);
438 break;
439
440 case ANDROID_WIFI_CMD_RXFILTER_START:
441 //bytes_written = net_os_set_packet_filter(net, 1);
442 break;
443 case ANDROID_WIFI_CMD_RXFILTER_STOP:
444 //bytes_written = net_os_set_packet_filter(net, 0);
445 break;
446 case ANDROID_WIFI_CMD_RXFILTER_ADD:
447 //int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
448 //bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
449 break;
450 case ANDROID_WIFI_CMD_RXFILTER_REMOVE:
451 //int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
452 //bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
453 break;
454
455 case ANDROID_WIFI_CMD_BTCOEXSCAN_START:
456 /* TBD: BTCOEXSCAN-START */
457 break;
458 case ANDROID_WIFI_CMD_BTCOEXSCAN_STOP:
459 /* TBD: BTCOEXSCAN-STOP */
460 break;
461 case ANDROID_WIFI_CMD_BTCOEXMODE:
462 #if 0
463 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
464 if (mode == 1)
465 net_os_set_packet_filter(net, 0); /* DHCP starts */
466 else
467 net_os_set_packet_filter(net, 1); /* DHCP ends */
468 #ifdef WL_CFG80211
469 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
470 #endif
471 #endif
472 break;
473
474 case ANDROID_WIFI_CMD_SETSUSPENDOPT:
475 //bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
476 break;
477
478 case ANDROID_WIFI_CMD_SETBAND:
479 bytes_written = rtw_android_setband(net, command, priv_cmd.total_len);
480 break;
481
482 case ANDROID_WIFI_CMD_GETBAND:
483 bytes_written = rtw_android_getband(net, command, priv_cmd.total_len);
484 break;
485
486 case ANDROID_WIFI_CMD_COUNTRY:
487 bytes_written = rtw_android_set_country(net, command, priv_cmd.total_len);
488 break;
489
490 #ifdef PNO_SUPPORT
491 case ANDROID_WIFI_CMD_PNOSSIDCLR_SET:
492 //bytes_written = dhd_dev_pno_reset(net);
493 break;
494 case ANDROID_WIFI_CMD_PNOSETUP_SET:
495 //bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
496 break;
497 case ANDROID_WIFI_CMD_PNOENABLE_SET:
498 //uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
499 //bytes_written = dhd_dev_pno_enable(net, pfn_enabled);
500 break;
501 #endif
502
503 case ANDROID_WIFI_CMD_P2P_DEV_ADDR:
504 bytes_written = rtw_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
505 break;
506 case ANDROID_WIFI_CMD_P2P_SET_NOA:
507 //int skip = strlen(CMD_P2P_SET_NOA) + 1;
508 //bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip);
509 break;
510 case ANDROID_WIFI_CMD_P2P_GET_NOA:
511 //bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
512 break;
513 case ANDROID_WIFI_CMD_P2P_SET_PS:
514 //int skip = strlen(CMD_P2P_SET_PS) + 1;
515 //bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, priv_cmd.total_len - skip);
516 break;
517
518 #ifdef CONFIG_IOCTL_CFG80211
519 case ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE:
520 {
521 int skip = strlen(android_wifi_cmd_str[ANDROID_WIFI_CMD_SET_AP_WPS_P2P_IE]) + 3;
522 bytes_written = rtw_cfg80211_set_mgnt_wpsp2pie(net, command + skip, priv_cmd.total_len - skip, *(command + skip - 2) - '0');
523 break;
524 }
525 #endif //CONFIG_IOCTL_CFG80211
526
527 #ifdef CONFIG_WFD
528 case ANDROID_WIFI_CMD_WFD_ENABLE:
529 {
530 // Commented by Albert 2012/07/24
531 // We can enable the WFD function by using the following command:
532 // wpa_cli driver wfd-enable
533
534 struct wifi_display_info *pwfd_info;
535 _adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
536
537 pwfd_info = &padapter->wfd_info;
538 if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
539 pwfd_info->wfd_enable = _TRUE;
540 break;
541 }
542
543 case ANDROID_WIFI_CMD_WFD_DISABLE:
544 {
545 // Commented by Albert 2012/07/24
546 // We can disable the WFD function by using the following command:
547 // wpa_cli driver wfd-disable
548
549 struct wifi_display_info *pwfd_info;
550 _adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
551
552 pwfd_info = &padapter->wfd_info;
553 if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
554 pwfd_info->wfd_enable = _FALSE;
555 break;
556 }
557 case ANDROID_WIFI_CMD_WFD_SET_TCPPORT:
558 {
559 // Commented by Albert 2012/07/24
560 // We can set the tcp port number by using the following command:
561 // wpa_cli driver wfd-set-tcpport = 554
562
563 struct wifi_display_info *pwfd_info;
564 _adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
565
566 pwfd_info = &padapter->wfd_info;
567 if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
568 pwfd_info->rtsp_ctrlport = ( u16 ) get_int_from_command( priv_cmd.buf );
569 break;
570 }
571 case ANDROID_WIFI_CMD_WFD_SET_MAX_TPUT:
572 {
573
574
575 break;
576 }
577 case ANDROID_WIFI_CMD_WFD_SET_DEVTYPE:
578 {
579 // Commented by Albert 2012/08/28
580 // Specify the WFD device type ( WFD source/primary sink )
581
582 struct wifi_display_info *pwfd_info;
583 _adapter* padapter = ( _adapter * ) rtw_netdev_priv(net);
584
585 pwfd_info = &padapter->wfd_info;
586 if( padapter->wdinfo.driver_interface == DRIVER_CFG80211 )
587 {
588 pwfd_info->wfd_device_type = ( u8 ) get_int_from_command( priv_cmd.buf );
589
590 pwfd_info->wfd_device_type &= WFD_DEVINFO_DUAL;
591 }
592 break;
593 }
594 #endif
595 default:
596 DBG_871X("Unknown PRIVATE command %s - ignored\n", command);
597 snprintf(command, 3, "OK");
598 bytes_written = strlen("OK");
599 }
600
601 response:
602 if (bytes_written >= 0) {
603 if ((bytes_written == 0) && (priv_cmd.total_len > 0))
604 command[0] = '\0';
605 if (bytes_written >= priv_cmd.total_len) {
606 DBG_871X("%s: bytes_written = %d\n", __FUNCTION__, bytes_written);
607 bytes_written = priv_cmd.total_len;
608 } else {
609 bytes_written++;
610 }
611 priv_cmd.used_len = bytes_written;
612 if (copy_to_user((void *)priv_cmd.buf, command, bytes_written)) {
613 DBG_871X("%s: failed to copy data to user buffer\n", __FUNCTION__);
614 ret = -EFAULT;
615 }
616 }
617 else {
618 ret = bytes_written;
619 }
620
621 exit:
622 rtw_unlock_suspend();
623 if (command) {
624 rtw_mfree(command, priv_cmd.total_len);
625 }
626
627 return ret;
628 }
629
630
631 /**
632 * Functions for Android WiFi card detection
633 */
634 #if defined(RTW_ENABLE_WIFI_CONTROL_FUNC)
635
636 static int g_wifidev_registered = 0;
637 static struct semaphore wifi_control_sem;
638 static struct wifi_platform_data *wifi_control_data = NULL;
639 static struct resource *wifi_irqres = NULL;
640
641 static int wifi_add_dev(void);
642 static void wifi_del_dev(void);
643
644 int rtw_android_wifictrl_func_add(void)
645 {
646 int ret = 0;
647 sema_init(&wifi_control_sem, 0);
648
649 ret = wifi_add_dev();
650 if (ret) {
651 DBG_871X("%s: platform_driver_register failed\n", __FUNCTION__);
652 return ret;
653 }
654 g_wifidev_registered = 1;
655
656 /* Waiting callback after platform_driver_register is done or exit with error */
657 if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) {
658 ret = -EINVAL;
659 DBG_871X("%s: platform_driver_register timeout\n", __FUNCTION__);
660 }
661
662 return ret;
663 }
664
665 void rtw_android_wifictrl_func_del(void)
666 {
667 if (g_wifidev_registered)
668 {
669 wifi_del_dev();
670 g_wifidev_registered = 0;
671 }
672 }
673
674 void *wl_android_prealloc(int section, unsigned long size)
675 {
676 void *alloc_ptr = NULL;
677 if (wifi_control_data && wifi_control_data->mem_prealloc) {
678 alloc_ptr = wifi_control_data->mem_prealloc(section, size);
679 if (alloc_ptr) {
680 DBG_871X("success alloc section %d\n", section);
681 if (size != 0L)
682 memset(alloc_ptr, 0, size);
683 return alloc_ptr;
684 }
685 }
686
687 DBG_871X("can't alloc section %d\n", section);
688 return NULL;
689 }
690
691 int wifi_get_irq_number(unsigned long *irq_flags_ptr)
692 {
693 if (wifi_irqres) {
694 *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
695 return (int)wifi_irqres->start;
696 }
697 #ifdef CUSTOM_OOB_GPIO_NUM
698 return CUSTOM_OOB_GPIO_NUM;
699 #else
700 return -1;
701 #endif
702 }
703
704 int wifi_set_power(int on, unsigned long msec)
705 {
706 DBG_871X("%s = %d\n", __FUNCTION__, on);
707 if (wifi_control_data && wifi_control_data->set_power) {
708 wifi_control_data->set_power(on);
709 }
710 if (msec)
711 msleep(msec);
712 return 0;
713 }
714
715 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
716 int wifi_get_mac_addr(unsigned char *buf)
717 {
718 DBG_871X("%s\n", __FUNCTION__);
719 if (!buf)
720 return -EINVAL;
721 if (wifi_control_data && wifi_control_data->get_mac_addr) {
722 return wifi_control_data->get_mac_addr(buf);
723 }
724 return -EOPNOTSUPP;
725 }
726 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
727
728 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) || defined(COMPAT_KERNEL_RELEASE)
729 void *wifi_get_country_code(char *ccode)
730 {
731 DBG_871X("%s\n", __FUNCTION__);
732 if (!ccode)
733 return NULL;
734 if (wifi_control_data && wifi_control_data->get_country_code) {
735 return wifi_control_data->get_country_code(ccode);
736 }
737 return NULL;
738 }
739 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
740
741 static int wifi_set_carddetect(int on)
742 {
743 DBG_871X("%s = %d\n", __FUNCTION__, on);
744 if (wifi_control_data && wifi_control_data->set_carddetect) {
745 wifi_control_data->set_carddetect(on);
746 }
747 return 0;
748 }
749
750 static int wifi_probe(struct platform_device *pdev)
751 {
752 struct wifi_platform_data *wifi_ctrl =
753 (struct wifi_platform_data *)(pdev->dev.platform_data);
754
755 DBG_871X("## %s\n", __FUNCTION__);
756 wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
757 if (wifi_irqres == NULL)
758 wifi_irqres = platform_get_resource_byname(pdev,
759 IORESOURCE_IRQ, "bcm4329_wlan_irq");
760 wifi_control_data = wifi_ctrl;
761
762 wifi_set_power(1, 0); /* Power On */
763 wifi_set_carddetect(1); /* CardDetect (0->1) */
764
765 up(&wifi_control_sem);
766 return 0;
767 }
768
769 static int wifi_remove(struct platform_device *pdev)
770 {
771 struct wifi_platform_data *wifi_ctrl =
772 (struct wifi_platform_data *)(pdev->dev.platform_data);
773
774 DBG_871X("## %s\n", __FUNCTION__);
775 wifi_control_data = wifi_ctrl;
776
777 wifi_set_power(0, 0); /* Power Off */
778 wifi_set_carddetect(0); /* CardDetect (1->0) */
779
780 up(&wifi_control_sem);
781 return 0;
782 }
783
784 static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
785 {
786 DBG_871X("##> %s\n", __FUNCTION__);
787 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
788 bcmsdh_oob_intr_set(0);
789 #endif
790 return 0;
791 }
792
793 static int wifi_resume(struct platform_device *pdev)
794 {
795 DBG_871X("##> %s\n", __FUNCTION__);
796 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
797 if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
798 bcmsdh_oob_intr_set(1);
799 #endif
800 return 0;
801 }
802
803 /* temporarily use these two */
804 static struct platform_driver wifi_device = {
805 .probe = wifi_probe,
806 .remove = wifi_remove,
807 .suspend = wifi_suspend,
808 .resume = wifi_resume,
809 .driver = {
810 .name = "bcmdhd_wlan",
811 }
812 };
813
814 static struct platform_driver wifi_device_legacy = {
815 .probe = wifi_probe,
816 .remove = wifi_remove,
817 .suspend = wifi_suspend,
818 .resume = wifi_resume,
819 .driver = {
820 .name = "bcm4329_wlan",
821 }
822 };
823
824 static int wifi_add_dev(void)
825 {
826 DBG_871X("## Calling platform_driver_register\n");
827 platform_driver_register(&wifi_device);
828 platform_driver_register(&wifi_device_legacy);
829 return 0;
830 }
831
832 static void wifi_del_dev(void)
833 {
834 DBG_871X("## Unregister platform_driver_register\n");
835 platform_driver_unregister(&wifi_device);
836 platform_driver_unregister(&wifi_device_legacy);
837 }
838 #endif /* defined(RTW_ENABLE_WIFI_CONTROL_FUNC) */