pkgsrc/sysutils/xbattbar/patches/patch-ab
pooka 47f1024dc0 Make charging detection use discharge rate instead of charge rate,
since a fully charged battery would sometimes drop the charge rate
to 0.  This happens at least on the submitter's and my laptops.

patch from ymous anonimo
2008-01-04 01:43:58 +00:00

211 lines
5.3 KiB
Text

$NetBSD: patch-ab,v 1.9 2008/01/04 01:43:58 pooka Exp $
--- xbattbar.c.orig 2001-02-02 07:25:29.000000000 +0200
+++ xbattbar.c 2008-01-04 03:32:10.000000000 +0200
@@ -27,6 +27,16 @@
#include <sys/types.h>
#include <sys/time.h>
+
+#ifdef __NetBSD__
+#define ENVSYSUNITNAMES
+#include <sys/param.h>
+#include <sys/envsys.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#endif /* __NetBSD__ */
+
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
@@ -577,33 +587,177 @@
#ifdef __NetBSD__
+#ifndef _NO_APM
#include <machine/apmvar.h>
+#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;
+ 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;
+ }
+ }
+ 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 +771,8 @@
} else {
p = APM_AC_OFF;
}
+#endif
+ }
if (first || ac_line != p || battery_level != r) {
first = 0;