/drivers/net/wireless/bcmdhd/wl_android.c
C | 861 lines | 707 code | 99 blank | 55 comment | 172 complexity | 6e068bd2f9d6680b86fad53c796668aa MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, GPL-2.0
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 99typedef struct cmd_tlv { 100 char prefix; 101 char version; 102 char subver; 103 char reserved; 104} cmd_tlv_t; 105#endif /* PNO_SUPPORT */ 106 107typedef 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 */ 116void dhd_customer_gpio_wlan_ctrl(int onoff); 117uint dhd_dev_reset(struct net_device *dev, uint8 flag); 118int dhd_dev_init_ioctl(struct net_device *dev); 119#ifdef WL_CFG80211 120int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); 121int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command); 122#else 123int wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) 124{ return 0; } 125int wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) 126{ return 0; } 127int wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len) 128{ return 0; } 129int wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len) 130{ return 0; } 131#endif 132extern int dhd_os_check_if_up(void *dhdp); 133extern void *bcmsdh_get_drvdata(void); 134 135extern bool ap_fw_loaded; 136#ifdef CUSTOMER_HW2 137extern 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 */ 148static int g_wifi_on = TRUE; 149 150/** 151 * Local (static) function definitions 152 */ 153static 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 170static 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 195static 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 217static 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 237static 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) 251static 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 353exit_proc: 354 return res; 355} 356#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ 357 358static 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 374int wl_android_wifi_on(struct net_device *dev) 375{ 376 int ret = 0; 377 378 printf("%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 401int wl_android_wifi_off(struct net_device *dev) 402{ 403 int ret = 0; 404 405 printf("%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 423static 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 439int 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 611exit: 612 net_os_wake_unlock(net); 613 if (command) { 614 kfree(command); 615 } 616 617 return ret; 618} 619 620int 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 637int wl_android_exit(void) 638{ 639 int ret = 0; 640 641 return ret; 642} 643 644void 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#if !defined(OOB_INTR_ONLY) 649 sdioh_stop(NULL); 650#endif /* !defined(OOB_INTR_ONLY) */ 651 dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); 652 g_wifi_on = 0; 653 } 654} 655/** 656 * Functions for Android WiFi card detection 657 */ 658#if defined(CONFIG_WIFI_CONTROL_FUNC) 659 660static int g_wifidev_registered = 0; 661static struct semaphore wifi_control_sem; 662static struct wifi_platform_data *wifi_control_data = NULL; 663static struct resource *wifi_irqres = NULL; 664 665static int wifi_add_dev(void); 666static void wifi_del_dev(void); 667 668int wl_android_wifictrl_func_add(void) 669{ 670 int ret = 0; 671 sema_init(&wifi_control_sem, 0); 672 673 ret = wifi_add_dev(); 674 if (ret) { 675 DHD_ERROR(("%s: platform_driver_register failed\n", __FUNCTION__)); 676 return ret; 677 } 678 g_wifidev_registered = 1; 679 680 /* Waiting callback after platform_driver_register is done or exit with error */ 681 if (down_timeout(&wifi_control_sem, msecs_to_jiffies(1000)) != 0) { 682 ret = -EINVAL; 683 DHD_ERROR(("%s: platform_driver_register timeout\n", __FUNCTION__)); 684 } 685 686 return ret; 687} 688 689void wl_android_wifictrl_func_del(void) 690{ 691 if (g_wifidev_registered) 692 { 693 wifi_del_dev(); 694 g_wifidev_registered = 0; 695 } 696} 697 698void* wl_android_prealloc(int section, unsigned long size) 699{ 700 void *alloc_ptr = NULL; 701 if (wifi_control_data && wifi_control_data->mem_prealloc) { 702 alloc_ptr = wifi_control_data->mem_prealloc(section, size); 703 if (alloc_ptr) { 704 DHD_INFO(("success alloc section %d\n", section)); 705 if (size != 0L) 706 bzero(alloc_ptr, size); 707 return alloc_ptr; 708 } 709 } 710 711 DHD_ERROR(("can't alloc section %d\n", section)); 712 return NULL; 713} 714 715int wifi_get_irq_number(unsigned long *irq_flags_ptr) 716{ 717 if (wifi_irqres) { 718 *irq_flags_ptr = wifi_irqres->flags & IRQF_TRIGGER_MASK; 719 return (int)wifi_irqres->start; 720 } 721#ifdef CUSTOM_OOB_GPIO_NUM 722 return CUSTOM_OOB_GPIO_NUM; 723#else 724 return -1; 725#endif 726} 727 728int wifi_set_power(int on, unsigned long msec) 729{ 730 DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); 731 if (wifi_control_data && wifi_control_data->set_power) { 732 wifi_control_data->set_power(on); 733 } 734 if (msec) 735 msleep(msec); 736 return 0; 737} 738 739#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) 740int wifi_get_mac_addr(unsigned char *buf) 741{ 742 DHD_ERROR(("%s\n", __FUNCTION__)); 743 if (!buf) 744 return -EINVAL; 745 if (wifi_control_data && wifi_control_data->get_mac_addr) { 746 return wifi_control_data->get_mac_addr(buf); 747 } 748 return -EOPNOTSUPP; 749} 750#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) */ 751 752#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) 753void *wifi_get_country_code(char *ccode) 754{ 755 DHD_TRACE(("%s\n", __FUNCTION__)); 756 if (!ccode) 757 return NULL; 758 if (wifi_control_data && wifi_control_data->get_country_code) { 759 return wifi_control_data->get_country_code(ccode); 760 } 761 return NULL; 762} 763#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)) */ 764 765static int wifi_set_carddetect(int on) 766{ 767 DHD_ERROR(("%s = %d\n", __FUNCTION__, on)); 768 if (wifi_control_data && wifi_control_data->set_carddetect) { 769 wifi_control_data->set_carddetect(on); 770 } 771 return 0; 772} 773 774static int wifi_probe(struct platform_device *pdev) 775{ 776 struct wifi_platform_data *wifi_ctrl = 777 (struct wifi_platform_data *)(pdev->dev.platform_data); 778 779 DHD_ERROR(("## %s\n", __FUNCTION__)); 780 wifi_irqres = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "bcmdhd_wlan_irq"); 781 if (wifi_irqres == NULL) 782 wifi_irqres = platform_get_resource_byname(pdev, 783 IORESOURCE_IRQ, "bcm4329_wlan_irq"); 784 wifi_control_data = wifi_ctrl; 785 786 wifi_set_power(1, 0); /* Power On */ 787 wifi_set_carddetect(1); /* CardDetect (0->1) */ 788 789 up(&wifi_control_sem); 790 return 0; 791} 792 793static int wifi_remove(struct platform_device *pdev) 794{ 795 struct wifi_platform_data *wifi_ctrl = 796 (struct wifi_platform_data *)(pdev->dev.platform_data); 797 798 DHD_ERROR(("## %s\n", __FUNCTION__)); 799 wifi_control_data = wifi_ctrl; 800 801 wifi_set_power(0, 0); /* Power Off */ 802 wifi_set_carddetect(0); /* CardDetect (1->0) */ 803 804 up(&wifi_control_sem); 805 return 0; 806} 807 808static int wifi_suspend(struct platform_device *pdev, pm_message_t state) 809{ 810 DHD_TRACE(("##> %s\n", __FUNCTION__)); 811#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) 812 bcmsdh_oob_intr_set(0); 813#endif 814 return 0; 815} 816 817static int wifi_resume(struct platform_device *pdev) 818{ 819 DHD_TRACE(("##> %s\n", __FUNCTION__)); 820#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)) && defined(OOB_INTR_ONLY) 821 if (dhd_os_check_if_up(bcmsdh_get_drvdata())) 822 bcmsdh_oob_intr_set(1); 823#endif 824 return 0; 825} 826 827static struct platform_driver wifi_device = { 828 .probe = wifi_probe, 829 .remove = wifi_remove, 830 .suspend = wifi_suspend, 831 .resume = wifi_resume, 832 .driver = { 833 .name = "bcmdhd_wlan", 834 } 835}; 836 837static struct platform_driver wifi_device_legacy = { 838 .probe = wifi_probe, 839 .remove = wifi_remove, 840 .suspend = wifi_suspend, 841 .resume = wifi_resume, 842 .driver = { 843 .name = "bcm4329_wlan", 844 } 845}; 846 847static int wifi_add_dev(void) 848{ 849 DHD_TRACE(("## Calling platform_driver_register\n")); 850 platform_driver_register(&wifi_device); 851 platform_driver_register(&wifi_device_legacy); 852 return 0; 853} 854 855static void wifi_del_dev(void) 856{ 857 DHD_TRACE(("## Unregister platform_driver_register\n")); 858 platform_driver_unregister(&wifi_device); 859 platform_driver_unregister(&wifi_device_legacy); 860} 861#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */