/drivers/net/wireless/bcmdhd/wl_android.c

https://bitbucket.org/cyanogenmod/android_kernel_asus_tf300t · C · 861 lines · 707 code · 99 blank · 55 comment · 172 complexity · 6e068bd2f9d6680b86fad53c796668aa MD5 · raw file

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