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