From 4eb77744b560f2d1cdb635747a712f5a9f6ca6a4 Mon Sep 17 00:00:00 2001 From: Mitsuru IWASAKI Date: Sat, 23 Jun 2001 10:38:25 +0000 Subject: [PATCH] Add sysctl interface (Read-only) for temprature, AC-line and Battery. Patches for acpi_cmbat.c submitted by Munehiro Matsuda. --- sys/dev/acpica/acpi.c | 199 +++++++++++++++++++ sys/dev/acpica/acpi_acad.c | 65 +++++-- sys/dev/acpica/acpi_cmbat.c | 348 +++++++++++++++++++++++++++++----- sys/dev/acpica/acpi_thermal.c | 21 +- sys/dev/acpica/acpiio.h | 44 ++++- sys/dev/acpica/acpivar.h | 12 ++ 6 files changed, 617 insertions(+), 72 deletions(-) diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 436f5f054556..78315b1afaba 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -1461,3 +1461,202 @@ acpi_set_debugging(void *junk) } SYSINIT(acpi_debugging, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_set_debugging, NULL); #endif + +/* + * ACPI Battery Abstruction Layer + */ + +struct acpi_batteries { + TAILQ_ENTRY(acpi_batteries) link; + struct acpi_battdesc battdesc; +}; + +static TAILQ_HEAD(,acpi_batteries) acpi_batteries; +static int acpi_batteries_initted = 0; +static int acpi_batteries_units = 0; +static struct acpi_battinfo acpi_battery_battinfo; + +static int +acpi_battery_get_units(void) +{ + + return (acpi_batteries_units); +} + +static int +acpi_battery_get_battdesc(int logical_unit, struct acpi_battdesc *battdesc) +{ + int i; + struct acpi_batteries *bp; + + if (logical_unit < 0 || logical_unit >= acpi_batteries_units) { + return (ENXIO); + } + + i = 0; + TAILQ_FOREACH(bp, &acpi_batteries, link) { + if (logical_unit == i) { + battdesc->type = bp->battdesc.type; + battdesc->phys_unit = bp->battdesc.phys_unit; + return (0); + } + i++; + } + + return (ENXIO); +} + +static int +acpi_battery_get_battinfo(int unit, struct acpi_battinfo *battinfo) +{ + int error; + struct acpi_battdesc battdesc; + + error = 0; + if (unit == -1) { + error = acpi_cmbat_get_battinfo(-1, battinfo); + goto out; + } else { + if ((error = acpi_battery_get_battdesc(unit, &battdesc)) != 0) { + goto out; + } + switch (battdesc.type) { + case ACPI_BATT_TYPE_CMBAT: + error = acpi_cmbat_get_battinfo(battdesc.phys_unit, + battinfo); + break; + default: + error = ENXIO; + break; + } + } +out: + return (error); +} + +static int +acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg) +{ + int error; + int logical_unit; + union acpi_battery_ioctl_arg *ioctl_arg; + + ioctl_arg = (union acpi_battery_ioctl_arg *)addr; + error = 0; + switch (cmd) { + case ACPIIO_BATT_GET_UNITS: + *(int *)addr = acpi_battery_get_units(); + break; + + case ACPIIO_BATT_GET_BATTDESC: + logical_unit = ioctl_arg->unit; + error = acpi_battery_get_battdesc(logical_unit, &ioctl_arg->battdesc); + break; + + case ACPIIO_BATT_GET_BATTINFO: + logical_unit = ioctl_arg->unit; + error = acpi_battery_get_battinfo(logical_unit, + &ioctl_arg->battinfo); + break; + + default: + error = EINVAL; + break; + } + + return (error); +} + +static int +acpi_battery_sysctl(SYSCTL_HANDLER_ARGS) +{ + int val; + int error; + + acpi_battery_get_battinfo(-1, &acpi_battery_battinfo); + val = *(u_int *)oidp->oid_arg1; + error = sysctl_handle_int(oidp, &val, 0, req); + return (error); +} + +static int +acpi_battery_init(void) +{ + device_t dev; + struct acpi_softc *sc; + int error; + + if ((dev = devclass_get_device(acpi_devclass, 0)) == NULL) { + return (ENXIO); + } + if ((sc = device_get_softc(dev)) == NULL) { + return (ENXIO); + } + + error = 0; + + TAILQ_INIT(&acpi_batteries); + acpi_batteries_initted = 1; + + if ((error = acpi_register_ioctl(ACPIIO_BATT_GET_UNITS, + acpi_battery_ioctl, NULL)) != 0) { + return (error); + } + if ((error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTDESC, + acpi_battery_ioctl, NULL)) != 0) { + return (error); + } + if ((error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTINFO, + acpi_battery_ioctl, NULL)) != 0) { + return (error); + } + + sysctl_ctx_init(&sc->acpi_battery_sysctl_ctx); + sc->acpi_battery_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_battery_sysctl_ctx, + SYSCTL_CHILDREN(sc->acpi_sysctl_tree), + OID_AUTO, "battery", CTLFLAG_RD, 0, ""); + SYSCTL_ADD_PROC(&sc->acpi_battery_sysctl_ctx, + SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree), + OID_AUTO, "life", CTLTYPE_INT | CTLFLAG_RD, + &acpi_battery_battinfo.cap, 0, acpi_battery_sysctl, "I", ""); + SYSCTL_ADD_PROC(&sc->acpi_battery_sysctl_ctx, + SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree), + OID_AUTO, "time", CTLTYPE_INT | CTLFLAG_RD, + &acpi_battery_battinfo.min, 0, acpi_battery_sysctl, "I", ""); + SYSCTL_ADD_PROC(&sc->acpi_battery_sysctl_ctx, + SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree), + OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RD, + &acpi_battery_battinfo.state, 0, acpi_battery_sysctl, "I", ""); + SYSCTL_ADD_INT(&sc->acpi_battery_sysctl_ctx, + SYSCTL_CHILDREN(sc->acpi_battery_sysctl_tree), + OID_AUTO, "units", CTLFLAG_RD, &acpi_batteries_units, 0, ""); + + return (error); +} + +int +acpi_battery_register(int type, int phys_unit) +{ + int error; + struct acpi_batteries *bp; + + error = 0; + if ((bp = malloc(sizeof(*bp), M_ACPIDEV, M_NOWAIT)) == NULL) { + return(ENOMEM); + } + + bp->battdesc.type = type; + bp->battdesc.phys_unit = phys_unit; + if (acpi_batteries_initted == 0) { + if ((error = acpi_battery_init()) != 0) { + free(bp, M_ACPIDEV); + return(error); + } + } + + TAILQ_INSERT_TAIL(&acpi_batteries, bp, link); + acpi_batteries_units++; + + return(0); +} + diff --git a/sys/dev/acpica/acpi_acad.c b/sys/dev/acpica/acpi_acad.c index d67d8cf19eb1..38fd7c27847f 100644 --- a/sys/dev/acpica/acpi_acad.c +++ b/sys/dev/acpica/acpi_acad.c @@ -57,6 +57,7 @@ static void acpi_acad_notify_handler(ACPI_HANDLE , UINT32 ,void *); static int acpi_acad_probe(device_t); static int acpi_acad_attach(device_t); static int acpi_acad_ioctl(u_long, caddr_t, void *); +static int acpi_acad_sysctl(SYSCTL_HANDLER_ARGS); struct acpi_acad_softc { int status; @@ -69,9 +70,14 @@ acpi_acad_get_status(void *context) struct acpi_acad_softc *sc = device_get_softc(dev); ACPI_HANDLE h = acpi_get_handle(dev); - if (acpi_EvaluateInteger(h, "_PSR", &sc->status) != AE_OK) + if (acpi_EvaluateInteger(h, "_PSR", &sc->status) != AE_OK) { + sc->status = -1; return; - device_printf(dev,"%s\n",(sc->status) ? "On Line" : "Off Line"); + } + + if (bootverbose) { + device_printf(dev,"%s\n",(sc->status) ? "On Line" : "Off Line"); + } } static void @@ -79,7 +85,10 @@ acpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) { device_t dev = context; - device_printf(dev, "Notify %d\n", notify); + if (bootverbose) { + device_printf(dev, "Notify %d\n", notify); + } + switch (notify) { case ACPI_DEVICE_CHECK_PNP: case ACPI_DEVICE_CHECK_EXISTENCE: @@ -113,6 +122,8 @@ static int acpi_acad_attach(device_t dev) { int error; + struct acpi_acad_softc *sc; + struct acpi_softc *acpi_sc; ACPI_HANDLE handle = acpi_get_handle(dev); AcpiInstallNotifyHandler(handle, @@ -123,12 +134,21 @@ acpi_acad_attach(device_t dev) ACPI_SYSTEM_NOTIFY, acpi_acad_notify_handler, dev); - acpi_acad_get_status((void *)dev); - - error = acpi_register_ioctl(ACPIIO_ACAD_GET_STATUS, acpi_acad_ioctl, - device_get_softc(dev)); - if (error) + if ((sc = device_get_softc(dev)) == NULL) { + return (ENXIO); + } + if ((error = acpi_register_ioctl(ACPIIO_ACAD_GET_STATUS, + acpi_acad_ioctl, dev)) != 0) { return (error); + } + + if (device_get_unit(dev) == 0) { + acpi_sc = acpi_device_get_parent_softc(dev); + SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx, + SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), + OID_AUTO, "acline", CTLTYPE_INT | CTLFLAG_RD, + &sc->status, 0, acpi_acad_sysctl, "I", ""); + } return(0); } @@ -153,18 +173,41 @@ DRIVER_MODULE(acpi_acad,acpi,acpi_acad_driver,acpi_acad_devclass,0,0); static int acpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg) { - struct acpi_acad_softc *sc; + device_t dev; + struct acpi_acad_softc *sc; - sc = (struct acpi_acad_softc *)arg; - if (sc == NULL) { + dev = (device_t)arg; + if ((sc = device_get_softc(dev)) == NULL) { return(ENXIO); } switch (cmd) { case ACPIIO_ACAD_GET_STATUS: + acpi_acad_get_status(dev); *(int *)addr = sc->status; break; } return(0); } + +static int +acpi_acad_sysctl(SYSCTL_HANDLER_ARGS) +{ + int val; + int error; + device_t dev; + struct acpi_acad_softc *sc; + + if ((dev = devclass_get_device(acpi_acad_devclass, 0)) == NULL) { + return (ENXIO); + } + if ((sc = device_get_softc(dev)) == NULL) { + return (ENXIO); + } + acpi_acad_get_status(dev); + val = *(u_int *)oidp->oid_arg1; + error = sysctl_handle_int(oidp, &val, 0, req); + return (error); +} + diff --git a/sys/dev/acpica/acpi_cmbat.c b/sys/dev/acpica/acpi_cmbat.c index f85ddd52b09e..5a714a8c5cd0 100644 --- a/sys/dev/acpica/acpi_cmbat.c +++ b/sys/dev/acpica/acpi_cmbat.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2000 Munehiro Matsuda * Copyright (c) 2000 Takanori Watanabe * Copyright (c) 2000 Mitsuru IWASAKI * All rights reserved. @@ -63,8 +64,17 @@ struct acpi_cmbat_softc { struct acpi_bst bst; ACPI_BUFFER bif_buffer; ACPI_BUFFER bst_buffer; + struct timespec bif_lastupdated; + struct timespec bst_lastupdated; + + int not_present; + int cap; + int min; + int full_charge_time; }; +static struct timespec acpi_cmbat_info_lastupdated; + /* XXX: devclass_get_maxunit() don't give us the current allocated units... */ static int acpi_cmbat_units = 0; @@ -73,8 +83,13 @@ static int acpi_cmbat_units = 0; #define PKG_GETINT(res, tmp, idx, dest, label) do { \ tmp = &res->Package.Elements[idx]; \ + if (tmp == NULL) { \ + device_printf(dev, "%s: PKG_GETINT idx = %d\n.", \ + __func__, idx); \ + goto label; \ + } \ if (tmp->Type != ACPI_TYPE_INTEGER) \ - goto label ; \ + goto label; \ dest = tmp->Integer.Value; \ } while(0) @@ -82,6 +97,11 @@ static int acpi_cmbat_units = 0; size_t length; \ length = size; \ tmp = &res->Package.Elements[idx]; \ + if (tmp == NULL) { \ + device_printf(dev, "%s: PKG_GETSTR idx = %d\n.", \ + __func__, idx); \ + goto label; \ + } \ bzero(dest, sizeof(dest)); \ switch (tmp->Type) { \ case ACPI_TYPE_STRING: \ @@ -92,7 +112,7 @@ static int acpi_cmbat_units = 0; break; \ case ACPI_TYPE_BUFFER: \ if (tmp->Buffer.Length < length) { \ - length = tmp->String.Length; \ + length = tmp->Buffer.Length; \ } \ strncpy(dest, tmp->Buffer.Pointer, length); \ break; \ @@ -102,6 +122,31 @@ static int acpi_cmbat_units = 0; dest[sizeof(dest)-1] = '\0'; \ } while(0) +#define BATTERY_INFO_EXPIRE 5 +static __inline int +acpi_cmbat_info_expired(struct timespec *lastupdated) +{ + struct timespec curtime; + + if (lastupdated == NULL) { + return (1); + } + + getnanotime(&curtime); + timespecsub(&curtime, lastupdated); + return ((curtime.tv_sec < 0 || curtime.tv_sec > BATTERY_INFO_EXPIRE)); +} + + +static __inline void +acpi_cmbat_info_updated(struct timespec *lastupdated) +{ + + if (lastupdated != NULL) { + getnanotime(lastupdated); + } +} + static void acpi_cmbat_get_bst(void *context) { @@ -110,7 +155,11 @@ acpi_cmbat_get_bst(void *context) ACPI_STATUS as; ACPI_OBJECT *res, *tmp; ACPI_HANDLE h = acpi_get_handle(dev); - + + if (!acpi_cmbat_info_expired(&sc->bst_lastupdated)) { + return; + } + retry: if (sc->bst_buffer.Length == 0) { sc->bst_buffer.Pointer = NULL; @@ -127,6 +176,7 @@ acpi_cmbat_get_bst(void *context) } } + bzero(sc->bst_buffer.Pointer, sc->bst_buffer.Length); as = AcpiEvaluateObject(h, "_BST", NULL, &sc->bst_buffer); if (as == AE_BUFFER_OVERFLOW){ @@ -141,15 +191,18 @@ acpi_cmbat_get_bst(void *context) return; } - res = sc->bst_buffer.Pointer; + res = (ACPI_OBJECT *)sc->bst_buffer.Pointer; - if ((res->Type != ACPI_TYPE_PACKAGE) && (res->Package.Count < 4)) - return ; + if ((res->Type != ACPI_TYPE_PACKAGE) || (res->Package.Count != 4)) { + device_printf(dev, "Battery status corrupted\n"); + return; + } PKG_GETINT(res, tmp, 0, sc->bst.state, end); PKG_GETINT(res, tmp, 1, sc->bst.rate, end); PKG_GETINT(res, tmp, 2, sc->bst.cap, end); PKG_GETINT(res, tmp, 3, sc->bst.volt, end); + acpi_cmbat_info_updated(&sc->bst_lastupdated); end: } @@ -162,6 +215,10 @@ acpi_cmbat_get_bif(void *context) ACPI_HANDLE h = acpi_get_handle(dev); ACPI_OBJECT *res, *tmp; + if (!acpi_cmbat_info_expired(&sc->bif_lastupdated)) { + return; + } + retry: if (sc->bif_buffer.Length == 0) { sc->bif_buffer.Pointer = NULL; @@ -178,6 +235,7 @@ acpi_cmbat_get_bif(void *context) } } + bzero(sc->bif_buffer.Pointer, sc->bif_buffer.Length); as = AcpiEvaluateObject(h, "_BIF", NULL, &sc->bif_buffer); if (as == AE_BUFFER_OVERFLOW){ @@ -192,9 +250,12 @@ acpi_cmbat_get_bif(void *context) return; } - res = sc->bif_buffer.Pointer; - if ((res->Type != ACPI_TYPE_PACKAGE) && (res->Package.Count < 13)) - return ; + res = (ACPI_OBJECT *)sc->bif_buffer.Pointer; + + if ((res->Type != ACPI_TYPE_PACKAGE) || (res->Package.Count != 13)) { + device_printf(dev, "Battery info corrupted\n"); + return; + } PKG_GETINT(res, tmp, 0, sc->bif.unit, end); PKG_GETINT(res, tmp, 1, sc->bif.dcap, end); @@ -209,12 +270,14 @@ acpi_cmbat_get_bif(void *context) PKG_GETSTR(res, tmp, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN, end); PKG_GETSTR(res, tmp, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN, end); PKG_GETSTR(res, tmp, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN, end); + acpi_cmbat_info_updated(&sc->bif_lastupdated); end: } static void acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) { + switch (notify) { #if 0 /* XXX @@ -256,31 +319,38 @@ acpi_cmbat_attach(device_t dev) int error; ACPI_HANDLE handle = acpi_get_handle(dev); struct acpi_cmbat_softc *sc; - sc = device_get_softc(dev); + + if ((sc = device_get_softc(dev)) == NULL) { + return (ENXIO); + } AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, - acpi_cmbat_notify_handler,dev); + acpi_cmbat_notify_handler, dev); bzero(&sc->bif_buffer, sizeof(sc->bif_buffer)); bzero(&sc->bst_buffer, sizeof(sc->bst_buffer)); - - acpi_cmbat_get_bif(dev); - acpi_cmbat_get_bst(dev); + sc->dev = dev; + + timespecclear(&sc->bif_lastupdated); + timespecclear(&sc->bst_lastupdated); if (acpi_cmbat_units == 0) { - error = acpi_register_ioctl(ACPIIO_CMBAT_GET_UNITS, - acpi_cmbat_ioctl, sc); - if (error) + if ((error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BIF, + acpi_cmbat_ioctl, NULL)) != 0) { return (error); - error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BIF, - acpi_cmbat_ioctl, sc); - if (error) - return (error); - error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BST, - acpi_cmbat_ioctl, sc); - if (error) + } + if ((error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BST, + acpi_cmbat_ioctl, NULL)) != 0) { return (error); + } + } + + if ((error = acpi_battery_register(ACPI_BATT_TYPE_CMBAT, + acpi_cmbat_units)) != 0) { + return (error); } acpi_cmbat_units++; + timespecclear(&acpi_cmbat_info_lastupdated); + return(0); } @@ -305,34 +375,23 @@ DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0); static int acpi_cmbat_ioctl(u_long cmd, caddr_t addr, void *arg) { - union acpi_cmbat_ioctl_arg *ioctl_arg; device_t dev; - struct acpi_cmbat_softc *sc; - struct acpi_bif *bifp; - struct acpi_bst *bstp; + union acpi_battery_ioctl_arg *ioctl_arg; + struct acpi_cmbat_softc *sc; + struct acpi_bif *bifp; + struct acpi_bst *bstp; - if (cmd == ACPIIO_CMBAT_GET_UNITS) { - ioctl_arg = NULL; - dev = NULL; - sc = NULL; - } else { - ioctl_arg = (union acpi_cmbat_ioctl_arg *)addr; - dev = devclass_get_device(acpi_cmbat_devclass, ioctl_arg->unit); - if (dev == NULL) { - return(ENXIO); - } - - sc = device_get_softc(dev); - if (sc == NULL) { - return(ENXIO); - } + ioctl_arg = (union acpi_battery_ioctl_arg *)addr; + if ((dev = devclass_get_device(acpi_cmbat_devclass, + ioctl_arg->unit)) == NULL) { + return(ENXIO); + } + + if ((sc = device_get_softc(dev)) == NULL) { + return(ENXIO); } switch (cmd) { - case ACPIIO_CMBAT_GET_UNITS: - *(int *)addr = acpi_cmbat_units; - break; - case ACPIIO_CMBAT_GET_BIF: acpi_cmbat_get_bif(dev); bifp = &ioctl_arg->bif; @@ -363,3 +422,198 @@ acpi_cmbat_ioctl(u_long cmd, caddr_t addr, void *arg) return(0); } + +static int +acpi_cmbat_get_total_battinfo(struct acpi_battinfo *battinfo) +{ + int i; + int error; + int batt_stat; + int valid_rate, valid_units; + int cap, min; + int total_cap, total_min, total_full; + device_t dev; + struct acpi_cmbat_softc *sc; + static int bat_units = 0; + static struct acpi_cmbat_softc **bat = NULL; + + cap = min = -1; + batt_stat = ACPI_BATT_STAT_NOT_PRESENT; + error = 0; + + /* Allocate array of softc pointers */ + if (bat_units != acpi_cmbat_units) { + if (bat != NULL) { + free(bat, M_DEVBUF); + } + bat_units = 0; + } + if (bat == NULL) { + bat_units = acpi_cmbat_units; + bat = malloc(sizeof(struct acpi_cmbat_softc *) * bat_units, + M_DEVBUF, M_NOWAIT); + if (bat == NULL) { + error = ENOMEM; + goto out; + } + + /* Collect softc pointers */ + for (i = 0; i < acpi_cmbat_units; i++) { + if ((dev = devclass_get_device(acpi_cmbat_devclass, i)) == NULL) { + error = ENXIO; + goto out; + } + + if ((sc = device_get_softc(dev)) == NULL) { + error = ENXIO; + goto out; + } + + bat[i] = sc; + } + } + + /* Get battery status, valid rate and valid units */ + batt_stat = valid_rate = valid_units = 0; + for (i = 0; i < acpi_cmbat_units; i++) { + acpi_cmbat_get_bif(bat[i]->dev); + acpi_cmbat_get_bst(bat[i]->dev); + + /* If battey not installed, we get strange values */ + if (bat[i]->bst.state >= ACPI_BATT_STAT_MAX || + bat[i]->bst.cap == 0xffffffff || + bat[i]->bst.volt == 0xffffffff || + bat[i]->bif.lfcap == 0) { + bat[i]->not_present = 1; + continue; + } else { + bat[i]->not_present = 0; + } + + valid_units++; + + bat[i]->cap = 100 * bat[i]->bst.cap / bat[i]->bif.lfcap; + + batt_stat |= bat[i]->bst.state; + + if (bat[i]->bst.rate > 0) { + /* + * XXX Hack to calculate total battery time. + * Systems with 2 or more battries, they may get used + * one by one, thus bst.rate is set only to the one + * in use. For remaining batteries bst.rate = 0, which + * makes it impossible to calculate remaining time. + * Some other systems may need sum of bst.rate in + * dis-charging state. + * There for we sum up the bst.rate that is valid + * (in dis-charging state), and use the sum to + * calcutate remaining batteries' time. + */ + if (bat[i]->bst.state & ACPI_BATT_STAT_DISCHARG) { + valid_rate += bat[i]->bst.rate; + } + } + } + + /* Calculate total battery capacity and time */ + total_cap = total_min = total_full = 0; + for (i = 0; i < acpi_cmbat_units; i++) { + if (bat[i]->not_present) { + continue; + } + + if (valid_rate > 0) { + /* Use the sum of bst.rate */ + bat[i]->min = 60 * bat[i]->bst.cap / valid_rate; + } else if (bat[i]->full_charge_time > 0) { + bat[i]->min = (bat[i]->full_charge_time * bat[i]->cap) / 100; + } else { + /* Couldn't find valid rate and full battery time */ + bat[i]->min = 0; + } + total_min += bat[i]->min; + total_cap += bat[i]->cap; + total_full += bat[i]->full_charge_time; + } + + /* Battery life */ + if (valid_units == 0) { + cap = -1; + batt_stat = ACPI_BATT_STAT_NOT_PRESENT; + } else { + cap = total_cap / valid_units; + } + + /* Battery time */ + if (valid_units == 0) { + min = -1; + } else if (valid_rate == 0 || (batt_stat & ACPI_BATT_STAT_CHARGING)) { + if (total_full == 0) { + min = -1; + } else { + min = (total_full * cap) / 100; + } + } else { + min = total_min; + } + + acpi_cmbat_info_updated(&acpi_cmbat_info_lastupdated); +out: + battinfo->cap = cap; + battinfo->min = min; + battinfo->state = batt_stat; + + return (error); +} + +/* + * Public interfaces. + */ + +int +acpi_cmbat_get_battinfo(int unit, struct acpi_battinfo *battinfo) +{ + int error; + device_t dev; + struct acpi_cmbat_softc *sc; + + if (unit == -1) { + return (acpi_cmbat_get_total_battinfo(battinfo)); + } + + if (acpi_cmbat_info_expired(&acpi_cmbat_info_lastupdated)) { + error = acpi_cmbat_get_total_battinfo(battinfo); + if (error) { + goto out; + } + } + + error = 0; + if (unit >= acpi_cmbat_units) { + error = ENXIO; + goto out; + } + + if ((dev = devclass_get_device(acpi_cmbat_devclass, unit)) == NULL) { + error = ENXIO; + goto out; + } + + if ((sc = device_get_softc(dev)) == NULL) { + error = ENXIO; + goto out; + } + + if (sc->not_present) { + battinfo->cap = -1; + battinfo->min = -1; + battinfo->state = ACPI_BATT_STAT_NOT_PRESENT; + } else { + battinfo->cap = sc->cap; + battinfo->min = sc->min; + battinfo->state = sc->bst.state; + } +out: + return (error); +} + diff --git a/sys/dev/acpica/acpi_thermal.c b/sys/dev/acpica/acpi_thermal.c index 0475d28f7c54..7b3cd4e43ef0 100644 --- a/sys/dev/acpica/acpi_thermal.c +++ b/sys/dev/acpica/acpi_thermal.c @@ -48,6 +48,7 @@ MODULE_NAME("THERMAL") struct acpi_tz_softc { device_t tz_dev; ACPI_HANDLE tz_handle; + int tz_tmp; }; static int acpi_tz_probe(device_t dev); @@ -90,7 +91,7 @@ static int acpi_tz_attach(device_t dev) { struct acpi_tz_softc *sc; - ACPI_STATUS status; + struct acpi_softc *acpi_sc; FUNCTION_TRACE(__func__); @@ -101,6 +102,14 @@ acpi_tz_attach(device_t dev) AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, acpi_tz_notify_handler, dev); + if (device_get_unit(dev) == 0) { + acpi_sc = acpi_device_get_parent_softc(dev); + SYSCTL_ADD_UINT(&acpi_sc->acpi_sysctl_ctx, + SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), + OID_AUTO, "temperature", CTLFLAG_RD, + &sc->tz_tmp, 0, ""); + } + /* * Don't bother evaluating/printing the temperature at this point; * on many systems it'll be bogus until the EC is running. @@ -124,7 +133,10 @@ acpi_tz_check_tripping_point(void *context) return_VOID; } - device_printf(dev,"%d.%dC\n", TZ_KELVTOC(tp)); + sc->tz_tmp = (tp - TZ_ZEROC) / 10; + if (bootverbose) { + device_printf(dev, "%dC\n", sc->tz_tmp); + } return_VOID; } @@ -145,8 +157,3 @@ acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) return_VOID; } - - - - - diff --git a/sys/dev/acpica/acpiio.h b/sys/dev/acpica/acpiio.h index d98ffeda3539..48439f3b888d 100644 --- a/sys/dev/acpica/acpiio.h +++ b/sys/dev/acpica/acpiio.h @@ -34,6 +34,20 @@ #define ACPIIO_DISABLE _IO('P', 2) #define ACPIIO_SETSLPSTATE _IOW('P', 3, int) +struct acpi_battdesc { + int type; /* battery type: e.g. CMBAT */ + int phys_unit; /* physical unit of devclass */ +}; + +#define ACPI_BATT_TYPE_CMBAT 0x0000 +#define ACPI_BATT_TYPE_SMBAT 0x0001 + +struct acpi_battinfo { + int cap; /* percent */ + int min; /* remianing time */ + int state; /* battery state */ +}; + #define ACPI_CMBAT_MAXSTRLEN 32 struct acpi_bif { u_int32_t unit; /* 0 for mWh, 1 for mAh */ @@ -58,15 +72,31 @@ struct acpi_bst { u_int32_t volt; /* Present Voltage */ }; -union acpi_cmbat_ioctl_arg { - int unit; - struct acpi_bif bif; - struct acpi_bst bst; +#define ACPI_BATT_STAT_DISCHARG 0x0001 +#define ACPI_BATT_STAT_CHARGING 0x0002 +#define ACPI_BATT_STAT_CRITICAL 0x0004 +#define ACPI_BATT_STAT_NOT_PRESENT 0x0007 +#define ACPI_BATT_STAT_MAX 0x0007 + +union acpi_battery_ioctl_arg { + int unit; /* argument: logical unit (-1 = overall) */ + + struct acpi_battdesc battdesc; + struct acpi_battinfo battinfo; + + struct acpi_bif bif; /* for acpi_cmbat */ + struct acpi_bst bst; /* for acpi_cmbat */ }; -#define ACPIIO_CMBAT_GET_UNITS _IOR('B', 1, int) -#define ACPIIO_CMBAT_GET_BIF _IOWR('B', 2, union acpi_cmbat_ioctl_arg) -#define ACPIIO_CMBAT_GET_BST _IOWR('B', 3, union acpi_cmbat_ioctl_arg) +/* Common battery ioctl */ +#define ACPIIO_BATT_GET_UNITS _IOR('B', 0x01, int) +#define ACPIIO_BATT_GET_TYPE _IOR('B', 0x02, union acpi_battery_ioctl_arg) +#define ACPIIO_BATT_GET_BATTINFO _IOWR('B', 0x03, union acpi_battery_ioctl_arg) +#define ACPIIO_BATT_GET_BATTDESC _IOWR('B', 0x04, union acpi_battery_ioctl_arg) + +/* Cotrol Method battery ioctl */ +#define ACPIIO_CMBAT_GET_BIF _IOWR('B', 0x10, union acpi_battery_ioctl_arg) +#define ACPIIO_CMBAT_GET_BST _IOWR('B', 0x11, union acpi_battery_ioctl_arg) #define ACPIIO_ACAD_GET_STATUS _IOR('A', 1, int) diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index ebefafbd7249..4e3930675681 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -53,6 +53,9 @@ struct acpi_softc { int acpi_power_button_sx; int acpi_sleep_button_sx; int acpi_lid_switch_sx; + + struct sysctl_ctx_list acpi_battery_sysctl_ctx; + struct sysctl_oid *acpi_battery_sysctl_tree; }; struct acpi_device { @@ -230,3 +233,12 @@ extern char *acpi_name(ACPI_HANDLE handle); extern int acpi_avoid(ACPI_HANDLE handle); extern int acpi_disabled(char *subsys); +/* + * Battery Abstruction and Generalized Power Management interface. + */ +struct acpi_battinfo; + +extern int acpi_battery_register(int, int); +extern int acpi_acad_get_acline(void); +extern int acpi_cmbat_get_battinfo(int, struct acpi_battinfo *); +