rk: temp revert rk change
[firefly-linux-kernel-4.4.55.git] / drivers / net / wireless / bcmdhd / wl_android.c
1 /*
2  * Linux cfg80211 driver - Android related functions
3  *
4  * Copyright (C) 1999-2011, Broadcom Corporation
5  * 
6  *         Unless you and Broadcom execute a separate written software license
7  * agreement governing use of this software, this software is licensed to you
8  * under the terms of the GNU General Public License version 2 (the "GPL"),
9  * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10  * following added to such license:
11  * 
12  *      As a special exception, the copyright holders of this software give you
13  * permission to link this software with independent modules, and to copy and
14  * distribute the resulting executable under terms of your choice, provided that
15  * you also meet, for each linked independent module, the terms and conditions of
16  * the license of that module.  An independent module is a module which is not
17  * derived from this software.  The special exception does not apply to any
18  * modifications of the software.
19  * 
20  *      Notwithstanding the above, under no circumstances may you combine this
21  * software in any way with any other Broadcom software provided under a license
22  * other than the GPL, without Broadcom's express prior written consent.
23  *
24  * $Id: wl_android.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $
25  */
26
27 #include <linux/module.h>
28 #include <linux/netdevice.h>
29
30 #include <wl_android.h>
31 #include <wldev_common.h>
32 #include <wlioctl.h>
33 #include <bcmutils.h>
34 #include <linux_osl.h>
35 #include <dhd_dbg.h>
36 #include <dngl_stats.h>
37 #include <dhd.h>
38 #include <bcmsdbus.h>
39 #ifdef WL_CFG80211
40 #include <wl_cfg80211.h>
41 #endif
42 #if defined(CONFIG_WIFI_CONTROL_FUNC)
43 #include <linux/platform_device.h>
44 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
45 #include <linux/wlan_plat.h>
46 #else
47 #include <linux/wifi_tiwlan.h>
48 #endif
49 #endif /* CONFIG_WIFI_CONTROL_FUNC */
50
51 /*
52  * Android private command strings, PLEASE define new private commands here
53  * so they can be updated easily in the future (if needed)
54  */
55
56 #define CMD_START                               "START"
57 #define CMD_STOP                                "STOP"
58 #define CMD_SCAN_ACTIVE                 "SCAN-ACTIVE"
59 #define CMD_SCAN_PASSIVE                "SCAN-PASSIVE"
60 #define CMD_RSSI                                "RSSI"
61 #define CMD_LINKSPEED                   "LINKSPEED"
62 #define CMD_RXFILTER_START              "RXFILTER-START"
63 #define CMD_RXFILTER_STOP               "RXFILTER-STOP"
64 #define CMD_RXFILTER_ADD                "RXFILTER-ADD"
65 #define CMD_RXFILTER_REMOVE             "RXFILTER-REMOVE"
66 #define CMD_BTCOEXSCAN_START    "BTCOEXSCAN-START"
67 #define CMD_BTCOEXSCAN_STOP             "BTCOEXSCAN-STOP"
68 #define CMD_BTCOEXMODE                  "BTCOEXMODE"
69 #define CMD_SETSUSPENDOPT               "SETSUSPENDOPT"
70 #define CMD_SETSUSPENDMODE              "SETSUSPENDMODE"
71 #define CMD_P2P_DEV_ADDR                "P2P_DEV_ADDR"
72 #define CMD_SETFWPATH                   "SETFWPATH"
73 #define CMD_SETBAND                             "SETBAND"
74 #define CMD_GETBAND                             "GETBAND"
75 #define CMD_COUNTRY                             "COUNTRY"
76 #define CMD_P2P_SET_NOA                 "P2P_SET_NOA"
77 #if !defined WL_ENABLE_P2P_IF
78 #define CMD_P2P_GET_NOA                 "P2P_GET_NOA"
79 #endif
80 #define CMD_P2P_SET_PS                  "P2P_SET_PS"
81 #define CMD_SET_AP_WPS_P2P_IE   "SET_AP_WPS_P2P_IE"
82
83
84 #ifdef PNO_SUPPORT
85 #define CMD_PNOSSIDCLR_SET      "PNOSSIDCLR"
86 #define CMD_PNOSETUP_SET        "PNOSETUP "
87 #define CMD_PNOENABLE_SET       "PNOFORCE"
88 #define CMD_PNODEBUG_SET        "PNODEBUG"
89
90 #define PNO_TLV_PREFIX                  'S'
91 #define PNO_TLV_VERSION                 '1'
92 #define PNO_TLV_SUBVERSION              '2'
93 #define PNO_TLV_RESERVED                '0'
94 #define PNO_TLV_TYPE_SSID_IE            'S'
95 #define PNO_TLV_TYPE_TIME               'T'
96 #define PNO_TLV_FREQ_REPEAT             'R'
97 #define PNO_TLV_FREQ_EXPO_MAX           'M'
98
99 typedef struct cmd_tlv {
100         char prefix;
101         char version;
102         char subver;
103         char reserved;
104 } cmd_tlv_t;
105 #endif /* PNO_SUPPORT */
106
107 typedef struct android_wifi_priv_cmd {
108         char *buf;
109         int used_len;
110         int total_len;
111 } android_wifi_priv_cmd;
112
113 /**
114  * Extern function declarations (TODO: move them to dhd_linux.h)
115  */
116 void dhd_customer_gpio_wlan_ctrl(int onoff);
117 uint dhd_dev_reset(struct net_device *dev, uint8 flag);
118 int dhd_dev_init_ioctl(struct net_device *dev);
119 #ifdef WL_CFG80211
120 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr);
121 int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command);
122 #else
123 int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr)
124 { return 0; }
125 int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len)
126 { return 0; }
127 int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len)
128 { return 0; }
129 int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len)
130 { return 0; }
131 #endif
132 extern int dhd_os_check_if_up(void *dhdp);
133 extern void *bcmsdh_get_drvdata(void);
134
135 extern bool ap_fw_loaded;
136 #ifdef CUSTOMER_HW2
137 extern char iface_name[IFNAMSIZ];
138 #endif
139
140 /**
141  * Local (static) functions and variables
142  */
143
144 /* Initialize g_wifi_on to 1 so dhd_bus_start will be called for the first
145  * time (only) in dhd_open, subsequential wifi on will be handled by
146  * wl_android_wifi_on
147  */
148 static int g_wifi_on = TRUE;
149
150 /**
151  * Local (static) function definitions
152  */
153 static int wl_android_get_link_speed(struct net_device *net, char *command, int total_len)
154 {
155         int link_speed;
156         int bytes_written;
157         int error;
158
159         error = wldev_get_link_speed(net, &link_speed);
160         if (error)
161                 return -1;
162
163         /* Convert Kbps to Android Mbps */
164         link_speed = link_speed / 1000;
165         bytes_written = snprintf(command, total_len, "LinkSpeed %d", link_speed);
166         DHD_INFO(("%s: command result is %s\n", __FUNCTION__, command));
167         return bytes_written;
168 }
169
170 static int wl_android_get_rssi(struct net_device *net, char *command, int total_len)
171 {
172         wlc_ssid_t ssid = {0};
173         int rssi;
174         int bytes_written = 0;
175         int error;
176
177         error = wldev_get_rssi(net, &rssi);
178         if (error)
179                 return -1;
180
181         error = wldev_get_ssid(net, &ssid);
182         if (error)
183                 return -1;
184         if ((ssid.SSID_len == 0) || (ssid.SSID_len > DOT11_MAX_SSID_LEN)) {
185                 DHD_ERROR(("%s: wldev_get_ssid failed\n", __FUNCTION__));
186         } else {
187                 memcpy(command, ssid.SSID, ssid.SSID_len);
188                 bytes_written = ssid.SSID_len;
189         }
190         bytes_written += snprintf(&command[bytes_written], total_len, " rssi %d", rssi);
191         DHD_INFO(("%s: command result is %s (%d)\n", __FUNCTION__, command, bytes_written));
192         return bytes_written;
193 }
194
195 static int wl_android_set_suspendopt(struct net_device *dev, char *command, int total_len)
196 {
197         int suspend_flag;
198         int ret_now;
199         int ret = 0;
200
201         suspend_flag = *(command + strlen(CMD_SETSUSPENDOPT) + 1) - '0';
202
203         if (suspend_flag != 0)
204                 suspend_flag = 1;
205         ret_now = net_os_set_suspend_disable(dev, suspend_flag);
206
207         if (ret_now != suspend_flag) {
208                 if (!(ret = net_os_set_suspend(dev, ret_now, 1)))
209                         DHD_INFO(("%s: Suspend Flag %d -> %d\n",
210                                 __FUNCTION__, ret_now, suspend_flag));
211                 else
212                         DHD_ERROR(("%s: failed %d\n", __FUNCTION__, ret));
213         }
214         return ret;
215 }
216
217 static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len)
218 {
219         int ret = 0;
220
221 #if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND)
222         int suspend_flag;
223
224         suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0';
225
226         if (suspend_flag != 0)
227                 suspend_flag = 1;
228
229         if (!(ret = net_os_set_suspend(dev, suspend_flag, 0)))
230                 DHD_INFO(("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag));
231         else
232                 DHD_ERROR(("%s: failed %d\n",__FUNCTION__,ret));
233 #endif
234         return ret;
235 }
236
237 static int wl_android_get_band(struct net_device *dev, char *command, int total_len)
238 {
239         uint band;
240         int bytes_written;
241         int error;
242
243         error = wldev_get_band(dev, &band);
244         if (error)
245                 return -1;
246         bytes_written = snprintf(command, total_len, "Band %d", band);
247         return bytes_written;
248 }
249
250 #if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN)
251 static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len)
252 {
253         wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT];
254         int res = -1;
255         int nssid = 0;
256         cmd_tlv_t *cmd_tlv_temp;
257         char *str_ptr;
258         int tlv_size_left;
259         int pno_time = 0;
260         int pno_repeat = 0;
261         int pno_freq_expo_max = 0;
262
263 #ifdef PNO_SET_DEBUG
264         int i;
265         char pno_in_example[] = {
266                 'P', 'N', 'O', 'S', 'E', 'T', 'U', 'P', ' ',
267                 'S', '1', '2', '0',
268                 'S',
269                 0x05,
270                 'd', 'l', 'i', 'n', 'k',
271                 'S',
272                 0x04,
273                 'G', 'O', 'O', 'G',
274                 'T',
275                 '0', 'B',
276                 'R',
277                 '2',
278                 'M',
279                 '2',
280                 0x00
281                 };
282 #endif /* PNO_SET_DEBUG */
283
284         DHD_INFO(("%s: command=%s, len=%d\n", __FUNCTION__, command, total_len));
285
286         if (total_len < (strlen(CMD_PNOSETUP_SET) + sizeof(cmd_tlv_t))) {
287                 DHD_ERROR(("%s argument=%d less min size\n", __FUNCTION__, total_len));
288                 goto exit_proc;
289         }
290
291 #ifdef PNO_SET_DEBUG
292         memcpy(command, pno_in_example, sizeof(pno_in_example));
293         for (i = 0; i < sizeof(pno_in_example); i++)
294                 printf("%02X ", command[i]);
295         printf("\n");
296         total_len = sizeof(pno_in_example);
297 #endif
298
299         str_ptr = command + strlen(CMD_PNOSETUP_SET);
300         tlv_size_left = total_len - strlen(CMD_PNOSETUP_SET);
301
302         cmd_tlv_temp = (cmd_tlv_t *)str_ptr;
303         memset(ssids_local, 0, sizeof(ssids_local));
304
305         if ((cmd_tlv_temp->prefix == PNO_TLV_PREFIX) &&
306                 (cmd_tlv_temp->version == PNO_TLV_VERSION) &&
307                 (cmd_tlv_temp->subver == PNO_TLV_SUBVERSION)) {
308
309                 str_ptr += sizeof(cmd_tlv_t);
310                 tlv_size_left -= sizeof(cmd_tlv_t);
311
312                 if ((nssid = wl_iw_parse_ssid_list_tlv(&str_ptr, ssids_local,
313                         MAX_PFN_LIST_COUNT, &tlv_size_left)) <= 0) {
314                         DHD_ERROR(("SSID is not presented or corrupted ret=%d\n", nssid));
315                         goto exit_proc;
316                 } else {
317                         if ((str_ptr[0] != PNO_TLV_TYPE_TIME) || (tlv_size_left <= 1)) {
318                                 DHD_ERROR(("%s scan duration corrupted field size %d\n",
319                                         __FUNCTION__, tlv_size_left));
320                                 goto exit_proc;
321                         }
322                         str_ptr++;
323                         pno_time = simple_strtoul(str_ptr, &str_ptr, 16);
324                         DHD_INFO(("%s: pno_time=%d\n", __FUNCTION__, pno_time));
325
326                         if (str_ptr[0] != 0) {
327                                 if ((str_ptr[0] != PNO_TLV_FREQ_REPEAT)) {
328                                         DHD_ERROR(("%s pno repeat : corrupted field\n",
329                                                 __FUNCTION__));
330                                         goto exit_proc;
331                                 }
332                                 str_ptr++;
333                                 pno_repeat = simple_strtoul(str_ptr, &str_ptr, 16);
334                                 DHD_INFO(("%s :got pno_repeat=%d\n", __FUNCTION__, pno_repeat));
335                                 if (str_ptr[0] != PNO_TLV_FREQ_EXPO_MAX) {
336                                         DHD_ERROR(("%s FREQ_EXPO_MAX corrupted field size\n",
337                                                 __FUNCTION__));
338                                         goto exit_proc;
339                                 }
340                                 str_ptr++;
341                                 pno_freq_expo_max = simple_strtoul(str_ptr, &str_ptr, 16);
342                                 DHD_INFO(("%s: pno_freq_expo_max=%d\n",
343                                         __FUNCTION__, pno_freq_expo_max));
344                         }
345                 }
346         } else {
347                 DHD_ERROR(("%s get wrong TLV command\n", __FUNCTION__));
348                 goto exit_proc;
349         }
350
351         res = dhd_dev_pno_set(dev, ssids_local, nssid, pno_time, pno_repeat, pno_freq_expo_max);
352
353 exit_proc:
354         return res;
355 }
356 #endif /* PNO_SUPPORT && !WL_SCHED_SCAN */
357
358 static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len)
359 {
360         int ret;
361         int bytes_written = 0;
362
363         ret = wl_cfg80211_get_p2p_dev_addr(ndev, (struct ether_addr*)command);
364         if (ret)
365                 return 0;
366         bytes_written = sizeof(struct ether_addr);
367         return bytes_written;
368 }
369
370 /**
371  * Global function definitions (declared in wl_android.h)
372  */
373
374 int wl_android_wifi_on(struct net_device *dev)
375 {
376         int ret = 0;
377
378         printk("%s in\n", __FUNCTION__);
379         if (!dev) {
380                 DHD_ERROR(("%s: dev is null\n", __FUNCTION__));
381                 return -EINVAL;
382         }
383
384         dhd_net_if_lock(dev);
385         if (!g_wifi_on) {
386                 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON);
387                 sdioh_start(NULL, 0);
388                 ret = dhd_dev_reset(dev, FALSE);
389                 sdioh_start(NULL, 1);
390                 if (!ret) {
391                         if (dhd_dev_init_ioctl(dev) < 0)
392                                 ret = -EFAULT;
393                 }
394                 g_wifi_on = 1;
395         }
396         dhd_net_if_unlock(dev);
397
398         return ret;
399 }
400
401 int wl_android_wifi_off(struct net_device *dev)
402 {
403         int ret = 0;
404
405         printk("%s in\n", __FUNCTION__);
406         if (!dev) {
407                 DHD_TRACE(("%s: dev is null\n", __FUNCTION__));
408                 return -EINVAL;
409         }
410
411         dhd_net_if_lock(dev);
412         if (g_wifi_on) {
413                 ret = dhd_dev_reset(dev, TRUE);
414                 sdioh_stop(NULL);
415                 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
416                 g_wifi_on = 0;
417         }
418         dhd_net_if_unlock(dev);
419
420         return ret;
421 }
422
423 static int wl_android_set_fwpath(struct net_device *net, char *command, int total_len)
424 {
425         if ((strlen(command) - strlen(CMD_SETFWPATH)) > MOD_PARAM_PATHLEN)
426                 return -1;
427         bcm_strncpy_s(fw_path, sizeof(fw_path),
428                 command + strlen(CMD_SETFWPATH) + 1, MOD_PARAM_PATHLEN - 1);
429         if (strstr(fw_path, "apsta") != NULL) {
430                 DHD_INFO(("GOT APSTA FIRMWARE\n"));
431                 ap_fw_loaded = TRUE;
432         } else {
433                 DHD_INFO(("GOT STA FIRMWARE\n"));
434                 ap_fw_loaded = FALSE;
435         }
436         return 0;
437 }
438
439 int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd)
440 {
441         int ret = 0;
442         char *command = NULL;
443         int bytes_written = 0;
444         android_wifi_priv_cmd priv_cmd;
445
446         net_os_wake_lock(net);
447
448         if (!ifr->ifr_data) {
449                 ret = -EINVAL;
450                 goto exit;
451         }
452         if (copy_from_user(&priv_cmd, ifr->ifr_data, sizeof(android_wifi_priv_cmd))) {
453                 ret = -EFAULT;
454                 goto exit;
455         }
456         command = kmalloc(priv_cmd.total_len, GFP_KERNEL);
457         if (!command)
458         {
459                 DHD_ERROR(("%s: failed to allocate memory\n", __FUNCTION__));
460                 ret = -ENOMEM;
461                 goto exit;
462         }
463         if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
464                 ret = -EFAULT;
465                 goto exit;
466         }
467
468         DHD_INFO(("%s: Android private cmd \"%s\" on %s\n", __FUNCTION__, command, ifr->ifr_name));
469
470         if (strnicmp(command, CMD_START, strlen(CMD_START)) == 0) {
471                 DHD_INFO(("%s, Received regular START command\n", __FUNCTION__));
472                 bytes_written = wl_android_wifi_on(net);
473         }
474         else if (strnicmp(command, CMD_SETFWPATH, strlen(CMD_SETFWPATH)) == 0) {
475                 bytes_written = wl_android_set_fwpath(net, command, priv_cmd.total_len);
476         }
477
478         if (!g_wifi_on) {
479                 DHD_ERROR(("%s: Ignore private cmd \"%s\" - iface %s is down\n",
480                         __FUNCTION__, command, ifr->ifr_name));
481                 ret = 0;
482                 goto exit;
483         }
484
485         if (strnicmp(command, CMD_STOP, strlen(CMD_STOP)) == 0) {
486                 bytes_written = wl_android_wifi_off(net);
487         }
488         else if (strnicmp(command, CMD_SCAN_ACTIVE, strlen(CMD_SCAN_ACTIVE)) == 0) {
489                 /* TBD: SCAN-ACTIVE */
490         }
491         else if (strnicmp(command, CMD_SCAN_PASSIVE, strlen(CMD_SCAN_PASSIVE)) == 0) {
492                 /* TBD: SCAN-PASSIVE */
493         }
494         else if (strnicmp(command, CMD_RSSI, strlen(CMD_RSSI)) == 0) {
495                 bytes_written = wl_android_get_rssi(net, command, priv_cmd.total_len);
496         }
497         else if (strnicmp(command, CMD_LINKSPEED, strlen(CMD_LINKSPEED)) == 0) {
498                 bytes_written = wl_android_get_link_speed(net, command, priv_cmd.total_len);
499         }
500         else if (strnicmp(command, CMD_RXFILTER_START, strlen(CMD_RXFILTER_START)) == 0) {
501                 bytes_written = net_os_set_packet_filter(net, 1);
502         }
503         else if (strnicmp(command, CMD_RXFILTER_STOP, strlen(CMD_RXFILTER_STOP)) == 0) {
504                 bytes_written = net_os_set_packet_filter(net, 0);
505         }
506         else if (strnicmp(command, CMD_RXFILTER_ADD, strlen(CMD_RXFILTER_ADD)) == 0) {
507                 int filter_num = *(command + strlen(CMD_RXFILTER_ADD) + 1) - '0';
508                 bytes_written = net_os_rxfilter_add_remove(net, TRUE, filter_num);
509         }
510         else if (strnicmp(command, CMD_RXFILTER_REMOVE, strlen(CMD_RXFILTER_REMOVE)) == 0) {
511                 int filter_num = *(command + strlen(CMD_RXFILTER_REMOVE) + 1) - '0';
512                 bytes_written = net_os_rxfilter_add_remove(net, FALSE, filter_num);
513         }
514         else if (strnicmp(command, CMD_BTCOEXSCAN_START, strlen(CMD_BTCOEXSCAN_START)) == 0) {
515                 /* TBD: BTCOEXSCAN-START */
516         }
517         else if (strnicmp(command, CMD_BTCOEXSCAN_STOP, strlen(CMD_BTCOEXSCAN_STOP)) == 0) {
518                 /* TBD: BTCOEXSCAN-STOP */
519         }
520         else if (strnicmp(command, CMD_BTCOEXMODE, strlen(CMD_BTCOEXMODE)) == 0) {
521                 uint mode = *(command + strlen(CMD_BTCOEXMODE) + 1) - '0';
522
523                 if (mode == 1)
524                         net_os_set_packet_filter(net, 0); /* DHCP starts */
525                 else
526                         net_os_set_packet_filter(net, 1); /* DHCP ends */
527 #ifdef WL_CFG80211
528                 bytes_written = wl_cfg80211_set_btcoex_dhcp(net, command);
529 #endif
530         }
531         else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) {
532                 bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len);
533         }
534         else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) {
535                 bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len);
536         }
537         else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) {
538                 uint band = *(command + strlen(CMD_SETBAND) + 1) - '0';
539                 bytes_written = wldev_set_band(net, band);
540         }
541         else if (strnicmp(command, CMD_GETBAND, strlen(CMD_GETBAND)) == 0) {
542                 bytes_written = wl_android_get_band(net, command, priv_cmd.total_len);
543         }
544         else if (strnicmp(command, CMD_COUNTRY, strlen(CMD_COUNTRY)) == 0) {
545                 char *country_code = command + strlen(CMD_COUNTRY) + 1;
546                 bytes_written = wldev_set_country(net, country_code);
547         }
548 #if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN)
549         else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) {
550                 bytes_written = dhd_dev_pno_reset(net);
551         }
552         else if (strnicmp(command, CMD_PNOSETUP_SET, strlen(CMD_PNOSETUP_SET)) == 0) {
553                 bytes_written = wl_android_set_pno_setup(net, command, priv_cmd.total_len);
554         }
555         else if (strnicmp(command, CMD_PNOENABLE_SET, strlen(CMD_PNOENABLE_SET)) == 0) {
556                 uint pfn_enabled = *(command + strlen(CMD_PNOENABLE_SET) + 1) - '0';
557                 bytes_written = dhd_dev_pno_enable(net, pfn_enabled);
558         }
559 #endif
560         else if (strnicmp(command, CMD_P2P_DEV_ADDR, strlen(CMD_P2P_DEV_ADDR)) == 0) {
561                 bytes_written = wl_android_get_p2p_dev_addr(net, command, priv_cmd.total_len);
562         }
563         else if (strnicmp(command, CMD_P2P_SET_NOA, strlen(CMD_P2P_SET_NOA)) == 0) {
564                 int skip = strlen(CMD_P2P_SET_NOA) + 1;
565                 bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip,
566                         priv_cmd.total_len - skip);
567         }
568 #if !defined WL_ENABLE_P2P_IF
569         else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) {
570                 bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len);
571         }
572 #endif
573         else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) {
574                 int skip = strlen(CMD_P2P_SET_PS) + 1;
575                 bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip,
576                         priv_cmd.total_len - skip);
577         }
578 #ifdef WL_CFG80211
579         else if (strnicmp(command, CMD_SET_AP_WPS_P2P_IE,
580                 strlen(CMD_SET_AP_WPS_P2P_IE)) == 0) {
581                 int skip = strlen(CMD_SET_AP_WPS_P2P_IE) + 3;
582                 bytes_written = wl_cfg80211_set_wps_p2p_ie(net, command + skip,
583                         priv_cmd.total_len - skip, *(command + skip - 2) - '0');
584         }
585 #endif /* WL_CFG80211 */
586         else {
587                 DHD_ERROR(("Unknown PRIVATE command %s - ignored\n", command));
588                 snprintf(command, 3, "OK");
589                 bytes_written = strlen("OK");
590         }
591
592         if (bytes_written >= 0) {
593                 if ((bytes_written == 0) && (priv_cmd.total_len > 0))
594                         command[0] = '\0';
595                 if (bytes_written >= priv_cmd.total_len) {
596                         DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written));
597                         bytes_written = priv_cmd.total_len;
598                 } else {
599                         bytes_written++;
600                 }
601                 priv_cmd.used_len = bytes_written;
602                 if (copy_to_user(priv_cmd.buf, command, bytes_written)) {
603                         DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__));
604                         ret = -EFAULT;
605                 }
606         }
607         else {
608                 ret = bytes_written;
609         }
610
611 exit:
612         net_os_wake_unlock(net);
613         if (command) {
614                 kfree(command);
615         }
616
617         return ret;
618 }
619
620 int wl_android_init(void)
621 {
622         int ret = 0;
623
624         dhd_msg_level |= DHD_ERROR_VAL;
625 #ifdef ENABLE_INSMOD_NO_FW_LOAD
626         dhd_download_fw_on_driverload = FALSE;
627 #endif /* ENABLE_INSMOD_NO_FW_LOAD */
628 #ifdef CUSTOMER_HW2
629         if (!iface_name[0]) {
630                 memset(iface_name, 0, IFNAMSIZ);
631                 bcm_strncpy_s(iface_name, IFNAMSIZ, "wlan", IFNAMSIZ);
632         }
633 #endif /* CUSTOMER_HW2 */
634         return ret;
635 }
636
637 int wl_android_exit(void)
638 {
639         int ret = 0;
640
641         return ret;
642 }
643
644 void wl_android_post_init(void)
645 {
646         if (!dhd_download_fw_on_driverload) {
647                 /* Call customer gpio to turn off power with WL_REG_ON signal */
648                 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF);
649                 g_wifi_on = 0;
650         }
651 }
652 /**
653  * Functions for Android WiFi card detection
654  */
655 #if defined(CONFIG_WIFI_CONTROL_FUNC)
656
657 static int g_wifidev_registered = 0;
658 static struct semaphore wifi_control_sem;
659 static struct wifi_platform_data *wifi_control_data = NULL;
660 static struct resource *wifi_irqres = NULL;
661
662 static int wifi_add_dev(void);
663 static void wifi_del_dev(void);
664
665 int wl_android_wifictrl_func_add(void)
666 {
667         int ret = 0;
668         sema_init(&wifi_control_sem, 0);
669
670         ret = wifi_add_dev();
671         if (ret) {
672                 DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__));
673                 return ret;
674         }
675         g_wifidev_registered = 1;
676
677         /* Waiting callback after platform_driver_register is done or exit with error */
678         if (down_timeout(&wifi_control_sem,  msecs_to_jiffies(1000)) != 0) {
679                 ret = -EINVAL;
680                 DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__));
681         }
682
683         return ret;
684 }
685
686 void wl_android_wifictrl_func_del(void)
687 {
688         if (g_wifidev_registered)
689         {
690                 wifi_del_dev();
691                 g_wifidev_registered = 0;
692         }
693 }
694
695 void* wl_android_prealloc(int section, unsigned long size)
696 {
697         void *alloc_ptr = NULL;
698         if (wifi_control_data && wifi_control_data->mem_prealloc) {
699                 alloc_ptr = wifi_control_data->mem_prealloc(section, size);
700                 if (alloc_ptr) {
701                         DHD_INFO(("success alloc section %d\n", section));
702                         if (size != 0L)
703                                 bzero(alloc_ptr, size);
704                         return alloc_ptr;
705                 }
706         }
707
708         DHD_ERROR(("can't alloc section %d\n", section));
709         return NULL;
710 }
711
712 int wifi_get_irq_number(unsigned long *irq_flags_ptr)
713 {
714         if (wifi_irqres) {
715                 *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK;
716                 return (int)wifi_irqres->start;
717         }
718 #ifdef CUSTOM_OOB_GPIO_NUM
719         return CUSTOM_OOB_GPIO_NUM;
720 #else
721         return -1;
722 #endif
723 }
724
725 int wifi_set_power(int on, unsigned long msec)
726 {
727         DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
728         if (wifi_control_data && wifi_control_data->set_power) {
729                 wifi_control_data->set_power(on);
730         }
731         if (msec)
732                 msleep(msec);
733         return 0;
734 }
735
736 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35))
737 int wifi_get_mac_addr(unsigned char *buf)
738 {
739         DHD_TRACE(("%s\n", __FUNCTION__));
740         if (!buf)
741                 return -EINVAL;
742         if (wifi_control_data && wifi_control_data->get_mac_addr) {
743                 return wifi_control_data->get_mac_addr(buf);
744         }
745         return -EOPNOTSUPP;
746 }
747 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */
748
749 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39))
750 void *wifi_get_country_code(char *ccode)
751 {
752         DHD_TRACE(("%s\n", __FUNCTION__));
753         if (!ccode)
754                 return NULL;
755         if (wifi_control_data && wifi_control_data->get_country_code) {
756                 return wifi_control_data->get_country_code(ccode);
757         }
758         return NULL;
759 }
760 #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */
761
762 static int wifi_set_carddetect(int on)
763 {
764         DHD_ERROR(("%s = %d\n", __FUNCTION__, on));
765         if (wifi_control_data && wifi_control_data->set_carddetect) {
766                 wifi_control_data->set_carddetect(on);
767         }
768         return 0;
769 }
770
771 static int wifi_probe(struct platform_device *pdev)
772 {
773         struct wifi_platform_data *wifi_ctrl =
774                 (struct wifi_platform_data *)(pdev->dev.platform_data);
775
776         DHD_ERROR(("## %s\n", __FUNCTION__));
777         wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq");
778         if (wifi_irqres == NULL)
779                 wifi_irqres = platform_get_resource_byname(pdev,
780                         IORESOURCE_IRQ, "bcm4329_wlan_irq");
781         wifi_control_data = wifi_ctrl;
782
783         wifi_set_power(1, 0);   /* Power On */
784         wifi_set_carddetect(1); /* CardDetect (0->1) */
785
786         up(&wifi_control_sem);
787         return 0;
788 }
789
790 static int wifi_remove(struct platform_device *pdev)
791 {
792         struct wifi_platform_data *wifi_ctrl =
793                 (struct wifi_platform_data *)(pdev->dev.platform_data);
794
795         DHD_ERROR(("## %s\n", __FUNCTION__));
796         wifi_control_data = wifi_ctrl;
797
798         wifi_set_power(0, 0);   /* Power Off */
799         wifi_set_carddetect(0); /* CardDetect (1->0) */
800
801         up(&wifi_control_sem);
802         return 0;
803 }
804
805 static int wifi_suspend(struct platform_device *pdev, pm_message_t state)
806 {
807         DHD_TRACE(("##> %s\n", __FUNCTION__));
808 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
809         bcmsdh_oob_intr_set(0);
810 #endif
811         return 0;
812 }
813
814 static int wifi_resume(struct platform_device *pdev)
815 {
816         DHD_TRACE(("##> %s\n", __FUNCTION__));
817 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY)
818         if (dhd_os_check_if_up(bcmsdh_get_drvdata()))
819                 bcmsdh_oob_intr_set(1);
820 #endif
821         return 0;
822 }
823
824 static struct platform_driver wifi_device = {
825         .probe          = wifi_probe,
826         .remove         = wifi_remove,
827         .suspend        = wifi_suspend,
828         .resume         = wifi_resume,
829         .driver         = {
830         .name   = "bcmdhd_wlan",
831         }
832 };
833
834 static struct platform_driver wifi_device_legacy = {
835         .probe          = wifi_probe,
836         .remove         = wifi_remove,
837         .suspend        = wifi_suspend,
838         .resume         = wifi_resume,
839         .driver         = {
840         .name   = "bcm4329_wlan",
841         }
842 };
843
844 static int wifi_add_dev(void)
845 {
846         DHD_TRACE(("## Calling platform_driver_register\n"));
847         platform_driver_register(&wifi_device);
848         platform_driver_register(&wifi_device_legacy);
849         return 0;
850 }
851
852 static void wifi_del_dev(void)
853 {
854         DHD_TRACE(("## Unregister platform_driver_register\n"));
855         platform_driver_unregister(&wifi_device);
856         platform_driver_unregister(&wifi_device_legacy);
857 }
858 #endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */