Date: Tue, 3 Jun 2008 00:56:53 +0200 From: "Pietro Cerutti" <gahr@FreeBSD.org> To: "FreeBSD gnats submit" <FreeBSD-gnats-submit@FreeBSD.org> Subject: kern/124223: [patch] acpi_battery.c -- Notify user-defined critical level via devd(8) Message-ID: <1212447413.32542@gahrtop.localhost> Resent-Message-ID: <200806022300.m52N0772060946@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>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@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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1212447413.32542>