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