blob: b4401284c10a5e3620ae4ba1a0d1c86465c016b3 [file] [log] [blame]
Colin Crossa2582c22012-05-03 17:30:16 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <fcntl.h>
19#include <stddef.h>
20#include <string.h>
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <unistd.h>
24
25#define LOG_TAG "libsuspend"
26#include <cutils/log.h>
27
28#include "autosuspend_ops.h"
29
30#define EARLYSUSPEND_SYS_POWER_STATE "/sys/power/state"
31#define EARLYSUSPEND_WAIT_FOR_FB_SLEEP "/sys/power/wait_for_fb_sleep"
32#define EARLYSUSPEND_WAIT_FOR_FB_WAKE "/sys/power/wait_for_fb_wake"
33
34
35static int sPowerStatefd;
36static const char *pwr_state_mem = "mem";
37static const char *pwr_state_on = "on";
Colin Cross2146b7f2012-06-07 14:12:54 -070038static pthread_t earlysuspend_thread;
Colin Crossa2582c22012-05-03 17:30:16 -070039
Colin Cross2146b7f2012-06-07 14:12:54 -070040int wait_for_fb_wake(void)
41{
42 int err = 0;
43 char buf;
44 int fd = open(EARLYSUSPEND_WAIT_FOR_FB_WAKE, O_RDONLY, 0);
45 // if the file doesn't exist, the error will be caught in read() below
46 do {
47 err = read(fd, &buf, 1);
48 } while (err < 0 && errno == EINTR);
49 ALOGE_IF(err < 0,
50 "*** ANDROID_WAIT_FOR_FB_WAKE failed (%s)", strerror(errno));
51 close(fd);
52 return err < 0 ? err : 0;
53}
54
55static int wait_for_fb_sleep(void)
56{
57 int err = 0;
58 char buf;
59 int fd = open(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, O_RDONLY, 0);
60 // if the file doesn't exist, the error will be caught in read() below
61 do {
62 err = read(fd, &buf, 1);
63 } while (err < 0 && errno == EINTR);
64 ALOGE_IF(err < 0,
65 "*** ANDROID_WAIT_FOR_FB_SLEEP failed (%s)", strerror(errno));
66 close(fd);
67 return err < 0 ? err : 0;
68}
69
70static void *earlysuspend_thread_func(void *arg)
71{
72 char buf[80];
73 char wakeup_count[20];
74 int wakeup_count_len;
75 int ret;
76
77 while (1) {
78 if (wait_for_fb_sleep()) {
79 ALOGE("Failed reading wait_for_fb_sleep, exiting earlysuspend thread\n");
80 return NULL;
81 }
82 if (wait_for_fb_wake()) {
83 ALOGE("Failed reading wait_for_fb_wake, exiting earlysuspend thread\n");
84 return NULL;
85 }
86 }
87}
Colin Crossa2582c22012-05-03 17:30:16 -070088static int autosuspend_earlysuspend_enable(void)
89{
90 char buf[80];
91 int ret;
92
93 ALOGV("autosuspend_earlysuspend_enable\n");
94
95 ret = write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));
96 if (ret < 0) {
97 strerror_r(errno, buf, sizeof(buf));
98 ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
99 goto err;
100 }
101
102 ALOGV("autosuspend_earlysuspend_enable done\n");
103
104 return 0;
105
106err:
107 return ret;
108}
109
110static int autosuspend_earlysuspend_disable(void)
111{
112 char buf[80];
113 int ret;
114
115 ALOGV("autosuspend_earlysuspend_disable\n");
116
117 ret = write(sPowerStatefd, pwr_state_on, strlen(pwr_state_on));
118 if (ret < 0) {
119 strerror_r(errno, buf, sizeof(buf));
120 ALOGE("Error writing to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
121 goto err;
122 }
123
124 ALOGV("autosuspend_earlysuspend_disable done\n");
125
126 return 0;
127
128err:
129 return ret;
130}
131
132struct autosuspend_ops autosuspend_earlysuspend_ops = {
133 .enable = autosuspend_earlysuspend_enable,
134 .disable = autosuspend_earlysuspend_disable,
135};
136
Colin Cross2146b7f2012-06-07 14:12:54 -0700137void start_earlysuspend_thread(void)
Colin Crossa2582c22012-05-03 17:30:16 -0700138{
139 char buf[80];
140 int ret;
141
142 ret = access(EARLYSUSPEND_WAIT_FOR_FB_SLEEP, F_OK);
143 if (ret < 0) {
Colin Cross2146b7f2012-06-07 14:12:54 -0700144 return;
Colin Crossa2582c22012-05-03 17:30:16 -0700145 }
146
147 ret = access(EARLYSUSPEND_WAIT_FOR_FB_WAKE, F_OK);
148 if (ret < 0) {
Colin Cross2146b7f2012-06-07 14:12:54 -0700149 return;
Colin Crossa2582c22012-05-03 17:30:16 -0700150 }
151
Colin Cross2146b7f2012-06-07 14:12:54 -0700152 ALOGI("Starting early suspend unblocker thread\n");
153 ret = pthread_create(&earlysuspend_thread, NULL, earlysuspend_thread_func, NULL);
154 if (ret) {
155 strerror_r(ret, buf, sizeof(buf));
156 ALOGE("Error creating thread: %s\n", buf);
157 }
158}
159
160struct autosuspend_ops *autosuspend_earlysuspend_init(void)
161{
162 char buf[80];
163 int ret;
164
Colin Crossa2582c22012-05-03 17:30:16 -0700165 sPowerStatefd = open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR);
166
167 if (sPowerStatefd < 0) {
168 strerror_r(errno, buf, sizeof(buf));
Colin Cross2146b7f2012-06-07 14:12:54 -0700169 ALOGW("Error opening %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
Colin Crossa2582c22012-05-03 17:30:16 -0700170 return NULL;
171 }
172
Colin Cross2146b7f2012-06-07 14:12:54 -0700173 ret = write(sPowerStatefd, "on", 2);
174 if (ret < 0) {
175 strerror_r(errno, buf, sizeof(buf));
176 ALOGW("Error writing 'on' to %s: %s\n", EARLYSUSPEND_SYS_POWER_STATE, buf);
177 goto err_write;
178 }
179
Colin Crossa2582c22012-05-03 17:30:16 -0700180 ALOGI("Selected early suspend\n");
Colin Cross2146b7f2012-06-07 14:12:54 -0700181
182 start_earlysuspend_thread();
183
Colin Crossa2582c22012-05-03 17:30:16 -0700184 return &autosuspend_earlysuspend_ops;
Colin Cross2146b7f2012-06-07 14:12:54 -0700185
186err_write:
187 close(sPowerStatefd);
188 return NULL;
Colin Crossa2582c22012-05-03 17:30:16 -0700189}