OLD | NEW |
1 /* | 1 //------------------------------------------------------------------------------ |
2 * | 2 // Copyright (c) 2004-2010 Atheros Communications Inc. |
3 * Copyright (c) 2004-2010 Atheros Communications Inc. | 3 // All rights reserved. |
4 * All rights reserved. | |
5 * | |
6 * | |
7 // This program is free software; you can redistribute it and/or modify | |
8 // it under the terms of the GNU General Public License version 2 as | |
9 // published by the Free Software Foundation; | |
10 // | 4 // |
11 // Software distributed under the License is distributed on an "AS | 5 // |
12 // IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or | 6 // |
13 // implied. See the License for the specific language governing | 7 // Permission to use, copy, modify, and/or distribute this software for any |
14 // rights and limitations under the License. | 8 // purpose with or without fee is hereby granted, provided that the above |
| 9 // copyright notice and this permission notice appear in all copies. |
| 10 // |
| 11 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| 12 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| 13 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| 14 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| 15 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| 16 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| 17 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 // | 18 // |
16 // | 19 // |
17 * | 20 // |
18 */ | 21 // Author(s): ="Atheros" |
| 22 //------------------------------------------------------------------------------ |
19 #include "ar6000_drv.h" | 23 #include "ar6000_drv.h" |
20 #undef ATH_MODULE_NAME | |
21 #define ATH_MODULE_NAME android | |
22 #include "htc.h" | 24 #include "htc.h" |
23 #include <linux/vmalloc.h> | 25 #include <linux/vmalloc.h> |
24 #include <linux/fs.h> | 26 #include <linux/fs.h> |
25 #include <linux/platform_device.h> | |
26 #include <linux/inetdevice.h> | |
27 | 27 |
28 #ifdef CONFIG_HAS_WAKELOCK | 28 #ifdef CONFIG_HAS_WAKELOCK |
29 #include <linux/wakelock.h> | 29 #include <linux/wakelock.h> |
30 #endif | 30 #endif |
| 31 #ifdef CONFIG_HAS_EARLYSUSPEND |
31 #include <linux/earlysuspend.h> | 32 #include <linux/earlysuspend.h> |
32 | |
33 enum { | |
34 WLAN_PWR_CTRL_UP = 0, | |
35 WLAN_PWR_CTRL_CUT_PWR, | |
36 WLAN_PWR_CTRL_DEEP_SLEEP, | |
37 WLAN_PWR_CTRL_WOW, | |
38 WLAN_PWR_CTRL_DEEP_SLEEP_DISABLED | |
39 }; | |
40 | |
41 enum { | |
42 WOW_STATE_NONE = 0, | |
43 WOW_STATE_SUSPENDED, | |
44 WOW_STATE_SUSPENDING, | |
45 }; | |
46 | |
47 #define WOW_ENABLE_MAX_INTERVAL 0 | |
48 #define WOW_SET_SCAN_PARAMS 0 | |
49 | |
50 #define IS_MAC_NULL(mac) (mac[0]==0 && mac[1]==0 && mac[2]==0 && mac[3]==0 && ma
c[4]==0 && mac[5]==0) | |
51 #define MAX_BUF (8*1024) | |
52 | |
53 #define ATH_DEBUG_SUSPEND ATH_DEBUG_MAKE_MODULE_MASK(0) | |
54 | |
55 #ifdef DEBUG | |
56 | |
57 static ATH_DEBUG_MASK_DESCRIPTION android_debug_desc[] = { | |
58 { ATH_DEBUG_SUSPEND , "Android Debug Logs"}, | |
59 }; | |
60 | |
61 ATH_DEBUG_INSTANTIATE_MODULE_VAR(android, | |
62 "android", | |
63 "Android Driver Interface", | |
64 ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_SUSPEND, | |
65 ATH_DEBUG_DESCRIPTION_COUNT(android_debug_desc)
, | |
66 android_debug_desc); | |
67 | |
68 #endif | 33 #endif |
69 | 34 |
70 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) | 35 A_BOOL enable_mmc_host_detect_change = 0; |
| 36 static void ar6000_enable_mmchost_detect_change(int enable); |
| 37 |
| 38 |
71 char fwpath[256] = "/system/wifi"; | 39 char fwpath[256] = "/system/wifi"; |
72 #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */ | |
73 int buspm = WLAN_PWR_CTRL_WOW; | |
74 int wow2mode = WLAN_PWR_CTRL_DEEP_SLEEP; | |
75 int wowledon; | 40 int wowledon; |
76 unsigned int enablelogcat; | 41 unsigned int enablelogcat; |
77 | 42 |
78 extern int bmienable; | 43 extern int bmienable; |
79 extern int wlaninitmode; | |
80 extern unsigned int wmitimeout; | |
81 extern wait_queue_head_t arEvent; | |
82 extern struct net_device *ar6000_devices[]; | 44 extern struct net_device *ar6000_devices[]; |
83 #ifdef CONFIG_HOST_TCMD_SUPPORT | 45 extern char ifname[]; |
84 extern unsigned int testmode; | 46 |
| 47 #ifdef CONFIG_HAS_WAKELOCK |
| 48 extern struct wake_lock ar6k_wow_wake_lock; |
| 49 struct wake_lock ar6k_init_wake_lock; |
85 #endif | 50 #endif |
86 extern char ifname[]; | |
87 extern unsigned int bypasswmi; | |
88 | 51 |
89 const char def_ifname[] = "wlan0"; | 52 const char def_ifname[] = "wlan0"; |
90 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) | |
91 module_param_string(fwpath, fwpath, sizeof(fwpath), 0644); | 53 module_param_string(fwpath, fwpath, sizeof(fwpath), 0644); |
92 module_param(buspm, int, 0644); | |
93 module_param(enablelogcat, uint, 0644); | 54 module_param(enablelogcat, uint, 0644); |
94 module_param(wowledon, int, 0644); | 55 module_param(wowledon, int, 0644); |
95 #else | |
96 #define __user | |
97 /* for linux 2.4 and lower */ | |
98 MODULE_PARM(buspm,"i"); | |
99 MODULE_PARAM(wowledon,"i"); | |
100 #endif | |
101 | 56 |
102 struct wake_lock ar6k_init_wake_lock; | 57 #ifdef CONFIG_HAS_EARLYSUSPEND |
103 struct wake_lock ar6k_wow_wake_lock; | |
104 static int screen_is_off; | 58 static int screen_is_off; |
105 static struct early_suspend ar6k_early_suspend; | 59 static struct early_suspend ar6k_early_suspend; |
| 60 #endif |
| 61 |
106 static A_STATUS (*ar6000_avail_ev_p)(void *, void *); | 62 static A_STATUS (*ar6000_avail_ev_p)(void *, void *); |
107 | 63 |
108 extern int ar6000_init(struct net_device *dev); | 64 #if defined(CONFIG_ANDROID_LOGGER) && (!defined(CONFIG_MMC_MSM)) |
109 extern A_STATUS ar6000_configure_target(AR_SOFTC_T *ar); | |
110 extern void ar6000_stop_endpoint(struct net_device *dev, A_BOOL keepprofile); | |
111 extern A_STATUS ar6000_sysfs_bmi_get_config(AR_SOFTC_T *ar, A_UINT32 mode); | |
112 extern void ar6000_destroy(struct net_device *dev, unsigned int unregister); | |
113 | |
114 static void ar6000_enable_mmchost_detect_change(int enable); | |
115 static void ar6000_restart_endpoint(struct net_device *dev); | |
116 | |
117 #if defined(CONFIG_PM) | |
118 static A_STATUS ar6000_suspend_ev(void *context); | |
119 | |
120 static A_STATUS ar6000_resume_ev(void *context); | |
121 #endif | |
122 | |
123 #ifndef CONFIG_MMC_MSM | |
124 int logger_write(const enum logidx index, | 65 int logger_write(const enum logidx index, |
125 const unsigned char prio, | 66 const unsigned char prio, |
126 const char __kernel * const tag, | 67 const char __kernel * const tag, |
127 const char __kernel * const fmt, | 68 const char __kernel * const fmt, |
128 ...) | 69 ...) |
129 { | 70 { |
130 int ret = 0; | 71 int ret = 0; |
131 va_list vargs; | 72 va_list vargs; |
132 struct file *filp = (struct file *)-ENOENT; | 73 struct file *filp = (struct file *)-ENOENT; |
133 mm_segment_t oldfs; | 74 mm_segment_t oldfs; |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
234 filp = filp_open(filename, mode, S_IRUSR); | 175 filp = filp_open(filename, mode, S_IRUSR); |
235 if (IS_ERR(filp) || !filp->f_op) { | 176 if (IS_ERR(filp) || !filp->f_op) { |
236 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: file %s filp_open error\n", __F
UNCTION__, filename)); | 177 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: file %s filp_open error\n", __F
UNCTION__, filename)); |
237 ret = -ENOENT; | 178 ret = -ENOENT; |
238 break; | 179 break; |
239 } | 180 } |
240 | 181 |
241 if (length==0) { | 182 if (length==0) { |
242 /* Read the length of the file only */ | 183 /* Read the length of the file only */ |
243 struct inode *inode; | 184 struct inode *inode; |
244 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) | 185 |
245 inode = filp->f_path.dentry->d_inode; | 186 inode = GET_INODE_FROM_FILEP(filp); |
246 #else | 187 if (!inode) { |
247 inode = filp->f_dentry->d_inode; | |
248 #endif | |
249 » » if (!inode) { | |
250 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Get inode from %s failed\n"
, __FUNCTION__, filename)); | 188 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: Get inode from %s failed\n"
, __FUNCTION__, filename)); |
251 ret = -ENOENT; | 189 ret = -ENOENT; |
252 break; | 190 break; |
253 } | 191 } |
254 ret = i_size_read(inode->i_mapping->host); | 192 ret = i_size_read(inode->i_mapping->host); |
255 break; | 193 break; |
256 } | 194 } |
257 | 195 |
258 if (wbuf) { | 196 if (wbuf) { |
259 if ( (ret=filp->f_op->write(filp, wbuf, length, &filp->f_pos)) < 0)
{ | 197 if ( (ret=filp->f_op->write(filp, wbuf, length, &filp->f_pos)) < 0)
{ |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 if ( (ret=android_readwrite_file(filename, NULL, NULL, 0)) < 0) { | 233 if ( (ret=android_readwrite_file(filename, NULL, NULL, 0)) < 0) { |
296 break; | 234 break; |
297 } else { | 235 } else { |
298 length = ret; | 236 length = ret; |
299 } | 237 } |
300 | 238 |
301 bufsize = ALIGN(length, PAGE_SIZE); | 239 bufsize = ALIGN(length, PAGE_SIZE); |
302 bmisize = A_ROUND_UP(length, 4); | 240 bmisize = A_ROUND_UP(length, 4); |
303 bufsize = max(bmisize, bufsize); | 241 bufsize = max(bmisize, bufsize); |
304 firmware->data = vmalloc(bufsize); | 242 firmware->data = vmalloc(bufsize); |
305 firmware->size = bmisize; | 243 firmware->size = length; |
306 if (!firmware->data) { | 244 if (!firmware->data) { |
307 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: Cannot allocate buffer for firmw
are\n", __FUNCTION__)); | 245 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: Cannot allocate buffer for firmw
are\n", __FUNCTION__)); |
308 ret = -ENOMEM; | 246 ret = -ENOMEM; |
309 break; | 247 break; |
310 } | 248 } |
311 | 249 |
312 if ( (ret=android_readwrite_file(filename, (char*)firmware->data, NULL,
length)) != length) { | 250 if ( (ret=android_readwrite_file(filename, (char*)firmware->data, NULL,
length)) != length) { |
313 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: file read error, ret %d request
%d\n", __FUNCTION__, ret, length)); | 251 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("%s: file read error, ret %d request
%d\n", __FUNCTION__, ret, length)); |
314 ret = -1; | 252 ret = -1; |
315 break; | 253 break; |
(...skipping 16 matching lines...) Expand all Loading... |
332 | 270 |
333 void android_release_firmware(const struct firmware *firmware) | 271 void android_release_firmware(const struct firmware *firmware) |
334 { | 272 { |
335 if (firmware) { | 273 if (firmware) { |
336 if (firmware->data) | 274 if (firmware->data) |
337 vfree(firmware->data); | 275 vfree(firmware->data); |
338 kfree(firmware); | 276 kfree(firmware); |
339 } | 277 } |
340 } | 278 } |
341 | 279 |
342 #if defined(CONFIG_PM) | |
343 static void ar6k_send_asleep_event_to_app(AR_SOFTC_T *ar, A_BOOL asleep) | |
344 { | |
345 char buf[128]; | |
346 union iwreq_data wrqu; | |
347 | |
348 snprintf(buf, sizeof(buf), "HOST_ASLEEP=%s", asleep ? "asleep" : "awake"); | |
349 A_MEMZERO(&wrqu, sizeof(wrqu)); | |
350 wrqu.data.length = strlen(buf); | |
351 wireless_send_event(ar->arNetDev, IWEVCUSTOM, &wrqu, buf); | |
352 } | |
353 | |
354 static void ar6000_wow_resume(AR_SOFTC_T *ar) | |
355 { | |
356 if (ar->arWowState!=WOW_STATE_NONE) { | |
357 A_UINT16 fg_start_period = (ar->scParams.fg_start_period==0) ? 1 : ar->s
cParams.fg_start_period; | |
358 A_UINT16 bg_period = (ar->scParams.bg_period==0) ? 60 : ar->scParams.bg_
period; | |
359 WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {TRUE, FALSE}; | |
360 ar->arWowState = WOW_STATE_NONE; | |
361 wake_lock_timeout(&ar6k_wow_wake_lock, 3*HZ); | |
362 if (wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode)!=A_OK) { | |
363 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup restore host awake\n")
); | |
364 } | |
365 #if WOW_SET_SCAN_PARAMS | |
366 wmi_scanparams_cmd(ar->arWmi, fg_start_period, | |
367 ar->scParams.fg_end_period, | |
368 bg_period, | |
369 ar->scParams.minact_chdwell_time, | |
370 ar->scParams.maxact_chdwell_time, | |
371 ar->scParams.pas_chdwell_time, | |
372 ar->scParams.shortScanRatio, | |
373 ar->scParams.scanCtrlFlags, | |
374 ar->scParams.max_dfsch_act_time, | |
375 ar->scParams.maxact_scan_per_ssid); | |
376 #else | |
377 (void)fg_start_period; | |
378 (void)bg_period; | |
379 #endif | |
380 | |
381 | |
382 #if WOW_ENABLE_MAX_INTERVAL /* we don't do it if the power consumption is alread
y good enough. */ | |
383 if (wmi_listeninterval_cmd(ar->arWmi, ar->arListenIntervalT, ar->arListe
nIntervalB) == A_OK) { | |
384 } | |
385 #endif | |
386 ar6k_send_asleep_event_to_app(ar, FALSE); | |
387 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND, ("Resume WoW successfully\n")); | |
388 } else { | |
389 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND, ("WoW does not invoked. skip resume")
); | |
390 } | |
391 } | |
392 | |
393 static void ar6000_wow_suspend(AR_SOFTC_T *ar) | |
394 { | |
395 #define ANDROID_WOW_LIST_ID 1 | |
396 if (ar->arNetworkType != AP_NETWORK) { | |
397 /* Setup WoW for unicast & Arp request for our own IP | |
398 disable background scan. Set listen interval into 1000 TUs | |
399 Enable keepliave for 110 seconds | |
400 */ | |
401 struct in_ifaddr **ifap = NULL; | |
402 struct in_ifaddr *ifa = NULL; | |
403 struct in_device *in_dev; | |
404 A_UINT8 macMask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | |
405 A_STATUS status; | |
406 WMI_ADD_WOW_PATTERN_CMD addWowCmd = { .filter = { 0 } }; | |
407 WMI_DEL_WOW_PATTERN_CMD delWowCmd; | |
408 WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = {FALSE, TRUE}; | |
409 WMI_SET_WOW_MODE_CMD wowMode = { .enable_wow = TRUE, | |
410 .hostReqDelay = 500 };/*500 ms delay
*/ | |
411 | |
412 if (ar->arWowState!=WOW_STATE_NONE) { | |
413 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("System already go into wow mode!\n")
); | |
414 return; | |
415 } | |
416 | |
417 ar6000_TxDataCleanup(ar); /* IMPORTANT, otherwise there will be 11mA aft
er listen interval as 1000*/ | |
418 | |
419 #if WOW_ENABLE_MAX_INTERVAL /* we don't do it if the power consumption is alread
y good enough. */ | |
420 if (wmi_listeninterval_cmd(ar->arWmi, A_MAX_WOW_LISTEN_INTERVAL, 0) == A
_OK) { | |
421 } | |
422 #endif | |
423 | |
424 #if WOW_SET_SCAN_PARAMS | |
425 status = wmi_scanparams_cmd(ar->arWmi, 0xFFFF, 0, 0xFFFF, 0, 0, 0, 0, 0,
0, 0); | |
426 #endif | |
427 /* clear up our WoW pattern first */ | |
428 delWowCmd.filter_list_id = ANDROID_WOW_LIST_ID; | |
429 delWowCmd.filter_id = 0; | |
430 wmi_del_wow_pattern_cmd(ar->arWmi, &delWowCmd); | |
431 | |
432 /* setup unicast packet pattern for WoW */ | |
433 if (ar->arNetDev->dev_addr[1]) { | |
434 addWowCmd.filter_list_id = ANDROID_WOW_LIST_ID; | |
435 addWowCmd.filter_size = 6; /* MAC address */ | |
436 addWowCmd.filter_offset = 0; | |
437 status = wmi_add_wow_pattern_cmd(ar->arWmi, &addWowCmd, ar->arNetDev
->dev_addr, macMask, addWowCmd.filter_size); | |
438 if (status != A_OK) { | |
439 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to add WoW pattern\n")); | |
440 } | |
441 } | |
442 /* setup ARP request for our own IP */ | |
443 if ((in_dev = __in_dev_get_rtnl(ar->arNetDev)) != NULL) { | |
444 for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->i
fa_next) { | |
445 if (!strcmp(ar->arNetDev->name, ifa->ifa_label)) { | |
446 break; /* found */ | |
447 } | |
448 } | |
449 } | |
450 if (ifa && ifa->ifa_local) { | |
451 WMI_SET_IP_CMD ipCmd; | |
452 memset(&ipCmd, 0, sizeof(ipCmd)); | |
453 ipCmd.ips[0] = ifa->ifa_local; | |
454 status = wmi_set_ip_cmd(ar->arWmi, &ipCmd); | |
455 if (status != A_OK) { | |
456 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup IP for ARP agent\n
")); | |
457 } | |
458 } | |
459 | |
460 #ifndef ATH6K_CONFIG_OTA_MODE | |
461 wmi_powermode_cmd(ar->arWmi, REC_POWER); | |
462 #endif | |
463 | |
464 status = wmi_set_wow_mode_cmd(ar->arWmi, &wowMode); | |
465 if (status != A_OK) { | |
466 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to enable wow mode\n")); | |
467 } | |
468 ar6k_send_asleep_event_to_app(ar, TRUE); | |
469 | |
470 status = wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode); | |
471 if (status != A_OK) { | |
472 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to set host asleep\n")); | |
473 } | |
474 | |
475 ar->arWowState = WOW_STATE_SUSPENDING; | |
476 if (ar->arTxPending[ar->arControlEp]) { | |
477 long timeleft = wait_event_interruptible_timeout(arEvent, | |
478 ar->arTxPending[ar->arControlEp] == 0, wmitimeout * HZ); | |
479 if (!timeleft || signal_pending(current)) { | |
480 /* what can I do? wow resume at once */ | |
481 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup WoW. Pending wmi c
ontrol data %d\n", ar->arTxPending[ar->arControlEp])); | |
482 } | |
483 } | |
484 } else { | |
485 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Not allowed to go to WOW at this moment.
\n")); | |
486 } | |
487 } | |
488 | |
489 static void ar6000_pwr_on(AR_SOFTC_T *ar) | |
490 { | |
491 if (ar == NULL) { | |
492 /* turn on for all cards */ | |
493 } | |
494 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("%s --enter\n", __FUNCTION__)); | |
495 | |
496 } | |
497 | |
498 static void ar6000_pwr_down(AR_SOFTC_T *ar) | |
499 { | |
500 if (ar == NULL) { | |
501 /* shutdown for all cards */ | |
502 } | |
503 AR_DEBUG_PRINTF(ATH_DEBUG_INFO,("%s --enter\n", __FUNCTION__)); | |
504 | |
505 } | |
506 | |
507 static A_STATUS ar6000_suspend_ev(void *context) | |
508 { | |
509 A_STATUS status = A_OK; | |
510 int pmmode = buspm; | |
511 AR_SOFTC_T *ar = (AR_SOFTC_T *)context; | |
512 wow_not_connected: | |
513 | |
514 switch (pmmode) { | |
515 case WLAN_PWR_CTRL_DEEP_SLEEP: | |
516 if (ar->arWlanState == WLAN_DISABLED) { | |
517 ar->arOsPowerCtrl = WLAN_PWR_CTRL_DEEP_SLEEP_DISABLED; | |
518 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND,("%s:Suspend for deep sleep disabl
ed mode %d\n", __func__, ar->arOsPowerCtrl)); | |
519 } else { | |
520 ar6000_set_wlan_state(ar, WLAN_DISABLED); | |
521 ar->arOsPowerCtrl = WLAN_PWR_CTRL_DEEP_SLEEP; | |
522 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND,("%s:Suspend for deep sleep mode %
d\n", __func__, ar->arOsPowerCtrl)); | |
523 } | |
524 status = A_EBUSY; | |
525 break; | |
526 case WLAN_PWR_CTRL_WOW: | |
527 if (ar->arWmiReady && ar->arWlanState==WLAN_ENABLED && ar->arConnected)
{ | |
528 ar->arOsPowerCtrl = WLAN_PWR_CTRL_WOW; | |
529 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND,("%s:Suspend for wow mode %d\n", _
_func__, ar->arOsPowerCtrl)); | |
530 ar6000_wow_suspend(ar); | |
531 /* leave for pm_device to setup wow */ | |
532 status = A_EBUSY; | |
533 } else { | |
534 pmmode = wow2mode; | |
535 goto wow_not_connected; | |
536 } | |
537 break; | |
538 case WLAN_PWR_CTRL_CUT_PWR: | |
539 /* fall through */ | |
540 default: | |
541 ar->arOsPowerCtrl = WLAN_PWR_CTRL_CUT_PWR; | |
542 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND,("%s: Suspend for cut off mode %d\n",
__func__, ar->arOsPowerCtrl)); | |
543 ar6000_stop_endpoint(ar->arNetDev, TRUE); | |
544 status = A_OK; | |
545 break; | |
546 } | |
547 | |
548 ar->scan_triggered = 0; | |
549 return status; | |
550 } | |
551 | |
552 static A_STATUS ar6000_resume_ev(void *context) | |
553 { | |
554 AR_SOFTC_T *ar = (AR_SOFTC_T *)context; | |
555 A_UINT16 powerCtrl = ar->arOsPowerCtrl; | |
556 wake_lock(&ar6k_init_wake_lock); | |
557 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND, ("%s: enter previous state %d wowState %d
\n", __func__, powerCtrl, ar->arWowState)); | |
558 ar->arOsPowerCtrl = WLAN_PWR_CTRL_UP; | |
559 switch (powerCtrl) { | |
560 case WLAN_PWR_CTRL_WOW: | |
561 ar6000_wow_resume(ar); | |
562 break; | |
563 case WLAN_PWR_CTRL_CUT_PWR: | |
564 ar6000_restart_endpoint(ar->arNetDev); | |
565 break; | |
566 case WLAN_PWR_CTRL_DEEP_SLEEP: | |
567 ar6000_set_wlan_state(ar, WLAN_ENABLED); | |
568 break; | |
569 case WLAN_PWR_CTRL_DEEP_SLEEP_DISABLED: | |
570 break; | |
571 case WLAN_PWR_CTRL_UP: | |
572 break; | |
573 default: | |
574 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Strange SDIO bus power mode!!\n")); | |
575 break; | |
576 } | |
577 wake_unlock(&ar6k_init_wake_lock); | |
578 return A_OK; | |
579 } | |
580 | |
581 static A_STATUS ar6000_android_avail_ev(void *context, void *hif_handle) | 280 static A_STATUS ar6000_android_avail_ev(void *context, void *hif_handle) |
582 { | 281 { |
583 A_STATUS ret; | 282 A_STATUS ret; |
| 283 #ifdef CONFIG_HAS_WAKELOCK |
584 wake_lock(&ar6k_init_wake_lock); | 284 wake_lock(&ar6k_init_wake_lock); |
| 285 #endif |
585 ar6000_enable_mmchost_detect_change(0); | 286 ar6000_enable_mmchost_detect_change(0); |
586 ret = ar6000_avail_ev_p(context, hif_handle); | 287 ret = ar6000_avail_ev_p(context, hif_handle); |
| 288 #ifdef CONFIG_HAS_WAKELOCK |
587 wake_unlock(&ar6k_init_wake_lock); | 289 wake_unlock(&ar6k_init_wake_lock); |
| 290 #endif |
588 return ret; | 291 return ret; |
589 } | 292 } |
590 | 293 |
591 | |
592 static int ar6000_pm_suspend(struct platform_device *dev, pm_message_t state) | |
593 { | |
594 int i; | |
595 for (i = 0; i < MAX_AR6000; i++) { | |
596 AR_SOFTC_T *ar; | |
597 | |
598 if (ar6000_devices[i] == NULL) | |
599 continue; | |
600 ar = (AR_SOFTC_T*)netdev_priv(ar6000_devices[i]); | |
601 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND,("%s: enter status %d\n", __func__, ar
->arOsPowerCtrl)); | |
602 switch (ar->arOsPowerCtrl) { | |
603 case WLAN_PWR_CTRL_CUT_PWR: | |
604 ar6000_pwr_down(ar); | |
605 break; | |
606 case WLAN_PWR_CTRL_WOW: | |
607 if (ar->arTxPending[ar->arControlEp]) { | |
608 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Fail to setup WoW. Pending wmi c
ontrol data %d\n", ar->arTxPending[ar->arControlEp])); | |
609 ar->arWowState = WOW_STATE_NONE; | |
610 } else { | |
611 ar->arWowState = WOW_STATE_SUSPENDED; | |
612 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND,("Setup WoW successfully\n")); | |
613 } | |
614 break; | |
615 case WLAN_PWR_CTRL_DEEP_SLEEP: | |
616 /* fall through */ | |
617 case WLAN_PWR_CTRL_DEEP_SLEEP_DISABLED: | |
618 /* nothing to do. keep the power on */ | |
619 break; | |
620 default: | |
621 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Something is strange for ar6000_pm_s
uspend %d\n", ar->arOsPowerCtrl)); | |
622 break; | |
623 } | |
624 } | |
625 return 0; | |
626 } | |
627 | |
628 static int ar6000_pm_resume(struct platform_device *dev) | |
629 { | |
630 int i; | |
631 for (i = 0; i < MAX_AR6000; i++) { | |
632 AR_SOFTC_T *ar; | |
633 | |
634 if (ar6000_devices[i] == NULL) | |
635 continue; | |
636 ar = (AR_SOFTC_T*)netdev_priv(ar6000_devices[i]); | |
637 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND,("%s: enter status %d\n", __func__, ar
->arOsPowerCtrl)); | |
638 switch (ar->arOsPowerCtrl) { | |
639 case WLAN_PWR_CTRL_CUT_PWR: | |
640 ar6000_pwr_on(ar); | |
641 break; | |
642 case WLAN_PWR_CTRL_WOW: | |
643 /* nothing to do. keep the power on */ | |
644 break; | |
645 case WLAN_PWR_CTRL_DEEP_SLEEP: | |
646 /* fall through */ | |
647 case WLAN_PWR_CTRL_DEEP_SLEEP_DISABLED: | |
648 /* nothing to do. keep the power on */ | |
649 break; | |
650 default: | |
651 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("Something is strange for ar6000_pm_r
esume %d\n", ar->arOsPowerCtrl)); | |
652 break; | |
653 } | |
654 } | |
655 return 0; | |
656 } | |
657 | |
658 static int ar6000_pm_probe(struct platform_device *pdev) | |
659 { | |
660 ar6000_pwr_on(NULL); | |
661 return 0; | |
662 } | |
663 | |
664 static int ar6000_pm_remove(struct platform_device *pdev) | |
665 { | |
666 ar6000_pwr_down(NULL); | |
667 return 0; | |
668 } | |
669 | |
670 static struct platform_driver ar6000_pm_device = { | |
671 .probe = ar6000_pm_probe, | |
672 .remove = ar6000_pm_remove, | |
673 .suspend = ar6000_pm_suspend, | |
674 .resume = ar6000_pm_resume, | |
675 .driver = { | |
676 .name = "wlan_ar6000_pm_dev", | |
677 }, | |
678 }; | |
679 #endif /* CONFIG_PM */ | |
680 | |
681 /* Useful for qualcom platform to detect our wlan card for mmc stack */ | 294 /* Useful for qualcom platform to detect our wlan card for mmc stack */ |
682 static void ar6000_enable_mmchost_detect_change(int enable) | 295 static void ar6000_enable_mmchost_detect_change(int enable) |
683 { | 296 { |
684 #ifdef CONFIG_MMC_MSM | 297 #ifdef CONFIG_MMC_MSM |
685 #define MMC_MSM_DEV "msm_sdcc.1" | 298 #define MMC_MSM_DEV "msm_sdcc.1" |
686 char buf[3]; | 299 char buf[3]; |
687 int length; | 300 int length; |
| 301 |
| 302 if (!enable_mmc_host_detect_change) { |
| 303 return; |
| 304 } |
688 length = snprintf(buf, sizeof(buf), "%d\n", enable ? 1 : 0); | 305 length = snprintf(buf, sizeof(buf), "%d\n", enable ? 1 : 0); |
689 if (android_readwrite_file("/sys/devices/platform/" MMC_MSM_DEV "/detect_cha
nge", | 306 if (android_readwrite_file("/sys/devices/platform/" MMC_MSM_DEV "/detect_cha
nge", |
690 NULL, buf, length) < 0) { | 307 NULL, buf, length) < 0) { |
691 /* fall back to polling */ | 308 /* fall back to polling */ |
692 android_readwrite_file("/sys/devices/platform/" MMC_MSM_DEV "/polling",
NULL, buf, length); | 309 android_readwrite_file("/sys/devices/platform/" MMC_MSM_DEV "/polling",
NULL, buf, length); |
693 } | 310 } |
694 #endif | 311 #endif |
695 } | 312 } |
696 | 313 |
697 static void | |
698 ar6000_restart_endpoint(struct net_device *dev) | |
699 { | |
700 A_STATUS status = A_OK; | |
701 AR_SOFTC_T *ar = (AR_SOFTC_T*)netdev_priv(dev); | |
702 if (down_interruptible(&ar->arSem)) { | |
703 AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s(): down_interruptible failed \n", __
func__)); | |
704 return ; | |
705 } | |
706 if (ar->bIsDestroyProgress) { | |
707 up(&ar->arSem); | |
708 return; | |
709 } | |
710 BMIInit(); | |
711 do { | |
712 if ( (status=ar6000_configure_target(ar))!=A_OK) | |
713 break; | |
714 if ( (status=ar6000_sysfs_bmi_get_config(ar, wlaninitmode)) != A
_OK) | |
715 { | |
716 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000_avail: ar6000_sys
fs_bmi_get_config failed\n")); | |
717 break; | |
718 } | |
719 rtnl_lock(); | |
720 status = (ar6000_init(dev)==0) ? A_OK : A_ERROR; | |
721 rtnl_unlock(); | |
722 | |
723 if (status!=A_OK) { | |
724 break; | |
725 } | |
726 if (ar->arWlanState==WLAN_ENABLED) { | |
727 if (ar->arSsidLen) { | |
728 ar6000_connect_to_ap(ar); | |
729 } | |
730 } else { | |
731 WMI_SET_WOW_MODE_CMD wowMode = { .enable_wow = FALSE }; | |
732 WMI_SET_HOST_SLEEP_MODE_CMD hostSleepMode = { .awake = FALSE, .aslee
p = TRUE }; | |
733 WMI_REPORT_SLEEP_STATE_EVENT wmiSleepEvent = { | |
734 .sleepState = WMI_REPORT_SLEEP_STATUS_IS_DEEP_SLEEP | |
735 }; | |
736 | |
737 wmi_set_wow_mode_cmd(ar->arWmi, &wowMode); | |
738 ar6000_send_event_to_app(ar, WMI_REPORT_SLEEP_STATE_EVENTID, (A_UINT
8*)&wmiSleepEvent, | |
739 sizeof(WMI_REPORT_SLEEP_STATE_EVENTID)); | |
740 wmi_set_host_sleep_mode_cmd(ar->arWmi, &hostSleepMode); | |
741 } | |
742 } while (0); | |
743 | |
744 up(&ar->arSem); | |
745 if (status==A_OK) { | |
746 return; | |
747 } | |
748 | |
749 ar6000_devices[ar->arDeviceIndex] = NULL; | |
750 ar6000_destroy(ar->arNetDev, 1); | |
751 } | |
752 | |
753 #ifdef CONFIG_HAS_EARLYSUSPEND | 314 #ifdef CONFIG_HAS_EARLYSUSPEND |
754 static void android_early_suspend(struct early_suspend *h) | 315 static void android_early_suspend(struct early_suspend *h) |
755 { | 316 { |
756 screen_is_off = 1; | 317 screen_is_off = 1; |
757 } | 318 } |
758 | 319 |
759 static void android_late_resume(struct early_suspend *h) | 320 static void android_late_resume(struct early_suspend *h) |
760 { | 321 { |
761 screen_is_off = 0; | 322 screen_is_off = 0; |
762 } | 323 } |
763 #endif | 324 #endif |
764 | 325 |
765 void android_module_init(OSDRV_CALLBACKS *osdrvCallbacks) | 326 void android_module_init(OSDRV_CALLBACKS *osdrvCallbacks) |
766 { | 327 { |
767 bmienable = 1; | 328 bmienable = 1; |
768 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) | |
769 if (ifname[0] == '\0') | 329 if (ifname[0] == '\0') |
770 strcpy(ifname, def_ifname); | 330 strcpy(ifname, def_ifname); |
771 #endif | 331 #ifdef CONFIG_HAS_WAKELOCK |
772 if (wow2mode!=WLAN_PWR_CTRL_CUT_PWR && wow2mode!=WLAN_PWR_CTRL_DEEP_SLEEP) { | |
773 wow2mode=WLAN_PWR_CTRL_CUT_PWR; | |
774 } | |
775 | |
776 wake_lock_init(&ar6k_init_wake_lock, WAKE_LOCK_SUSPEND, "ar6k_init"); | 332 wake_lock_init(&ar6k_init_wake_lock, WAKE_LOCK_SUSPEND, "ar6k_init"); |
777 wake_lock_init(&ar6k_wow_wake_lock, WAKE_LOCK_SUSPEND, "ar6k_wow"); | 333 #endif |
778 | |
779 #ifdef CONFIG_HAS_EARLYSUSPEND | 334 #ifdef CONFIG_HAS_EARLYSUSPEND |
780 ar6k_early_suspend.suspend = android_early_suspend; | 335 ar6k_early_suspend.suspend = android_early_suspend; |
781 ar6k_early_suspend.resume = android_late_resume; | 336 ar6k_early_suspend.resume = android_late_resume; |
782 ar6k_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; | 337 ar6k_early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN; |
783 register_early_suspend(&ar6k_early_suspend); | 338 register_early_suspend(&ar6k_early_suspend); |
784 #endif | 339 #endif |
785 | 340 |
786 #if defined(CONFIG_PM) | |
787 osdrvCallbacks->deviceSuspendHandler = ar6000_suspend_ev; | |
788 osdrvCallbacks->deviceResumeHandler = ar6000_resume_ev; | |
789 #endif | |
790 ar6000_avail_ev_p = osdrvCallbacks->deviceInsertedHandler; | 341 ar6000_avail_ev_p = osdrvCallbacks->deviceInsertedHandler; |
791 osdrvCallbacks->deviceInsertedHandler = ar6000_android_avail_ev; | 342 osdrvCallbacks->deviceInsertedHandler = ar6000_android_avail_ev; |
792 | 343 |
793 #if defined(CONFIG_PM) | |
794 /* Register ar6000_pm_device into system. | |
795 * We should also add platform_device into the first item of array devices[]
in | |
796 * file arch/xxx/mach-xxx/board-xxxx.c | |
797 * Otherwise, WoW may not work properly since we may trigger WoW GPIO before
system suspend | |
798 */ | |
799 if (platform_driver_register(&ar6000_pm_device)) | |
800 AR_DEBUG_PRINTF(ATH_DEBUG_ERR,("ar6000: fail to register the power contr
ol driver.\n")); | |
801 #endif | |
802 | |
803 ar6000_enable_mmchost_detect_change(1); | 344 ar6000_enable_mmchost_detect_change(1); |
804 } | 345 } |
805 | 346 |
806 void android_module_exit(void) | 347 void android_module_exit(void) |
807 { | 348 { |
808 #ifdef CONFIG_HAS_EARLYSUSPEND | 349 #ifdef CONFIG_HAS_EARLYSUSPEND |
809 unregister_early_suspend(&ar6k_early_suspend); | 350 unregister_early_suspend(&ar6k_early_suspend); |
810 #endif | 351 #endif |
811 wake_lock_destroy(&ar6k_wow_wake_lock); | 352 #ifdef CONFIG_HAS_WAKELOCK |
812 wake_lock_destroy(&ar6k_init_wake_lock); | 353 wake_lock_destroy(&ar6k_init_wake_lock); |
813 | |
814 #ifdef CONFIG_PM | |
815 platform_driver_unregister(&ar6000_pm_device); | |
816 #endif | 354 #endif |
817 ar6000_enable_mmchost_detect_change(1); | 355 ar6000_enable_mmchost_detect_change(1); |
818 } | 356 } |
819 | 357 |
820 A_BOOL android_ar6k_endpoint_is_stop(AR_SOFTC_T *ar) | |
821 { | |
822 #ifdef CONFIG_PM | 358 #ifdef CONFIG_PM |
823 return ar->arOsPowerCtrl == WLAN_PWR_CTRL_CUT_PWR; | |
824 #else | |
825 return FALSE; | |
826 #endif | |
827 } | |
828 | |
829 void android_ar6k_check_wow_status(AR_SOFTC_T *ar, struct sk_buff *skb, A_BOOL i
sEvent) | 359 void android_ar6k_check_wow_status(AR_SOFTC_T *ar, struct sk_buff *skb, A_BOOL i
sEvent) |
830 { | 360 { |
831 #ifdef CONFIG_PM | 361 if ( |
832 if (ar->arWowState!=WOW_STATE_NONE) { | 362 #ifdef CONFIG_HAS_EARLYSUSPEND |
833 if (ar->arWowState==WOW_STATE_SUSPENDING) { | 363 screen_is_off && |
834 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND,("%s: Received IRQ while we are wo
w suspending!!!\n", __func__)); | 364 #endif |
835 return; | 365 skb && ar->arConnected) { |
836 } | |
837 /* Wow resume from irq interrupt */ | |
838 AR_DEBUG_PRINTF(ATH_DEBUG_SUSPEND, ("%s: WoW resume from irq thread stat
us %d\n", | |
839 __func__, ar->arOsPowerCtrl)); | |
840 ar6000_wow_resume(ar); | |
841 ar->arOsPowerCtrl = WLAN_PWR_CTRL_UP; | |
842 } else if (screen_is_off && skb && ar->arConnected) { | |
843 A_BOOL needWake = FALSE; | 366 A_BOOL needWake = FALSE; |
844 if (isEvent) { | 367 if (isEvent) { |
845 if (A_NETBUF_LEN(skb) >= sizeof(A_UINT16)) { | 368 if (A_NETBUF_LEN(skb) >= sizeof(A_UINT16)) { |
846 A_UINT16 cmd = *(const A_UINT16 *)A_NETBUF_DATA(skb); | 369 A_UINT16 cmd = *(const A_UINT16 *)A_NETBUF_DATA(skb); |
847 switch (cmd) { | 370 switch (cmd) { |
848 case WMI_CONNECT_EVENTID: | 371 case WMI_CONNECT_EVENTID: |
849 case WMI_DISCONNECT_EVENTID: | 372 case WMI_DISCONNECT_EVENTID: |
850 needWake = TRUE; | 373 needWake = TRUE; |
851 break; | 374 break; |
852 default: | 375 default: |
(...skipping 12 matching lines...) Expand all Loading... |
865 needWake = TRUE; | 388 needWake = TRUE; |
866 break; | 389 break; |
867 case 0x0806: /* ARP is not important to hold wake lock */ | 390 case 0x0806: /* ARP is not important to hold wake lock */ |
868 default: | 391 default: |
869 break; | 392 break; |
870 } | 393 } |
871 } | 394 } |
872 } | 395 } |
873 if (needWake) { | 396 if (needWake) { |
874 /* keep host wake up if there is any event and packate comming in*/ | 397 /* keep host wake up if there is any event and packate comming in*/ |
| 398 #ifdef CONFIG_HAS_WAKELOCK |
875 wake_lock_timeout(&ar6k_wow_wake_lock, 3*HZ); | 399 wake_lock_timeout(&ar6k_wow_wake_lock, 3*HZ); |
| 400 #endif |
876 if (wowledon) { | 401 if (wowledon) { |
877 char buf[32]; | 402 char buf[32]; |
878 int len = sprintf(buf, "on"); | 403 int len = sprintf(buf, "on"); |
879 android_readwrite_file("/sys/power/state", NULL, buf, len); | 404 android_readwrite_file("/sys/power/state", NULL, buf, len); |
880 | 405 |
881 len = sprintf(buf, "%d", 127); | 406 len = sprintf(buf, "%d", 127); |
882 android_readwrite_file("/sys/class/leds/lcd-backlight/brightness
", | 407 android_readwrite_file("/sys/class/leds/lcd-backlight/brightness
", |
883 NULL, buf,len); | 408 NULL, buf,len); |
884 } | 409 } |
885 } | 410 } |
886 } | 411 } |
| 412 } |
887 #endif /* CONFIG_PM */ | 413 #endif /* CONFIG_PM */ |
888 } | |
889 | |
890 A_STATUS android_ar6k_start(AR_SOFTC_T *ar) | |
891 { | |
892 if (!bypasswmi) { | |
893 #ifdef ATH6K_CONFIG_OTA_MODE | |
894 wmi_powermode_cmd(ar->arWmi, MAX_PERF_POWER); | |
895 #endif | |
896 wmi_disctimeout_cmd(ar->arWmi, 3); | |
897 | |
898 } | |
899 return A_OK; | |
900 } | |
OLD | NEW |