1a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross/* 2a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * Copyright (C) 2012 The Android Open Source Project 3a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * 4a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * Licensed under the Apache License, Version 2.0 (the "License"); 5a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * you may not use this file except in compliance with the License. 6a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * You may obtain a copy of the License at 7a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * 8a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * http://www.apache.org/licenses/LICENSE-2.0 9a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * 10a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * Unless required by applicable law or agreed to in writing, software 11a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * distributed under the License is distributed on an "AS IS" BASIS, 12a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * See the License for the specific language governing permissions and 14a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross * limitations under the License. 15a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross */ 16a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 17a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <errno.h> 18a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <fcntl.h> 19a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <pthread.h> 20a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <semaphore.h> 21a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <stddef.h> 22a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <string.h> 23a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <sys/stat.h> 24a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <sys/types.h> 25a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <unistd.h> 26a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 27a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#define LOG_TAG "libsuspend" 289552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn//#define LOG_NDEBUG 0 29a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <cutils/log.h> 30a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 31a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include "autosuspend_ops.h" 32a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 33a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#define SYS_POWER_STATE "/sys/power/state" 34a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count" 35a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 36a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic int state_fd; 37a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic int wakeup_count_fd; 38a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic pthread_t suspend_thread; 39a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic sem_t suspend_lockout; 40a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic const char *sleep_state = "mem"; 419552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackbornstatic void (*wakeup_func)(void) = NULL; 42a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 4362f9ffac1aa4809c0acd29dc4c4872a3b4da2062Edwin Vanestatic void *suspend_thread_func(void *arg __attribute__((unused))) 44a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross{ 45a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char buf[80]; 46a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char wakeup_count[20]; 47a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int wakeup_count_len; 48a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int ret; 49a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 50a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross while (1) { 51a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross usleep(100000); 52a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: read wakeup_count\n", __func__); 53a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross lseek(wakeup_count_fd, 0, SEEK_SET); 54a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross wakeup_count_len = read(wakeup_count_fd, wakeup_count, sizeof(wakeup_count)); 55a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (wakeup_count_len < 0) { 56a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 57a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error reading from %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf); 58a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross wakeup_count_len = 0; 59a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross continue; 60a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 61a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (!wakeup_count_len) { 62a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Empty wakeup count\n"); 63a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross continue; 64a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 65a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 66a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: wait\n", __func__); 67a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_wait(&suspend_lockout); 68a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 69a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 70a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error waiting on semaphore: %s\n", buf); 71a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross continue; 72a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 73a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 74a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count); 75a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = write(wakeup_count_fd, wakeup_count, wakeup_count_len); 76a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 77a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 78a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error writing to %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf); 79a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } else { 80a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE); 81a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = write(state_fd, sleep_state, strlen(sleep_state)); 82a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 83a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 84a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf); 859552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn } else { 869552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn void (*func)(void) = wakeup_func; 879552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn if (func != NULL) { 889552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn (*func)(); 899552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn } 90a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 91a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 92a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 93a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: release sem\n", __func__); 94a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_post(&suspend_lockout); 95a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 96a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 97a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error releasing semaphore: %s\n", buf); 98a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 99a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 100a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return NULL; 101a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross} 102a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 103a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic int autosuspend_wakeup_count_enable(void) 104a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross{ 105a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char buf[80]; 106a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int ret; 107a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 108a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("autosuspend_wakeup_count_enable\n"); 109a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 110a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_post(&suspend_lockout); 111a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 112a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 113a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 114a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error changing semaphore: %s\n", buf); 115a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 116a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 117a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("autosuspend_wakeup_count_enable done\n"); 118a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 119a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return ret; 120a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross} 121a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 122a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic int autosuspend_wakeup_count_disable(void) 123a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross{ 124a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char buf[80]; 125a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int ret; 126a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 127a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("autosuspend_wakeup_count_disable\n"); 128a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 129a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_wait(&suspend_lockout); 130a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 131a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 132a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 133a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error changing semaphore: %s\n", buf); 134a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 135a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 136a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("autosuspend_wakeup_count_disable done\n"); 137a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 138a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return ret; 139a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross} 140a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 1419552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackbornvoid set_wakeup_callback(void (*func)(void)) 1429552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn{ 1439552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn if (wakeup_func != NULL) { 1449552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn ALOGE("Duplicate wakeup callback applied, keeping original"); 1459552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn return; 1469552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn } 1479552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn wakeup_func = func; 1489552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn} 1499552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn 150a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstruct autosuspend_ops autosuspend_wakeup_count_ops = { 151a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross .enable = autosuspend_wakeup_count_enable, 152a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross .disable = autosuspend_wakeup_count_disable, 153a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross}; 154a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 155a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstruct autosuspend_ops *autosuspend_wakeup_count_init(void) 156a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross{ 157a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int ret; 158a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char buf[80]; 159a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 160a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross state_fd = open(SYS_POWER_STATE, O_RDWR); 161a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (state_fd < 0) { 162a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 163a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error opening %s: %s\n", SYS_POWER_STATE, buf); 164a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross goto err_open_state; 165a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 166a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 167a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross wakeup_count_fd = open(SYS_POWER_WAKEUP_COUNT, O_RDWR); 168a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (wakeup_count_fd < 0) { 169a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 170a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error opening %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf); 171a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross goto err_open_wakeup_count; 172a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 173a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 174a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_init(&suspend_lockout, 0, 0); 175a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 176a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 177a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error creating semaphore: %s\n", buf); 178a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross goto err_sem_init; 179a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 180a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL); 181a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret) { 182a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(ret, buf, sizeof(buf)); 183a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error creating thread: %s\n", buf); 184a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross goto err_pthread_create; 185a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 186a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 187a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGI("Selected wakeup count\n"); 188a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return &autosuspend_wakeup_count_ops; 189a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 190a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crosserr_pthread_create: 191a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross sem_destroy(&suspend_lockout); 192a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crosserr_sem_init: 193a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross close(wakeup_count_fd); 194a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crosserr_open_wakeup_count: 195a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross close(state_fd); 196a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crosserr_open_state: 197a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return NULL; 198a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross} 199