$NetBSD: patch-ab,v 1.10 2018/05/06 14:32:06 jmcneill Exp $ --- xbattbar.c.orig 2001-02-02 05:25:29.000000000 +0000 +++ xbattbar.c @@ -27,6 +27,16 @@ static char *ReleaseVersion="1.4.2"; #include #include + +#ifdef __NetBSD__ +#define ENVSYSUNITNAMES +#include +#include +#include +#include +#include +#endif /* __NetBSD__ */ + #include #include #include @@ -577,33 +587,190 @@ void battery_check(void) #ifdef __NetBSD__ +#ifndef _NO_APM #include +#else +#define APM_AC_OFF 0x00 +#define APM_AC_ON 0x01 +#endif #define _PATH_APM_SOCKET "/var/run/apmdev" #define _PATH_APM_CTLDEV "/dev/apmctl" #define _PATH_APM_NORMAL "/dev/apm" +/* + * pre: fd contains a valid file descriptor of an envsys(4) supporting device + * && ns is the number of sensors + * && etds and ebis are arrays of sufficient size + * post: returns 0 and etds and ebis arrays are filled with sensor info + * or returns -1 on failure + */ +static int +fillsensors(int fd, envsys_tre_data_t *etds, envsys_basic_info_t *ebis, + size_t ns) +{ + int i; + + for (i = 0; i < ns; ++i) { + ebis[i].sensor = i; + if (ioctl(fd, ENVSYS_GTREINFO, &ebis[i]) == -1) { + warn("Can't get sensor info for sensor %d", i); + return 0; + } + + etds[i].sensor = i; + if (ioctl(fd, ENVSYS_GTREDATA, &etds[i]) == -1) { + warn("Can't get sensor data for sensor %d", i); + return 0; + } + } + return 1; +} + +/* + * pre: fd contains a valid file descriptor of an envsys(4) supporting device + * post: returns the number of valid sensors provided by the device + * or -1 on error + */ +static size_t +numsensors(int fd) +{ + int count = 0, valid = 1; + envsys_tre_data_t etd; + etd.sensor = 0; + + while (valid) { + if (ioctl(fd, ENVSYS_GTREDATA, &etd) == -1) + err(1, "Can't get sensor data"); + + valid = etd.validflags & ENVSYS_FVALID; + if (valid) + ++count; + + ++etd.sensor; + } + + return count; +} + +static envsys_tre_data_t *etds; +static envsys_basic_info_t *ebis; +static int *cetds; + +#if defined(_PATH_SYSMON) && __NetBSD_Version__ >= 106110000 +#define HAVE_NETBSD_ACPI +#endif + int first = 1; void battery_check(void) { int fd, r, p; +#ifndef _NO_APM struct apm_power_info info; +#endif + int acpi; + size_t ns; + size_t cc; + char *apmdev; + int i; + + acpi = 0; + apmdev = _PATH_APM_NORMAL; + if ((fd = open(apmdev, O_RDONLY)) == -1) { +#ifdef HAVE_NETBSD_ACPI + apmdev = _PATH_SYSMON; + fd = open(apmdev, O_RDONLY); + acpi = 1; +#endif + } + if (fd < 0) { + fprintf(stderr, "xbattbar: cannot open %s device\n", apmdev); + exit(1); + } - if ((fd = open(_PATH_APM_NORMAL, O_RDONLY)) == -1) { - fprintf(stderr, "xbattbar: cannot open apm device\n"); + if (acpi) { +#ifdef HAVE_NETBSD_ACPI + if ((ns = numsensors(fd)) == 0) { + fprintf(stderr, "xbattbar: no sensors found\n"); exit(1); } + if (first) { + cetds = (int *)malloc(ns * sizeof(int)); + etds = (envsys_tre_data_t *)malloc(ns * sizeof(envsys_tre_data_t)); + ebis = (envsys_basic_info_t *)malloc(ns * sizeof(envsys_basic_info_t)); + + if ((cetds == NULL) || (etds == NULL) || (ebis == NULL)) { + err(1, "Out of memory"); + } + } + + fillsensors(fd, etds, ebis, ns); + +#endif +#ifndef _NO_APM + } else { + memset(&info, 0, sizeof(info)); if (ioctl(fd, APM_IOC_GETPOWER, &info) != 0) { fprintf(stderr, "xbattbar: ioctl APM_IOC_GETPOWER failed\n"); exit(1); } +#endif + } close(fd); ++elapsed_time; - /* get current remoain */ + if (acpi) { +#ifdef HAVE_NETBSD_ACPI + int32_t rtot = 0, maxtot = 0; + int have_pct = 0; + p = APM_AC_ON; + for (i = 0 ; i < ns ; i++) { + if ((etds[i].validflags & ENVSYS_FCURVALID) == 0) + continue; + cc = strlen(ebis[i].desc); + if (strncmp(ebis[i].desc, "acpibat", 7) == 0 && + (strcmp(&ebis[i].desc[cc - 7], " charge") == 0 || + strcmp(&ebis[i].desc[cc - 7], " energy") == 0)) { + rtot += etds[i].cur.data_s; + maxtot += etds[i].max.data_s; + } + /* + * XXX: We should use acpiacad driver and look for + * " connected", but that's broken on some machines + * and we want this to work everywhere. With this + * we will occasionally catch a machine conditioning + * a battery while connected, while other machines take + * 10-15 seconds to switch from "charging" to + * "discharging" and vice versa, but this is the best + * compromise. + */ + if ((ebis[i].units == ENVSYS_SWATTS || ebis[i].units == ENVSYS_SAMPS) && + etds[i].cur.data_s && + strncmp(ebis[i].desc, "acpibat", 7) == 0 && + strcmp(&ebis[i].desc[cc - 14], "discharge rate") == 0) { + p = APM_AC_OFF; + } + + if (ebis[i].units == ENVSYS_INTEGER && + strcmp(ebis[i].desc, "battery percent") == 0) { + have_pct = 1; + r = etds[i].cur.data_s; + } + if (ebis[i].units == ENVSYS_INDICATOR && + strcmp(ebis[i].desc, "ACIN present") == 0 && + etds[i].cur.data_s == 0) { + p = APM_AC_OFF; + } + } + if (!have_pct) + r = (rtot * 100.0) / maxtot; +#endif +#ifndef _NO_APM + } else { + /* get current remain */ if (info.battery_life > 100) { /* some APM BIOSes return values slightly > 100 */ r = 100; @@ -617,6 +784,8 @@ void battery_check(void) } else { p = APM_AC_OFF; } +#endif + } if (first || ac_line != p || battery_level != r) { first = 0;