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 1766ce3e08c5632a20ea66bde6dd76397041edf034Mark Salyzyn#define LOG_TAG "libsuspend" 1866ce3e08c5632a20ea66bde6dd76397041edf034Mark Salyzyn//#define LOG_NDEBUG 0 1966ce3e08c5632a20ea66bde6dd76397041edf034Mark Salyzyn 20a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <errno.h> 21a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <fcntl.h> 22a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <pthread.h> 23a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <semaphore.h> 24a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <stddef.h> 25d3027d85f30a13d03e2c58c009215bf0b48f9ac9Ruchi Kandoi#include <stdbool.h> 26a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <string.h> 27a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <sys/stat.h> 28a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <sys/types.h> 29a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include <unistd.h> 30a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 3130f991f251940be3ed11566fb71139852286f68aMark Salyzyn#include <log/log.h> 32a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 33a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#include "autosuspend_ops.h" 34a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 35a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#define SYS_POWER_STATE "/sys/power/state" 36a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross#define SYS_POWER_WAKEUP_COUNT "/sys/power/wakeup_count" 37a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 38a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic int state_fd; 39a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic int wakeup_count_fd; 40a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic pthread_t suspend_thread; 41a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic sem_t suspend_lockout; 42a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic const char *sleep_state = "mem"; 43d3027d85f30a13d03e2c58c009215bf0b48f9ac9Ruchi Kandoistatic void (*wakeup_func)(bool success) = NULL; 44a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 4562f9ffac1aa4809c0acd29dc4c4872a3b4da2062Edwin Vanestatic void *suspend_thread_func(void *arg __attribute__((unused))) 46a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross{ 47a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char buf[80]; 48a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char wakeup_count[20]; 49a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int wakeup_count_len; 50a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int ret; 5123c8bab0243bc6e7be8b95702c262c354009d56aTim Murray bool success; 52a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 53a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross while (1) { 5423c8bab0243bc6e7be8b95702c262c354009d56aTim Murray usleep(100000); 55a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: read wakeup_count\n", __func__); 56a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross lseek(wakeup_count_fd, 0, SEEK_SET); 570446e16f5333977810dec3a33c1af89d1f61d2deJeff Brown wakeup_count_len = TEMP_FAILURE_RETRY(read(wakeup_count_fd, wakeup_count, 580446e16f5333977810dec3a33c1af89d1f61d2deJeff Brown sizeof(wakeup_count))); 59a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (wakeup_count_len < 0) { 60a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 61a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error reading from %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf); 62a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross wakeup_count_len = 0; 63a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross continue; 64a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 65a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (!wakeup_count_len) { 66a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Empty wakeup count\n"); 67a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross continue; 68a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 69a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 70a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: wait\n", __func__); 71a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_wait(&suspend_lockout); 72a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 73a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 74a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error waiting on semaphore: %s\n", buf); 75a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross continue; 76a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 77a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 7823c8bab0243bc6e7be8b95702c262c354009d56aTim Murray success = true; 79a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: write %*s to wakeup_count\n", __func__, wakeup_count_len, wakeup_count); 800446e16f5333977810dec3a33c1af89d1f61d2deJeff Brown ret = TEMP_FAILURE_RETRY(write(wakeup_count_fd, wakeup_count, wakeup_count_len)); 81a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 82a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 83a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error writing to %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf); 84a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } else { 85a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: write %s to %s\n", __func__, sleep_state, SYS_POWER_STATE); 860446e16f5333977810dec3a33c1af89d1f61d2deJeff Brown ret = TEMP_FAILURE_RETRY(write(state_fd, sleep_state, strlen(sleep_state))); 8723c8bab0243bc6e7be8b95702c262c354009d56aTim Murray if (ret < 0) { 8823c8bab0243bc6e7be8b95702c262c354009d56aTim Murray success = false; 89d3027d85f30a13d03e2c58c009215bf0b48f9ac9Ruchi Kandoi } 90d3027d85f30a13d03e2c58c009215bf0b48f9ac9Ruchi Kandoi void (*func)(bool success) = wakeup_func; 91d3027d85f30a13d03e2c58c009215bf0b48f9ac9Ruchi Kandoi if (func != NULL) { 92d3027d85f30a13d03e2c58c009215bf0b48f9ac9Ruchi Kandoi (*func)(success); 93a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 94a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 95a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 96a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("%s: release sem\n", __func__); 97a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_post(&suspend_lockout); 98a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 99a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 100a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error releasing semaphore: %s\n", buf); 101a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 102a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 103a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return NULL; 104a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross} 105a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 106a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic int autosuspend_wakeup_count_enable(void) 107a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross{ 108a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char buf[80]; 109a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int ret; 110a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 111a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("autosuspend_wakeup_count_enable\n"); 112a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 113a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_post(&suspend_lockout); 114a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 115a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 116a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 117a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error changing semaphore: %s\n", buf); 118a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 119a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 120a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("autosuspend_wakeup_count_enable done\n"); 121a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 122a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return ret; 123a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross} 124a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 125a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstatic int autosuspend_wakeup_count_disable(void) 126a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross{ 127a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char buf[80]; 128a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int ret; 129a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 130a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("autosuspend_wakeup_count_disable\n"); 131a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 132a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_wait(&suspend_lockout); 133a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 134a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 135a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 136a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error changing semaphore: %s\n", buf); 137a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 138a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 139a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGV("autosuspend_wakeup_count_disable done\n"); 140a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 141a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return ret; 142a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross} 143a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 144d3027d85f30a13d03e2c58c009215bf0b48f9ac9Ruchi Kandoivoid set_wakeup_callback(void (*func)(bool success)) 1459552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn{ 1469552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn if (wakeup_func != NULL) { 1479552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn ALOGE("Duplicate wakeup callback applied, keeping original"); 1489552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn return; 1499552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn } 1509552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn wakeup_func = func; 1519552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn} 1529552cdf434ac1c9ff8730f5492d649845ad4f86cDianne Hackborn 153a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstruct autosuspend_ops autosuspend_wakeup_count_ops = { 154a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross .enable = autosuspend_wakeup_count_enable, 155a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross .disable = autosuspend_wakeup_count_disable, 156a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross}; 157a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 158a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crossstruct autosuspend_ops *autosuspend_wakeup_count_init(void) 159a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross{ 160a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross int ret; 161a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross char buf[80]; 162a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 1630446e16f5333977810dec3a33c1af89d1f61d2deJeff Brown state_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_STATE, O_RDWR)); 164a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (state_fd < 0) { 165a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 166a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error opening %s: %s\n", SYS_POWER_STATE, buf); 167a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross goto err_open_state; 168a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 169a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 1700446e16f5333977810dec3a33c1af89d1f61d2deJeff Brown wakeup_count_fd = TEMP_FAILURE_RETRY(open(SYS_POWER_WAKEUP_COUNT, O_RDWR)); 171a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (wakeup_count_fd < 0) { 172a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 173a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error opening %s: %s\n", SYS_POWER_WAKEUP_COUNT, buf); 174a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross goto err_open_wakeup_count; 175a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 176a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 177a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = sem_init(&suspend_lockout, 0, 0); 178a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret < 0) { 179a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(errno, buf, sizeof(buf)); 180a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error creating semaphore: %s\n", buf); 181a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross goto err_sem_init; 182a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 183a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ret = pthread_create(&suspend_thread, NULL, suspend_thread_func, NULL); 184a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross if (ret) { 185a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross strerror_r(ret, buf, sizeof(buf)); 186a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGE("Error creating thread: %s\n", buf); 187a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross goto err_pthread_create; 188a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross } 189a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 190a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross ALOGI("Selected wakeup count\n"); 191a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return &autosuspend_wakeup_count_ops; 192a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross 193a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crosserr_pthread_create: 194a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross sem_destroy(&suspend_lockout); 195a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crosserr_sem_init: 196a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross close(wakeup_count_fd); 197a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crosserr_open_wakeup_count: 198a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross close(state_fd); 199a2582c2c4d20684b21aaf50913a27239789bf5ebColin Crosserr_open_state: 200a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross return NULL; 201a2582c2c4d20684b21aaf50913a27239789bf5ebColin Cross} 202