1 /* 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 <pthread.h> 20 #include <semaphore.h> 21 #include <stddef.h> 22 #include <string.h> 23 #include <sys/stat.h> 24 #include <sys/types.h> 25 #include <unistd.h> 26 27 #define LOG_TAG "libsuspend" 28 //#define LOG_NDEBUG 0 29 #include <cutils/log.h> 30 31 #include "autosuspend_ops.h" 32 33 #define SYS_POWER_STATE "/sys/power/state" 34 #define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count" 35 36 static int state_fd; 37 static int wakeup_count_fd; 38 static pthread_t suspend_thread; 39 static sem_t suspend_lockout; 40 static const char *sleep_state = "mem"; 41 static void (*wakeup_func)(void) = NULL; 42 43 static void *suspend_thread_func(void *arg __attribute__((unused))) 44 { 45 char buf[80]; 46 char wakeup_count[20]; 47 int wakeup_count_len; 48 int ret; 49 50 while (1) { 51 usleep(100000); 52 ALOGV("%s: read wakeup_count\n", __func__); 53 lseek(wakeup_count_fd, 0, SEEK_SET); 54 wakeup_count_len = read(wakeup_count_fd, wakeup_count, sizeof(wakeup_count)); 55 if (wakeup_count_len < 0) { 56 strerror_r(errno, buf, sizeof(buf)); 57 ALOGE("Error reading from %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf); 58 wakeup_count_len = 0; 59 continue; 60 } 61 if (!wakeup_count_len) { 62 ALOGE("Empty wakeup count\n"); 63 continue; 64 } 65 66 ALOGV("%s: wait\n", __func__); 67 ret = sem_wait(&suspend_lockout); 68 if (ret < 0) { 69 strerror_r(errno, buf, sizeof(buf)); 70 ALOGE("Error waiting on semaphore: %s\n", buf); 71 continue; 72 } 73 74 ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count); 75 ret = write(wakeup_count_fd, wakeup_count, wakeup_count_len); 76 if (ret < 0) { 77 strerror_r(errno, buf, sizeof(buf)); 78 ALOGE("Error writing to %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf); 79 } else { 80 ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE); 81 ret = write(state_fd, sleep_state, strlen(sleep_state)); 82 if (ret < 0) { 83 strerror_r(errno, buf, sizeof(buf)); 84 ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf); 85 } else { 86 void (*func)(void) = wakeup_func; 87 if (func != NULL) { 88 (*func)(); 89 } 90 } 91 } 92 93 ALOGV("%s: release sem\n", __func__); 94 ret = sem_post(&suspend_lockout); 95 if (ret < 0) { 96 strerror_r(errno, buf, sizeof(buf)); 97 ALOGE("Error releasing semaphore: %s\n", buf); 98 } 99 } 100 return NULL; 101 } 102 103 static int autosuspend_wakeup_count_enable(void) 104 { 105 char buf[80]; 106 int ret; 107 108 ALOGV("autosuspend_wakeup_count_enable\n"); 109 110 ret = sem_post(&suspend_lockout); 111 112 if (ret < 0) { 113 strerror_r(errno, buf, sizeof(buf)); 114 ALOGE("Error changing semaphore: %s\n", buf); 115 } 116 117 ALOGV("autosuspend_wakeup_count_enable done\n"); 118 119 return ret; 120 } 121 122 static int autosuspend_wakeup_count_disable(void) 123 { 124 char buf[80]; 125 int ret; 126 127 ALOGV("autosuspend_wakeup_count_disable\n"); 128 129 ret = sem_wait(&suspend_lockout); 130 131 if (ret < 0) { 132 strerror_r(errno, buf, sizeof(buf)); 133 ALOGE("Error changing semaphore: %s\n", buf); 134 } 135 136 ALOGV("autosuspend_wakeup_count_disable done\n"); 137 138 return ret; 139 } 140 141 void set_wakeup_callback(void (*func)(void)) 142 { 143 if (wakeup_func != NULL) { 144 ALOGE("Duplicate wakeup callback applied, keeping original"); 145 return; 146 } 147 wakeup_func = func; 148 } 149 150 struct autosuspend_ops autosuspend_wakeup_count_ops = { 151 .enable = autosuspend_wakeup_count_enable, 152 .disable = autosuspend_wakeup_count_disable, 153 }; 154 155 struct autosuspend_ops *autosuspend_wakeup_count_init(void) 156 { 157 int ret; 158 char buf[80]; 159 160 state_fd = open(SYS_POWER_STATE, O_RDWR); 161 if (state_fd < 0) { 162 strerror_r(errno, buf, sizeof(buf)); 163 ALOGE("Error opening %s: %s\n", SYS_POWER_STATE, buf); 164 goto err_open_state; 165 } 166 167 wakeup_count_fd = open(SYS_POWER_WAKEUP_COUNT, O_RDWR); 168 if (wakeup_count_fd < 0) { 169 strerror_r(errno, buf, sizeof(buf)); 170 ALOGE("Error opening %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf); 171 goto err_open_wakeup_count; 172 } 173 174 ret = sem_init(&suspend_lockout, 0, 0); 175 if (ret < 0) { 176 strerror_r(errno, buf, sizeof(buf)); 177 ALOGE("Error creating semaphore: %s\n", buf); 178 goto err_sem_init; 179 } 180 ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL); 181 if (ret) { 182 strerror_r(ret, buf, sizeof(buf)); 183 ALOGE("Error creating thread: %s\n", buf); 184 goto err_pthread_create; 185 } 186 187 ALOGI("Selected wakeup count\n"); 188 return &autosuspend_wakeup_count_ops; 189 190 err_pthread_create: 191 sem_destroy(&suspend_lockout); 192 err_sem_init: 193 close(wakeup_count_fd); 194 err_open_wakeup_count: 195 close(state_fd); 196 err_open_state: 197 return NULL; 198 } 199