charger.c revision 1a5ca61b28b3269b625b7a7162b4f50734f7fea9
1f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin/* 2f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * Copyright (C) 2011 The Android Open Source Project 3f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * 4f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * Licensed under the Apache License, Version 2.0 (the "License"); 5f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * you may not use this file except in compliance with the License. 6f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * You may obtain a copy of the License at 7f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * 8f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * http://www.apache.org/licenses/LICENSE-2.0 9f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * 10f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * Unless required by applicable law or agreed to in writing, software 11f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * distributed under the License is distributed on an "AS IS" BASIS, 12f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * See the License for the specific language governing permissions and 14f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * limitations under the License. 15f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin */ 16f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 17f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin//#define DEBUG_UEVENTS 18f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define CHARGER_KLOG_LEVEL 6 19f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 20f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <dirent.h> 21f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <errno.h> 22f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <fcntl.h> 23f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <linux/input.h> 24f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <linux/netlink.h> 25f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <stdbool.h> 26f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <stdio.h> 27f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <stdlib.h> 28f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <string.h> 29f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <sys/poll.h> 30f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <sys/socket.h> 31f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <sys/stat.h> 32f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <sys/types.h> 33f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <sys/un.h> 34f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <time.h> 35f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <unistd.h> 36f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 37f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <cutils/android_reboot.h> 38f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <cutils/klog.h> 39f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <cutils/list.h> 40f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include <cutils/uevent.h> 41f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 42f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#include "minui/minui.h" 43f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 44f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#ifndef max 45f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define max(a,b) ((a) > (b) ? (a) : (b)) 46f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#endif 47f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 48f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#ifndef min 49f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define min(a,b) ((a) < (b) ? (a) : (b)) 50f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#endif 51f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 520052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) 530052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 54f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define MSEC_PER_SEC (1000LL) 55f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define NSEC_PER_MSEC (1000000LL) 56f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 570052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC) 5892312a515b0b877deed5dfdbf9d7613e8d66fee5Dima Zavin#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC) 59f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC) 60f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 611a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin#define BATTERY_FULL_THRESH 95 621a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin 63f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0) 64f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0) 65f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0) 66f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 67f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstruct key_state { 68f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin bool pending; 69f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin bool down; 70f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t timestamp; 71f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}; 72f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 73f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstruct power_supply { 74f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct listnode list; 75f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin char name[256]; 76f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin char type[32]; 77f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin bool online; 78f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin bool valid; 790052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin char cap_path[PATH_MAX]; 800052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}; 810052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 820052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstruct frame { 830052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin const char *name; 840052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int disp_time; 850052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int min_capacity; 860052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 870052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin gr_surface surface; 880052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}; 890052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 900052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstruct animation { 910052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin bool run; 920052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 930052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin struct frame *frames; 940052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int cur_frame; 950052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int num_frames; 960052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 970052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int cur_cycle; 980052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int num_cycles; 990052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 1000052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* current capacity being animated */ 1010052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int capacity; 102f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}; 103f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 104f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstruct charger { 105f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t next_screen_transition; 106f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t next_key_check; 107f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t next_pwr_check; 108f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 109f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct key_state keys[KEY_MAX + 1]; 110f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int uevent_fd; 111f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 112f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct listnode supplies; 113f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int num_supplies; 114f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int num_supplies_online; 115f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 1160052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin struct animation *batt_anim; 1170052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin gr_surface surf_unknown; 1180052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 119f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct power_supply *battery; 120f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}; 121f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 122f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstruct uevent { 123f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin const char *action; 124f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin const char *path; 125f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin const char *subsystem; 126f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin const char *ps_name; 127f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin const char *ps_type; 128f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin const char *ps_online; 129f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}; 130f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 1310052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic struct frame batt_anim_frames[] = { 1320052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin { 1330052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .name = "charger/battery_0", 1340052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .disp_time = 750, 1350052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .min_capacity = 0, 1360052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin }, 1370052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin { 1380052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .name = "charger/battery_1", 1390052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .disp_time = 750, 1400052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .min_capacity = 20, 1410052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin }, 1420052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin { 1430052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .name = "charger/battery_2", 1440052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .disp_time = 750, 1450052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .min_capacity = 40, 1460052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin }, 1470052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin { 1480052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .name = "charger/battery_3", 1490052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .disp_time = 750, 1500052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .min_capacity = 60, 1510052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin }, 1520052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin { 1530052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .name = "charger/battery_4", 1540052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .disp_time = 750, 1550052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .min_capacity = 80, 1560052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin }, 1571a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin { 1581a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin .name = "charger/battery_5", 1591a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin .disp_time = 750, 1601a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin .min_capacity = BATTERY_FULL_THRESH, 1611a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin }, 1620052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}; 1630052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 1640052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic struct animation battery_animation = { 1650052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .frames = batt_anim_frames, 1660052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .num_frames = ARRAY_SIZE(batt_anim_frames), 1670052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .num_cycles = 3, 1680052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}; 1690052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 1700052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic struct charger charger_state = { 1710052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin .batt_anim = &battery_animation, 1720052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin}; 1730052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 174f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int char_width; 175f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int char_height; 176f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 177f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin/* current time in milliseconds */ 178f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int64_t curr_time_ms(void) 179f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 180f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct timespec tm; 181f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin clock_gettime(CLOCK_MONOTONIC, &tm); 182f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC); 183f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 184f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 185f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void clear_screen(void) 186f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 187f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin gr_color(0, 0, 0, 255); 188f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin gr_fill(0, 0, gr_fb_width(), gr_fb_height()); 189f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin}; 190f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 191f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int read_file(const char *path, char *buf, size_t sz) 192f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 193f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int fd; 194f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin size_t cnt; 195f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 196f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin fd = open(path, O_RDONLY, 0); 197f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (fd < 0) 198f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin goto err; 199f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 200f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin cnt = read(fd, buf, sz - 1); 201f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (cnt <= 0) 202f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin goto err; 203f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin buf[cnt] = '\0'; 204f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (buf[cnt - 1] == '\n') { 205f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin cnt--; 206f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin buf[cnt] = '\0'; 207f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 208f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 209f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin close(fd); 210f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return cnt; 211f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 212f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinerr: 213f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (fd >= 0) 214f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin close(fd); 215f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return -1; 216f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 217f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 218f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int read_file_int(const char *path, int *val) 219f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 220f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin char buf[32]; 221f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int ret; 222f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int tmp; 223f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin char *end; 224f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 225f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ret = read_file(path, buf, sizeof(buf)); 226f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (ret < 0) 227f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return -1; 228f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 229f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin tmp = strtol(buf, &end, 0); 230f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (end == buf || 231f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ((end < buf+sizeof(buf)) && (*end != '\n' && *end != '\0'))) 232f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin goto err; 233f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 234f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin *val = tmp; 235f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return 0; 236f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 237f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinerr: 238f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return -1; 239f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 240f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 2411a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavinstatic int get_battery_capacity(struct charger *charger) 2421a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin{ 2431a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin int ret; 2441a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin int batt_cap = -1; 2451a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin 2461a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin if (!charger->battery) 2471a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin return -1; 2481a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin 2491a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin ret = read_file_int(charger->battery->cap_path, &batt_cap); 2501a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin if (ret < 0 || batt_cap > 100) { 2511a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin batt_cap = -1; 2521a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin } 2531a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin 2541a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin return batt_cap; 2551a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin} 2561a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin 257f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic struct power_supply *find_supply(struct charger *charger, 258f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin const char *name) 259f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 260f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct listnode *node; 261f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct power_supply *supply; 262f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 263f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin list_for_each(node, &charger->supplies) { 264f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin supply = node_to_item(node, struct power_supply, list); 265f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!strncmp(name, supply->name, sizeof(supply->name))) 266f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return supply; 267f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 268f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return NULL; 269f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 270f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 271f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic struct power_supply *add_supply(struct charger *charger, 272f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin const char *name, const char *type, 2730052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin const char *path, bool online) 274f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 275f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct power_supply *supply; 276f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 277f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin supply = calloc(1, sizeof(struct power_supply)); 278f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!supply) 279f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return NULL; 280f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 281f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin strlcpy(supply->name, name, sizeof(supply->name)); 282f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin strlcpy(supply->type, type, sizeof(supply->type)); 2830052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin snprintf(supply->cap_path, sizeof(supply->cap_path), 2840052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin "/sys/%s/capacity", path); 285f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin supply->online = online; 286f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin list_add_tail(&charger->supplies, &supply->list); 287f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->num_supplies++; 288f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("... added %s %s %d\n", supply->name, supply->type, online); 289f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return supply; 290f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 291f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 292f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void remove_supply(struct charger *charger, struct power_supply *supply) 293f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 294f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!supply) 295f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return; 296f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin list_remove(&supply->list); 297f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->num_supplies--; 298f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin free(supply); 299f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 300f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 301f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void parse_uevent(const char *msg, struct uevent *uevent) 302f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 303f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->action = ""; 304f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->path = ""; 305f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->subsystem = ""; 306f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_name = ""; 307f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_online = ""; 308f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_type = ""; 309f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 310f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin /* currently ignoring SEQNUM */ 311f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin while (*msg) { 312f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#ifdef DEBUG_UEVENTS 313f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("uevent str: %s\n", msg); 314f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#endif 315f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!strncmp(msg, "ACTION=", 7)) { 316f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin msg += 7; 317f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->action = msg; 318f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else if (!strncmp(msg, "DEVPATH=", 8)) { 319f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin msg += 8; 320f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->path = msg; 321f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else if (!strncmp(msg, "SUBSYSTEM=", 10)) { 322f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin msg += 10; 323f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->subsystem = msg; 324f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else if (!strncmp(msg, "POWER_SUPPLY_NAME=", 18)) { 325f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin msg += 18; 326f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_name = msg; 327f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else if (!strncmp(msg, "POWER_SUPPLY_ONLINE=", 20)) { 328f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin msg += 20; 329f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_online = msg; 330f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else if (!strncmp(msg, "POWER_SUPPLY_TYPE=", 18)) { 331f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin msg += 18; 332f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_type = msg; 333f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 334f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 335f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin /* advance to after the next \0 */ 336f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin while (*msg++) 337f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ; 338f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 339f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 340f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("event { '%s', '%s', '%s', '%s', '%s', '%s' }\n", 341f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->action, uevent->path, uevent->subsystem, 342f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_name, uevent->ps_type, uevent->ps_online); 343f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 344f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 345f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void process_ps_uevent(struct charger *charger, struct uevent *uevent) 346f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 347f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int online; 348f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin char ps_type[32]; 349f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct power_supply *supply = NULL; 350f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int i; 351f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin bool was_online = false; 352f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin bool battery = false; 353f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 354f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (uevent->ps_type[0] == '\0') { 355f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin char *path; 356f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int ret; 357f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 358f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (uevent->path[0] == '\0') 359f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return; 360f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ret = asprintf(&path, "/sys/%s/type", uevent->path); 361f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (ret <= 0) 362f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return; 363f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ret = read_file(path, ps_type, sizeof(ps_type)); 364f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin free(path); 365f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (ret < 0) 366f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return; 367f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else { 368f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin strlcpy(ps_type, uevent->ps_type, sizeof(ps_type)); 369f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 370f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 371f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!strncmp(ps_type, "Battery", 7)) 372f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin battery = true; 373f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 374f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin online = atoi(uevent->ps_online); 375f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin supply = find_supply(charger, uevent->ps_name); 376f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (supply) { 377f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin was_online = supply->online; 378f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin supply->online = online; 379f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 380f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 381f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!strcmp(uevent->action, "add")) { 382f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!supply) { 3830052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin supply = add_supply(charger, uevent->ps_name, ps_type, uevent->path, 3840052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin online); 385f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!supply) { 386f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name, 387f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_type, online); 388f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return; 389f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 390f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin /* only pick up the first battery for now */ 391f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (battery && !charger->battery) 392f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->battery = supply; 393f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else { 394f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGE("supply '%s' already exists..\n", uevent->ps_name); 395f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 396f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else if (!strcmp(uevent->action, "remove")) { 397f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (supply) { 398f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (charger->battery == supply) 399f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->battery = NULL; 400f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin remove_supply(charger, supply); 401f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin supply = NULL; 402f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 403f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else if (!strcmp(uevent->action, "change")) { 404f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!supply) { 405f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGE("power supply '%s' not found ('%s' %d)\n", 406f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_name, ps_type, online); 407f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return; 408f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 409f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else { 410f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return; 411f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 412f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 413f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin /* allow battery to be managed in the supply list but make it not 414f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * contribute to online power supplies. */ 415f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!battery) { 416f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (was_online && !online) 417f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->num_supplies_online--; 418f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin else if (supply && !was_online && online) 419f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->num_supplies_online++; 420f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 421f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 422f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGI("power supply %s (%s) %s (action=%s num_online=%d num_supplies=%d)\n", 423f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->ps_name, ps_type, battery ? "" : online ? "online" : "offline", 424f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin uevent->action, charger->num_supplies_online, charger->num_supplies); 425f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 426f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 427f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void process_uevent(struct charger *charger, struct uevent *uevent) 428f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 429f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!strcmp(uevent->subsystem, "power_supply")) 430f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin process_ps_uevent(charger, uevent); 431f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 432f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 433f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin#define UEVENT_MSG_LEN 1024 434f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int handle_uevent_fd(struct charger *charger, int fd) 435f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 436f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin char msg[UEVENT_MSG_LEN+2]; 437f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int n; 438f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 439f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (fd < 0) 440f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return -1; 441f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 442f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin while (true) { 443f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct uevent uevent; 444f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 445f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin n = uevent_kernel_multicast_recv(fd, msg, UEVENT_MSG_LEN); 446f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (n <= 0) 447f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin break; 448f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ 449f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin continue; 450f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 451f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin msg[n] = '\0'; 452f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin msg[n+1] = '\0'; 453f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 454f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin parse_uevent(msg, &uevent); 455f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin process_uevent(charger, &uevent); 456f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 457f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 458f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return 0; 459f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 460f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 461f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int uevent_callback(int fd, short revents, void *data) 462f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 463f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct charger *charger = data; 464f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 465f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!(revents & POLLIN)) 466f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return -1; 467f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return handle_uevent_fd(charger, fd); 468f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 469f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 470f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin/* force the kernel to regenerate the change events for the existing 471f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * devices, if valid */ 472f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void do_coldboot(struct charger *charger, DIR *d, const char *event, 473f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin bool follow_links, int max_depth) 474f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 475f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct dirent *de; 476f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int dfd, fd; 477f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 478f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin dfd = dirfd(d); 479f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 480f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin fd = openat(dfd, "uevent", O_WRONLY); 481f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (fd >= 0) { 482f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin write(fd, event, strlen(event)); 483f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin close(fd); 484f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin handle_uevent_fd(charger, charger->uevent_fd); 485f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 486f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 487f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin while ((de = readdir(d)) && max_depth > 0) { 488f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin DIR *d2; 489f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 490f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("looking at '%s'\n", de->d_name); 491f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 492f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if ((de->d_type != DT_DIR && !(de->d_type == DT_LNK && follow_links)) || 493f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin de->d_name[0] == '.') { 494f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("skipping '%s' type %d (depth=%d follow=%d)\n", 495f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin de->d_name, de->d_type, max_depth, follow_links); 496f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin continue; 497f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 498f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("can descend into '%s'\n", de->d_name); 499f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 500f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); 501f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (fd < 0) { 502f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGE("cannot openat %d '%s' (%d: %s)\n", dfd, de->d_name, 503f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin errno, strerror(errno)); 504f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin continue; 505f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 506f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 507f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin d2 = fdopendir(fd); 508f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (d2 == 0) 509f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin close(fd); 510f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin else { 511f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("opened '%s'\n", de->d_name); 512f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin do_coldboot(charger, d2, event, follow_links, max_depth - 1); 513f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin closedir(d2); 514f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 515f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 516f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 517f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 518f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void coldboot(struct charger *charger, const char *path, 519f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin const char *event) 520f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 521f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin char str[256]; 522f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 523f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("doing coldboot '%s' in '%s'\n", event, path); 524f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin DIR *d = opendir(path); 525f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (d) { 526f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin snprintf(str, sizeof(str), "%s\n", event); 527f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin do_coldboot(charger, d, str, true, 1); 528f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin closedir(d); 529f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 530f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 531f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 532f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int draw_text(const char *str, int x, int y) 533f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 534f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int str_len_px = gr_measure(str); 535f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 536f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (x < 0) 537f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin x = (gr_fb_width() - str_len_px) / 2; 538f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (y < 0) 539f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin y = (gr_fb_height() - char_height) / 2; 540f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin gr_text(x, y, str); 541f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 542f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return y + char_height; 543f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 544f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 545f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void android_green(void) 546f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 547f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin gr_color(0xa4, 0xc6, 0x39, 255); 548f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 549f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 5500052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin/* returns the last y-offset of where the surface ends */ 5510052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic int draw_surface_centered(struct charger *charger, gr_surface surface) 552f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 5530052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int w; 5540052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int h; 555f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int x; 5560052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int y; 557f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 5580052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin w = gr_get_width(surface); 5590052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin h = gr_get_height(surface); 5600052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin x = (gr_fb_width() - w) / 2 ; 5610052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin y = (gr_fb_height() - h) / 2 ; 562f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 5630052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y); 5640052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin gr_blit(surface, 0, 0, w, h, x, y); 5650052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin return y + h; 5660052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin} 567f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 5680052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void draw_unknown(struct charger *charger) 5690052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{ 5700052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int y; 5710052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (charger->surf_unknown) { 5720052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin draw_surface_centered(charger, charger->surf_unknown); 573f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else { 574f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin android_green(); 575f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin y = draw_text("Charging!", -1, -1); 5760052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin draw_text("?\?/100", -1, y + 25); 577f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 5780052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin} 579f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 5800052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void draw_battery(struct charger *charger) 5810052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{ 5820052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin struct animation *batt_anim = charger->batt_anim; 5830052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin struct frame *frame = &batt_anim->frames[batt_anim->cur_frame]; 5840052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 5850052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (batt_anim->num_frames != 0) { 5860052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin draw_surface_centered(charger, frame->surface); 5870052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin LOGV("drawing frame #%d name=%s min_cap=%d time=%d\n", 5880052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin batt_anim->cur_frame, frame->name, frame->min_capacity, 5890052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin frame->disp_time); 590f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 5910052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin} 592f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 5930052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void redraw_screen(struct charger *charger) 5940052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{ 5950052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin struct animation *batt_anim = charger->batt_anim; 596f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 5970052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin clear_screen(); 598f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 5990052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* try to display *something* */ 6000052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (batt_anim->capacity < 0 || batt_anim->num_frames == 0) 6010052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin draw_unknown(charger); 6020052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin else 6030052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin draw_battery(charger); 604f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin gr_flip(); 605f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 606f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 6070052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void kick_animation(struct animation *anim) 6080052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{ 6090052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin anim->run = true; 6100052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin} 6110052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6120052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void reset_animation(struct animation *anim) 6130052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin{ 6140052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin anim->cur_cycle = 0; 6150052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin anim->cur_frame = 0; 6160052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin anim->run = false; 6170052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin} 6180052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6190052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavinstatic void update_screen_state(struct charger *charger, int64_t now) 620f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 6210052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin struct animation *batt_anim = charger->batt_anim; 6220052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int cur_frame; 6230052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int disp_time; 6240052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6250052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (!batt_anim->run || now < charger->next_screen_transition) 626f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return; 627f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 6280052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* animation is over, blank screen and leave */ 6290052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (batt_anim->cur_cycle == batt_anim->num_cycles) { 6300052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin reset_animation(batt_anim); 631f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_screen_transition = -1; 6320052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin gr_fb_blank(true); 6330052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin LOGV("[%lld] animation done\n", now); 6340052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin return; 6350052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin } 6360052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6370052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time; 6380052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6390052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* animation starting, set up the animation */ 6400052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (batt_anim->cur_frame == 0) { 6410052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int batt_cap; 6420052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int ret; 6430052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6440052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin LOGV("[%lld] animation starting\n", now); 6451a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin batt_cap = get_battery_capacity(charger); 6461a5ca61b28b3269b625b7a7162b4f50734f7fea9Dima Zavin if (batt_cap >= 0 && batt_anim->num_frames != 0) { 6470052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int i; 6480052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6490052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* find first frame given current capacity */ 6500052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin for (i = 1; i < batt_anim->num_frames; i++) { 6510052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (batt_cap < batt_anim->frames[i].min_capacity) 6520052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin break; 6530052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin } 6540052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin batt_anim->cur_frame = i - 1; 6550052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6560052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* show the first frame for twice as long */ 6570052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2; 6580052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin } 6590052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6600052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin batt_anim->capacity = batt_cap; 6610052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin } 6620052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6630052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* unblank the screen on first cycle */ 6640052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (batt_anim->cur_cycle == 0) 6650052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin gr_fb_blank(false); 6660052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6670052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* draw the new frame (@ cur_frame) */ 6680052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin redraw_screen(charger); 6690052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6700052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* if we don't have anim frames, we only have one image, so just bump 6710052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin * the cycle counter and exit 6720052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin */ 6730052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) { 6740052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin LOGV("[%lld] animation missing or unknown battery status\n", now); 6750052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME; 6760052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin batt_anim->cur_cycle++; 6770052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin return; 6780052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin } 6790052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6800052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* schedule next screen transition */ 6810052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin charger->next_screen_transition = now + disp_time; 6820052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 6830052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* advance frame cntr to the next valid frame 6840052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin * if necessary, advance cycle cntr, and reset frame cntr 6850052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin */ 6860052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin batt_anim->cur_frame++; 6870052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (batt_anim->cur_frame == batt_anim->num_frames) { 6880052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin batt_anim->cur_cycle++; 6890052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin batt_anim->cur_frame = 0; 690f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 6910052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* don't reset the cycle counter, since we use that as a signal 6920052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin * in a test above to check if animation is over 6930052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin */ 6940052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin } 695f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 696f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 697f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void update_input_state(struct charger *charger, 698f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct input_event *ev, 699f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t now) 700f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 701f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int down = !!ev->value; 702f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 703f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (ev->type != EV_KEY || ev->code > KEY_MAX) 704f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return; 705f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 706f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin /* only record the down even timestamp, as the amount 707f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * of time the key spent not being pressed is not useful */ 708f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (down) 709f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->keys[ev->code].timestamp = now; 710f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->keys[ev->code].down = down; 711f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->keys[ev->code].pending = true; 712f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (down) { 713f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("[%lld] key[%d] down\n", now, ev->code); 714f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else { 715f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t duration = now - charger->keys[ev->code].timestamp; 716f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t secs = duration / 1000; 717f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t msecs = duration - secs * 1000; 718f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now, 719f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ev->code, secs, msecs); 720f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 721f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 722f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 723f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void set_next_key_check(struct charger *charger, 724f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct key_state *key, 725f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t timeout) 726f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 727f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t then = key->timestamp + timeout; 728f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 729f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (charger->next_key_check == -1 || then < charger->next_key_check) 730f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_key_check = then; 731f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 732f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 733f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void process_key(struct charger *charger, int code, int64_t now) 734f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 735f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct key_state *key = &charger->keys[code]; 736f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t next_key_check; 737f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 738f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (code == KEY_POWER) { 739f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (key->down) { 740f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME; 741f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (now >= reboot_timeout) { 742f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGI("[%lld] rebooting\n", now); 743f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin android_reboot(ANDROID_RB_RESTART, 0, 0); 744f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else { 745f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin /* if the key is pressed but timeout hasn't expired, 746f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin * make sure we wake up at the right-ish time to check 747f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin */ 748f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin set_next_key_check(charger, key, POWER_ON_KEY_TIME); 749f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 750f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else { 751f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin /* if the power key got released, force screen state cycle */ 752f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (key->pending) 7530052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin kick_animation(charger->batt_anim); 754f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 755f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 756f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 757f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin key->pending = false; 758f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 759f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 760f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void handle_input_state(struct charger *charger, int64_t now) 761f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 762f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin process_key(charger, KEY_POWER, now); 763f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 764f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (charger->next_key_check != -1 && now > charger->next_key_check) 765f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_key_check = -1; 766f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 767f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 768f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void handle_power_supply_state(struct charger *charger, int64_t now) 769f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 770f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (charger->num_supplies_online == 0) { 771f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (charger->next_pwr_check == -1) { 772f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME; 773e0c70dad4b4d417182e4c0ba8adae199f2622582Dima Zavin kick_animation(charger->batt_anim); 774f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n", 775f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check); 776f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else if (now >= charger->next_pwr_check) { 777f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGI("[%lld] shutting down\n", now); 778f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin android_reboot(ANDROID_RB_POWEROFF, 0, 0); 779f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else { 780f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin /* otherwise we already have a shutdown timer scheduled */ 781f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 782f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } else { 783f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin /* online supply present, reset shutdown timer if set */ 784f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (charger->next_pwr_check != -1) { 785f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGI("[%lld] device plugged in: shutdown cancelled\n", now); 7860052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin kick_animation(charger->batt_anim); 787f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 788f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_pwr_check = -1; 789f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 790f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 791f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 792f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void wait_next_event(struct charger *charger, int64_t now) 793f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 794f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t next_event = INT64_MAX; 795f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t timeout; 796f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct input_event ev; 797f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int ret; 798f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 799f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("[%lld] next screen: %lld next key: %lld next pwr: %lld\n", now, 800f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_screen_transition, charger->next_key_check, 801f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_pwr_check); 802f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 803f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (charger->next_screen_transition != -1) 804f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin next_event = charger->next_screen_transition; 805f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (charger->next_key_check != -1 && charger->next_key_check < next_event) 806f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin next_event = charger->next_key_check; 807f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event) 808f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin next_event = charger->next_pwr_check; 809f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 810f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (next_event != -1 && next_event != INT64_MAX) 811f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin timeout = max(0, next_event - now); 812f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin else 813f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin timeout = -1; 814f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("[%lld] blocking (%lld)\n", now, timeout); 815f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ret = ev_wait((int)timeout); 816f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (!ret) 817f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ev_dispatch(); 818f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 819f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 820f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic int input_callback(int fd, short revents, void *data) 821f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 822f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct charger *charger = data; 823f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct input_event ev; 824f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int ret; 825f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 826f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ret = ev_get_input(fd, revents, &ev); 827f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (ret) 828f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return -1; 829f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin update_input_state(charger, &ev, curr_time_ms()); 830f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return 0; 831f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 832f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 833f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinstatic void event_loop(struct charger *charger) 834f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 835f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int ret; 836f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 837f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin while (true) { 838f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t now = curr_time_ms(); 839f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 840f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGV("[%lld] event_loop()\n", now); 841f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin handle_input_state(charger, now); 842f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin handle_power_supply_state(charger, now); 843f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 8440052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* do screen update last in case any of the above want to start 8450052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin * screen transitions (animations, etc) 8460052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin */ 8470052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin update_screen_state(charger, now); 8480052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 849f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin wait_next_event(charger, now); 850f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 851f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 852f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 853f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavinint main(int argc, char **argv) 854f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin{ 855f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int ret; 856f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin struct charger *charger = &charger_state; 857f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int64_t now = curr_time_ms() - 1; 858f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin int fd; 8590052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin int i; 860f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 861f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin list_init(&charger->supplies); 862f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 863f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin klog_init(); 864f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin klog_set_level(CHARGER_KLOG_LEVEL); 865f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 866f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin gr_init(); 867f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin gr_font_size(&char_width, &char_height); 868f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 869f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ev_init(input_callback, charger); 870f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 871f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin fd = uevent_open_socket(64*1024, true); 872f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (fd >= 0) { 873f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin fcntl(fd, F_SETFL, O_NONBLOCK); 874f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin ev_add_fd(fd, uevent_callback, charger); 875f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 876f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->uevent_fd = fd; 877f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin coldboot(charger, "/sys/class/power_supply", "add"); 878f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 8790052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin ret = res_create_surface("charger/battery_fail", &charger->surf_unknown); 880f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin if (ret < 0) { 881f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin LOGE("Cannot load image\n"); 8820052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin charger->surf_unknown = NULL; 8830052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin } 8840052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 8850052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin for (i = 0; i < charger->batt_anim->num_frames; i++) { 8860052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin struct frame *frame = &charger->batt_anim->frames[i]; 8870052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin 8880052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin ret = res_create_surface(frame->name, &frame->surface); 8890052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin if (ret < 0) { 8900052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin LOGE("Cannot load image %s\n", frame->name); 8910052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin /* TODO: free the already allocated surfaces... */ 8920052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin charger->batt_anim->num_frames = 0; 8930052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin charger->batt_anim->num_cycles = 1; 8940052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin break; 8950052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin } 896f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin } 897f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 898f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin gr_fb_blank(true); 899f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 900f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_screen_transition = now - 1; 901f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_key_check = -1; 902f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin charger->next_pwr_check = -1; 9030052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin reset_animation(charger->batt_anim); 9040052abdafd7179fc4a7458f09d2f95c74dda0021Dima Zavin kick_animation(charger->batt_anim); 905f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 906f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin event_loop(charger); 907f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin 908f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin return 0; 909f48b23688c1303212c65e470af9f9f3892e98f8eDima Zavin} 910