kern/124223: [patch] acpi_battery.c -- Notify user-defined critical
level via devd(8)
Pietro Cerutti
gahr at FreeBSD.org
Mon Jun 2 23:00:08 UTC 2008
>Number: 124223
>Category: kern
>Synopsis: [patch] acpi_battery.c -- Notify user-defined critical level via devd(8)
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Mon Jun 02 23:00:07 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator: Pietro Cerutti
>Release: FreeBSD 8.0-CURRENT i386
>Organization:
The FreeBSD Project
>Environment:
System: FreeBSD 8.0-CURRENT #39: Mon Jun 2 20:33:05 CEST 2008
root at gahrtop.localhost:/usr/obj/usr/src/sys/MSI1034
>Description:
Critically low battery levels are notified by the ACPI subsystem via the acpi_cmbat.c module.
This prints a line on the console.
The problem with cmbat is that the "critically low level" value is not configurable.
The following patch implements a kernel process within acpi_battery.c.
Two sysctl OIDs are exported in order to control the polling rate and the life % to be considered critical.
When this critical level is reached, acpi_battery.c notifies userland via devd(8), allowing for a devd.conf(5) configuration such as:
notify 10 {
match "system" "ACPI";
match "subsystem" "Battery";
match "notify" "0x80";
action "logger -p kern.emerg 'WARNING: Low battery!'";
};
>How-To-Repeat:
>Fix:
--- acpi_battery.c.diff begins here ---
Index: acpi_battery.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/acpica/acpi_battery.c,v
retrieving revision 1.26
diff -u -u -r1.26 acpi_battery.c
--- acpi_battery.c 20 Nov 2007 18:35:36 -0000 1.26
+++ acpi_battery.c 23 May 2008 14:35:21 -0000
@@ -31,10 +31,12 @@
#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/kthread.h>
#include <sys/malloc.h>
#include <sys/bus.h>
#include <sys/ioccom.h>
#include <sys/sysctl.h>
+#include <sys/unistd.h>
#include <contrib/dev/acpica/acpi.h>
#include <dev/acpica/acpivar.h>
@@ -43,6 +45,14 @@
/* Default seconds before re-sampling the battery state. */
#define ACPI_BATTERY_INFO_EXPIRE 5
+/* Check for battery low level each 60 seconds */
+#define BATT_POLLRATE 60
+
+/* Default level to notify devd */
+#define BATT_LOWLEVEL 5
+
+#define BATT_NOTIFY_LOWLEVEL 0x80
+
static int acpi_batteries_initted;
static int acpi_battery_info_expire = ACPI_BATTERY_INFO_EXPIRE;
static struct acpi_battinfo acpi_battery_battinfo;
@@ -56,8 +66,16 @@
static device_t acpi_battery_find_dev(u_int logical_unit);
static int acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg);
static int acpi_battery_sysctl(SYSCTL_HANDLER_ARGS);
+static int acpi_battery_rate_sysctl(SYSCTL_HANDLER_ARGS);
+static int acpi_battery_crit_sysctl(SYSCTL_HANDLER_ARGS);
static int acpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS);
static int acpi_battery_init(void);
+static void acpi_battery_thread(void *);
+
+static struct proc *acpi_battery_proc;
+static int acpi_battery_pollrate = BATT_POLLRATE;
+static int acpi_battery_lowlevel = BATT_LOWLEVEL;
+static int acpi_battery_previous = -1;
int
acpi_battery_register(device_t dev)
@@ -69,6 +87,8 @@
if (!acpi_batteries_initted)
error = acpi_battery_init();
ACPI_SERIAL_END(battery);
+ if(error) return (error);
+ error = kproc_create(acpi_battery_thread, NULL, &acpi_battery_proc, RFHIGHPID, 0, "acpi_battery");
return (error);
}
@@ -422,6 +442,36 @@
}
static int
+acpi_battery_rate_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+
+ error = sysctl_handle_int(oidp, &acpi_battery_pollrate, 0, req);
+
+ if(error || !req->newptr)
+ return (error);
+
+ acpi_battery_pollrate = *(int *)req->newptr;
+
+ wakeup(&acpi_battery_proc);
+ return (error);
+}
+
+static int
+acpi_battery_crit_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+
+ error = sysctl_handle_int(oidp, &acpi_battery_lowlevel, 0, req);
+
+ if(error || !req->newptr)
+ return (error);
+
+ acpi_battery_lowlevel = *(int *)req->newptr;
+ return (error);
+}
+
+static int
acpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS)
{
int count, error;
@@ -489,6 +539,16 @@
OID_AUTO, "info_expire", CTLFLAG_RW,
&acpi_battery_info_expire, 0,
"time in seconds until info is refreshed");
+ SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
+ SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
+ OID_AUTO, "polling_rate", CTLTYPE_INT | CTLFLAG_RW,
+ NULL, 0, acpi_battery_rate_sysctl, "I",
+ "polling rate in seconds");
+ SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx,
+ SYSCTL_CHILDREN(acpi_battery_sysctl_tree),
+ OID_AUTO, "critical_level", CTLTYPE_INT | CTLFLAG_RW,
+ NULL, 0, acpi_battery_crit_sysctl, "I",
+ "critical level in percent");
acpi_batteries_initted = TRUE;
@@ -501,3 +561,31 @@
}
return (error);
}
+
+/*
+ * ACPI Battery monitor thread
+ */
+static void
+acpi_battery_thread(void *arg)
+{
+ (void) arg; /* not used */
+ struct acpi_battinfo battinfo;
+ device_t dev;
+ ACPI_HANDLE h;
+
+ if(!(dev = devclass_get_device(devclass_find("acpi"), 0)))
+ return;
+
+ h = acpi_get_handle(dev);
+
+ while(1)
+ {
+ if(!acpi_battery_get_battinfo(NULL, &battinfo))
+ {
+ if(battinfo.cap <= acpi_battery_lowlevel && battinfo.cap < acpi_battery_previous)
+ acpi_UserNotify("Battery", h, BATT_NOTIFY_LOWLEVEL);
+ acpi_battery_previous = battinfo.cap;
+ }
+ tsleep(&acpi_battery_proc, 0, "batpol", hz * acpi_battery_pollrate);
+ }
+}
--- acpi_battery.c.diff ends here ---
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list