/* * Copyright (C) 2016 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "PowerHAL" #include #include #include #include #include #include #include #include #include "power.h" #define CPUFREQ_PATH "/sys/devices/system/cpu/cpu0/cpufreq/" #define INTERACTIVE_PATH "/sys/devices/system/cpu/cpufreq/interactive/" /* touchkeys */ #define TK_POWER "/sys/class/input/input1/enabled" /* touchscreen */ #define TS_POWER "/sys/class/input/input2/enabled" static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; static int boostpulse_fd = -1; // Balanced profile by default static int current_power_profile = 1; static int requested_power_profile = -1; static int sysfs_write_str(char *path, char *s) { char buf[80]; int len; int ret = 0; int fd; fd = open(path, O_WRONLY); if (fd < 0) { strerror_r(errno, buf, sizeof(buf)); ALOGE("Error opening %s: %s\n", path, buf); return -1 ; } len = write(fd, s, strlen(s)); if (len < 0) { strerror_r(errno, buf, sizeof(buf)); ALOGE("Error writing to %s: %s\n", path, buf); ret = -1; } close(fd); return ret; } static int sysfs_write_int(char *path, int value) { char buf[80]; snprintf(buf, 80, "%d", value); return sysfs_write_str(path, buf); } static int is_profile_valid(int profile) { return profile >= 0 && profile < PROFILE_MAX; } static void power_init(__attribute__((unused)) struct power_module *module) { ALOGI("%s", __func__); } static int boostpulse_open() { pthread_mutex_lock(&lock); if (boostpulse_fd < 0) { boostpulse_fd = open(INTERACTIVE_PATH "boostpulse", O_WRONLY); } pthread_mutex_unlock(&lock); return boostpulse_fd; } static void power_set_interactive_ext(int on) { ALOGD("%s: %s input devices", __func__, on ? "enabling" : "disabling"); sysfs_write_str(TK_POWER, on ? "1" : "0"); sysfs_write_str(TS_POWER, on ? "1" : "0"); } static void power_set_interactive(__attribute__((unused)) struct power_module *module, int on) { /* We want to first set the input device state otherwise * it never gets turned off/on when our HAL isnt compatible with the power_profiles from * our framework */ power_set_interactive_ext(on); } static void set_power_profile(__attribute__((unused)) int profile) { return; } static void power_hint(__attribute__((unused)) struct power_module *module, power_hint_t hint, void *data) { char buf[80]; int len; switch (hint) { case POWER_HINT_INTERACTION: case POWER_HINT_SET_PROFILE: pthread_mutex_lock(&lock); set_power_profile(*(int32_t *)data); pthread_mutex_unlock(&lock); break; case POWER_HINT_LOW_POWER: /* This hint is handled by the framework */ break; default: break; } } static int get_feature(__attribute__((unused)) struct power_module *module, feature_t feature) { if (feature == POWER_FEATURE_SUPPORTED_PROFILES) { return PROFILE_MAX; } return -1; } static int power_open(const hw_module_t* module, const char* name, hw_device_t** device) { ALOGD("%s: enter; name=%s", __FUNCTION__, name); if (strcmp(name, POWER_HARDWARE_MODULE_ID)) { return -EINVAL; } power_module_t *dev = (power_module_t *)calloc(1, sizeof(power_module_t)); if (!dev) { ALOGD("%s: failed to allocate memory", __FUNCTION__); return -ENOMEM; } dev->common.tag = HARDWARE_MODULE_TAG; dev->common.module_api_version = POWER_MODULE_API_VERSION_0_2; dev->common.hal_api_version = HARDWARE_HAL_API_VERSION; dev->init = power_init; dev->powerHint = power_hint; // This is handled by framework dev->setInteractive = power_set_interactive; dev->getFeature = get_feature; *device = (hw_device_t*)dev; ALOGD("%s: exit", __FUNCTION__); return 0; } static struct hw_module_methods_t power_module_methods = { .open = power_open, }; struct power_module HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = POWER_MODULE_API_VERSION_0_2, .hal_api_version = HARDWARE_HAL_API_VERSION, .id = POWER_HARDWARE_MODULE_ID, .name = "MSM8226 Power HAL", .author = "The LineageOS Project", .methods = &power_module_methods, }, .init = power_init, .setInteractive = power_set_interactive, .powerHint = power_hint, .getFeature = get_feature };