blob: 50c17916cbb0c4ae56567018ea174d2b82453d8c [file] [log] [blame] [raw]
/*
htop - haiku/Battery.c
Copyright 2015-2022 Rivoreo
Released under the GNU GPL, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h"
#include "BatteryMeter.h"
#include <Drivers.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#define PM_GET_BATTERY_INFO (B_DEVICE_OP_CODES_END + 20010)
#define PM_GET_EXTENDED_BATTERY_INFO (B_DEVICE_OP_CODES_END + 20011)
#define ACPI_BATTERY_PATH "/dev/power/acpi_battery/"
#define ACPI_BATTERY_DISCHARGING 0x01
#define ACPI_BATTERY_CHARGING 0x02
#define ACPI_BATTERY_CRITICAL_STATE 0x04
struct acpi_battery_info {
int state;
int current_rate;
int capacity;
int voltage;
};
struct acpi_extended_battery_info {
int power_unit;
int design_capacity;
int last_full_charge;
int technology;
int design_voltage;
int design_capacity_warning;
int design_capacity_low;
int capacity_granularity_1;
int capacity_granularity_2;
char model_number[32];
char serial_number[32];
char type[32];
char oem_info[32];
};
static DIR *acpi_battery_dir;
void Battery_getData(double *level, ACPresence *is_on_ac) {
*level = -1;
*is_on_ac = AC_ERROR;
if(!acpi_battery_dir) {
acpi_battery_dir = opendir(ACPI_BATTERY_PATH);
if(!acpi_battery_dir) return;
}
double max_cap = 0;
double cap = 0;
rewinddir(acpi_battery_dir);
struct dirent *e;
while((e = readdir(acpi_battery_dir))) {
if(e->d_name[0] == '.') continue;
size_t name_len = strlen(e->d_name) + 1;
char path[sizeof ACPI_BATTERY_PATH - 1 + name_len];
memcpy(path, ACPI_BATTERY_PATH, sizeof ACPI_BATTERY_PATH - 1);
memcpy(path + sizeof ACPI_BATTERY_PATH - 1, e->d_name, name_len);
int fd = open(path, O_RDONLY);
if(fd == -1) continue;
struct acpi_battery_info info;
if(ioctl(fd, PM_GET_BATTERY_INFO, &info, sizeof info) == 0 &&
!(info.state & ACPI_BATTERY_CRITICAL_STATE)) {
if(*is_on_ac != AC_PRESENT) {
*is_on_ac = (info.state & ACPI_BATTERY_DISCHARGING) ?
AC_ABSENT : AC_PRESENT;
}
struct acpi_extended_battery_info ext_info;
if(ioctl(fd, PM_GET_EXTENDED_BATTERY_INFO, &ext_info, sizeof ext_info) == 0) {
max_cap += ext_info.last_full_charge;
cap += info.capacity;
}
}
close(fd);
}
if(max_cap > 0) {
*level = cap / max_cap * 100;
if(*level > 100) *level = 100;
}
}