179282Smsmith/*- 2148352Snjl * Copyright (c) 2005 Nate Lawson 379282Smsmith * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 479282Smsmith * All rights reserved. 579282Smsmith * 679282Smsmith * Redistribution and use in source and binary forms, with or without 779282Smsmith * modification, are permitted provided that the following conditions 879282Smsmith * are met: 979282Smsmith * 1. Redistributions of source code must retain the above copyright 1079282Smsmith * notice, this list of conditions and the following disclaimer. 1179282Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1279282Smsmith * notice, this list of conditions and the following disclaimer in the 1379282Smsmith * documentation and/or other materials provided with the distribution. 1479282Smsmith * 1579282Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1679282Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1779282Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1879282Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1979282Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2079282Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2179282Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2279282Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2379282Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2479282Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2579282Smsmith * SUCH DAMAGE. 2679282Smsmith */ 2779282Smsmith 28143002Sobrien#include <sys/cdefs.h> 29143002Sobrien__FBSDID("$FreeBSD$"); 30143002Sobrien 31118783Snjl#include "opt_acpi.h" 3279282Smsmith#include <sys/param.h> 3379282Smsmith#include <sys/kernel.h> 3479282Smsmith#include <sys/malloc.h> 3579282Smsmith#include <sys/bus.h> 3679282Smsmith#include <sys/ioccom.h> 3779282Smsmith#include <sys/sysctl.h> 3879282Smsmith 39193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 40193530Sjkim 4179282Smsmith#include <dev/acpica/acpivar.h> 4279282Smsmith#include <dev/acpica/acpiio.h> 4379282Smsmith 44148352Snjl/* Default seconds before re-sampling the battery state. */ 45148352Snjl#define ACPI_BATTERY_INFO_EXPIRE 5 4679282Smsmith 47148352Snjlstatic int acpi_batteries_initted; 48148352Snjlstatic int acpi_battery_info_expire = ACPI_BATTERY_INFO_EXPIRE; 49148352Snjlstatic struct acpi_battinfo acpi_battery_battinfo; 50148352Snjlstatic struct sysctl_ctx_list acpi_battery_sysctl_ctx; 51148352Snjlstatic struct sysctl_oid *acpi_battery_sysctl_tree; 5279282Smsmith 53133614SnjlACPI_SERIAL_DECL(battery, "ACPI generic battery"); 5479282Smsmith 55148352Snjlstatic void acpi_reset_battinfo(struct acpi_battinfo *info); 56151563Snjlstatic void acpi_battery_clean_str(char *str, int len); 57151591Snjlstatic device_t acpi_battery_find_dev(u_int logical_unit); 58148352Snjlstatic int acpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg); 59148352Snjlstatic int acpi_battery_sysctl(SYSCTL_HANDLER_ARGS); 60148352Snjlstatic int acpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS); 61148352Snjlstatic int acpi_battery_init(void); 62148352Snjl 6385556Siwasakiint 64148352Snjlacpi_battery_register(device_t dev) 65133614Snjl{ 66148352Snjl int error; 67148352Snjl 68148352Snjl error = 0; 69148352Snjl ACPI_SERIAL_BEGIN(battery); 70148352Snjl if (!acpi_batteries_initted) 71148352Snjl error = acpi_battery_init(); 72148352Snjl ACPI_SERIAL_END(battery); 73148352Snjl return (error); 74133614Snjl} 75133614Snjl 76133614Snjlint 77148352Snjlacpi_battery_remove(device_t dev) 78148352Snjl{ 79148352Snjl 80148352Snjl return (0); 81148352Snjl} 82148352Snjl 83148352Snjlint 8479282Smsmithacpi_battery_get_units(void) 8579282Smsmith{ 86148352Snjl devclass_t batt_dc; 87148352Snjl 88148352Snjl batt_dc = devclass_find("battery"); 89148352Snjl if (batt_dc == NULL) 90148352Snjl return (0); 91148352Snjl return (devclass_get_count(batt_dc)); 9279282Smsmith} 9379282Smsmith 9485556Siwasakiint 95148352Snjlacpi_battery_get_info_expire(void) 9679282Smsmith{ 9779282Smsmith 98148352Snjl return (acpi_battery_info_expire); 99148352Snjl} 10079282Smsmith 101148352Snjl/* Check _BST results for validity. */ 102148352Snjlint 103148352Snjlacpi_battery_bst_valid(struct acpi_bst *bst) 104148352Snjl{ 105216503Savg 106216503Savg return (bst->state != ACPI_BATT_STAT_NOT_PRESENT && 107216503Savg bst->cap != ACPI_BATT_UNKNOWN && bst->volt != ACPI_BATT_UNKNOWN); 108148352Snjl} 10979282Smsmith 110148352Snjl/* Check _BIF results for validity. */ 111148352Snjlint 112148352Snjlacpi_battery_bif_valid(struct acpi_bif *bif) 113148352Snjl{ 114152703Snjl return (bif->lfcap != 0); 11579282Smsmith} 11679282Smsmith 117148352Snjl/* Get info about one or all batteries. */ 11885556Siwasakiint 119148352Snjlacpi_battery_get_battinfo(device_t dev, struct acpi_battinfo *battinfo) 12079282Smsmith{ 121148352Snjl int batt_stat, devcount, dev_idx, error, i; 122148352Snjl int total_cap, total_min, valid_rate, valid_units; 123148352Snjl devclass_t batt_dc; 124148352Snjl device_t batt_dev; 125148352Snjl struct acpi_bst *bst; 126148352Snjl struct acpi_bif *bif; 127148352Snjl struct acpi_battinfo *bi; 12879282Smsmith 129148352Snjl /* 130151563Snjl * Get the battery devclass and max unit for battery devices. If there 131151563Snjl * are none or error, return immediately. 132148352Snjl */ 133148352Snjl batt_dc = devclass_find("battery"); 134148352Snjl if (batt_dc == NULL) 135148352Snjl return (ENXIO); 136151563Snjl devcount = devclass_get_maxunit(batt_dc); 137148352Snjl if (devcount == 0) 138148352Snjl return (ENXIO); 139148352Snjl 140148352Snjl /* 141148352Snjl * Allocate storage for all _BST data, their derived battinfo data, 142148352Snjl * and the current battery's _BIF data. 143148352Snjl */ 144148489Snjl bst = malloc(devcount * sizeof(*bst), M_TEMP, M_WAITOK | M_ZERO); 145148489Snjl bi = malloc(devcount * sizeof(*bi), M_TEMP, M_WAITOK | M_ZERO); 146148489Snjl bif = malloc(sizeof(*bif), M_TEMP, M_WAITOK | M_ZERO); 147148352Snjl 148148352Snjl /* 149148352Snjl * Pass 1: for each battery that is present and valid, get its status, 150148352Snjl * calculate percent capacity remaining, and sum all the current 151148352Snjl * discharge rates. 152148352Snjl */ 153148352Snjl dev_idx = -1; 154148352Snjl batt_stat = valid_rate = valid_units = 0; 155148352Snjl for (i = 0; i < devcount; i++) { 156148352Snjl /* Default info for every battery is "not present". */ 157148352Snjl acpi_reset_battinfo(&bi[i]); 158148352Snjl 159151563Snjl /* 160151563Snjl * Find the device. Since devcount is in terms of max units, this 161151563Snjl * may be a sparse array so skip devices that aren't present. 162151563Snjl */ 163151563Snjl batt_dev = devclass_get_device(batt_dc, i); 164151563Snjl if (batt_dev == NULL) 165151563Snjl continue; 166151563Snjl 167148352Snjl /* If examining a specific battery and this is it, record its index. */ 168148352Snjl if (dev != NULL && dev == batt_dev) 169148352Snjl dev_idx = i; 170148352Snjl 171151563Snjl /* 172173782Sjkim * Be sure we can get various info from the battery. Note that 173173782Sjkim * acpi_BatteryIsPresent() is not enough because smart batteries only 174151563Snjl * return that the device is present. 175151563Snjl */ 176173782Sjkim if (!acpi_BatteryIsPresent(batt_dev) || 177173782Sjkim ACPI_BATT_GET_STATUS(batt_dev, &bst[i]) != 0 || 178148352Snjl ACPI_BATT_GET_INFO(batt_dev, bif) != 0) 179148352Snjl continue; 180148352Snjl 181148352Snjl /* If a battery is not installed, we sometimes get strange values. */ 182148352Snjl if (!acpi_battery_bst_valid(&bst[i]) || 183148352Snjl !acpi_battery_bif_valid(bif)) 184148352Snjl continue; 185148352Snjl 186151563Snjl /* 187151563Snjl * Record current state. If both charging and discharging are set, 188151563Snjl * ignore the charging flag. 189151563Snjl */ 190148352Snjl valid_units++; 191151563Snjl if ((bst[i].state & ACPI_BATT_STAT_DISCHARG) != 0) 192151563Snjl bst[i].state &= ~ACPI_BATT_STAT_CHARGING; 193148352Snjl batt_stat |= bst[i].state; 194148352Snjl bi[i].state = bst[i].state; 195148352Snjl 196148352Snjl /* 197151563Snjl * If the battery info is in terms of mA, convert to mW by 198172490Snjl * multiplying by the design voltage. If the design voltage 199172490Snjl * is 0 (due to some error reading the battery), skip this 200172490Snjl * conversion. 201151563Snjl */ 202187368Smav if (bif->units == ACPI_BIF_UNITS_MA && bif->dvol != 0 && dev == NULL) { 203151563Snjl bst[i].rate = (bst[i].rate * bif->dvol) / 1000; 204151563Snjl bst[i].cap = (bst[i].cap * bif->dvol) / 1000; 205151563Snjl bif->lfcap = (bif->lfcap * bif->dvol) / 1000; 206151563Snjl } 207151563Snjl 208230595Sdumbbell /* 209230595Sdumbbell * The calculation above may set bif->lfcap to zero. This was 210230595Sdumbbell * seen on a laptop with a broken battery. The result of the 211230595Sdumbbell * division was rounded to zero. 212230595Sdumbbell */ 213230595Sdumbbell if (!acpi_battery_bif_valid(bif)) 214230595Sdumbbell continue; 215230595Sdumbbell 216151563Snjl /* Calculate percent capacity remaining. */ 217151563Snjl bi[i].cap = (100 * bst[i].cap) / bif->lfcap; 218151563Snjl 219151563Snjl /* 220148352Snjl * Some laptops report the "design-capacity" instead of the 221148352Snjl * "real-capacity" when the battery is fully charged. That breaks 222148352Snjl * the above arithmetic as it needs to be 100% maximum. 223148352Snjl */ 224148352Snjl if (bi[i].cap > 100) 225148352Snjl bi[i].cap = 100; 226148352Snjl 227148352Snjl /* 228148352Snjl * On systems with more than one battery, they may get used 229148352Snjl * sequentially, thus bst.rate may only signify the one currently 230148352Snjl * in use. For the remaining batteries, bst.rate will be zero, 231148352Snjl * which makes it impossible to calculate the total remaining time. 232148352Snjl * Therefore, we sum the bst.rate for batteries in the discharging 233148352Snjl * state and use the sum to calculate the total remaining time. 234148352Snjl */ 235151563Snjl if (bst[i].rate != ACPI_BATT_UNKNOWN && 236151563Snjl (bst[i].state & ACPI_BATT_STAT_DISCHARG) != 0) 237148352Snjl valid_rate += bst[i].rate; 238118783Snjl } 239118783Snjl 240148352Snjl /* If the caller asked for a device but we didn't find it, error. */ 241151563Snjl if (dev != NULL && dev_idx == -1) { 242148352Snjl error = ENXIO; 243148352Snjl goto out; 244148352Snjl } 245148352Snjl 246148352Snjl /* Pass 2: calculate capacity and remaining time for all batteries. */ 247148352Snjl total_cap = total_min = 0; 248148352Snjl for (i = 0; i < devcount; i++) { 249148352Snjl /* 250148352Snjl * If any batteries are discharging, use the sum of the bst.rate 251148352Snjl * values. Otherwise, we are on AC power, and there is infinite 252148352Snjl * time remaining for this battery until we go offline. 253148352Snjl */ 254148352Snjl if (valid_rate > 0) 255151563Snjl bi[i].min = (60 * bst[i].cap) / valid_rate; 256148352Snjl else 257148352Snjl bi[i].min = 0; 258148352Snjl total_min += bi[i].min; 259148742Snjl 260148742Snjl /* If this battery is not present, don't use its capacity. */ 261148968Snjl if (bi[i].cap != -1) 262148968Snjl total_cap += bi[i].cap; 263148352Snjl } 264148352Snjl 265148352Snjl /* 266148352Snjl * Return total battery percent and time remaining. If there are 267148352Snjl * no valid batteries, report values as unknown. 268148352Snjl */ 269148352Snjl if (valid_units > 0) { 270148352Snjl if (dev == NULL) { 271148352Snjl battinfo->cap = total_cap / valid_units; 272148352Snjl battinfo->min = total_min; 273148352Snjl battinfo->state = batt_stat; 274148352Snjl battinfo->rate = valid_rate; 275148352Snjl } else { 276148352Snjl battinfo->cap = bi[dev_idx].cap; 277148352Snjl battinfo->min = bi[dev_idx].min; 278148352Snjl battinfo->state = bi[dev_idx].state; 279148352Snjl battinfo->rate = bst[dev_idx].rate; 280148352Snjl } 281148400Snjl 282148400Snjl /* 283148400Snjl * If the queried battery has no discharge rate or is charging, 284148400Snjl * report that we don't know the remaining time. 285148400Snjl */ 286148400Snjl if (valid_rate == 0 || (battinfo->state & ACPI_BATT_STAT_CHARGING)) 287148400Snjl battinfo->min = -1; 288148352Snjl } else 289148352Snjl acpi_reset_battinfo(battinfo); 290148352Snjl 291148352Snjl error = 0; 292148352Snjl 29379282Smsmithout: 294148352Snjl if (bi) 295148352Snjl free(bi, M_TEMP); 296148352Snjl if (bif) 297148352Snjl free(bif, M_TEMP); 298148352Snjl if (bst) 299148352Snjl free(bst, M_TEMP); 300118783Snjl return (error); 30179282Smsmith} 30279282Smsmith 303148352Snjlstatic void 304148352Snjlacpi_reset_battinfo(struct acpi_battinfo *info) 305148352Snjl{ 306148352Snjl info->cap = -1; 307148352Snjl info->min = -1; 308148352Snjl info->state = ACPI_BATT_STAT_NOT_PRESENT; 309148352Snjl info->rate = -1; 310148352Snjl} 311148352Snjl 312151563Snjl/* Make string printable, removing invalid chars. */ 313151563Snjlstatic void 314151563Snjlacpi_battery_clean_str(char *str, int len) 315151563Snjl{ 316151563Snjl int i; 317151563Snjl 318151563Snjl for (i = 0; i < len && *str != '\0'; i++, str++) { 319151563Snjl if (!isprint(*str)) 320151563Snjl *str = '?'; 321151563Snjl } 322151563Snjl 323151563Snjl /* NUL-terminate the string if we reached the end. */ 324151563Snjl if (i == len) 325151563Snjl *str = '\0'; 326151563Snjl} 327151563Snjl 328151563Snjl/* 329151563Snjl * The battery interface deals with devices and methods but userland 330151563Snjl * expects a logical unit number. Convert a logical unit to a device_t. 331151563Snjl */ 332151563Snjlstatic device_t 333151563Snjlacpi_battery_find_dev(u_int logical_unit) 334151563Snjl{ 335151563Snjl int found_unit, i, maxunit; 336151563Snjl device_t dev; 337151563Snjl devclass_t batt_dc; 338151563Snjl 339151563Snjl dev = NULL; 340151563Snjl found_unit = 0; 341151563Snjl batt_dc = devclass_find("battery"); 342151563Snjl maxunit = devclass_get_maxunit(batt_dc); 343151563Snjl for (i = 0; i < maxunit; i++) { 344151563Snjl dev = devclass_get_device(batt_dc, i); 345151563Snjl if (dev == NULL) 346151563Snjl continue; 347151563Snjl if (logical_unit == found_unit) 348151563Snjl break; 349151563Snjl found_unit++; 350151563Snjl dev = NULL; 351151563Snjl } 352151563Snjl 353151563Snjl return (dev); 354151563Snjl} 355151563Snjl 35679282Smsmithstatic int 35779282Smsmithacpi_battery_ioctl(u_long cmd, caddr_t addr, void *arg) 35879282Smsmith{ 359118783Snjl union acpi_battery_ioctl_arg *ioctl_arg; 360143771Snjl int error, unit; 361148352Snjl device_t dev; 36279282Smsmith 363253642Savg 364253642Savg /* 365253642Savg * Giant is acquired to work around a reference counting bug in ACPICA 366253642Savg * versions prior to 20130328. If not for that bug this function could 367253642Savg * be executed concurrently without any problems. 368253642Savg * The bug is in acpi_BatteryIsPresent -> AcpiGetObjectInfo call tree, 369253642Savg * where AcpiUtExecute_HID, AcpiUtExecute_UID, etc are executed without 370253642Savg * protection of any ACPICA lock and may concurrently call 371253642Savg * AcpiUtRemoveReference on a battery object. 372253642Savg */ 373253642Savg mtx_lock(&Giant); 374253642Savg 375151563Snjl /* For commands that use the ioctl_arg struct, validate it first. */ 376148352Snjl error = ENXIO; 377151563Snjl unit = 0; 378151563Snjl dev = NULL; 379151563Snjl ioctl_arg = NULL; 380151563Snjl if (IOCPARM_LEN(cmd) == sizeof(*ioctl_arg)) { 381151563Snjl ioctl_arg = (union acpi_battery_ioctl_arg *)addr; 382151563Snjl unit = ioctl_arg->unit; 383151563Snjl if (unit != ACPI_BATTERY_ALL_UNITS) 384151563Snjl dev = acpi_battery_find_dev(unit); 385151563Snjl } 386110894Stakawata 387118783Snjl /* 388118783Snjl * No security check required: information retrieval only. If 389118783Snjl * new functions are added here, a check might be required. 390118783Snjl */ 391118783Snjl switch (cmd) { 392118783Snjl case ACPIIO_BATT_GET_UNITS: 393118783Snjl *(int *)addr = acpi_battery_get_units(); 394165457Simp error = 0; 395118783Snjl break; 396118783Snjl case ACPIIO_BATT_GET_BATTINFO: 397151563Snjl if (dev != NULL || unit == ACPI_BATTERY_ALL_UNITS) { 398151563Snjl bzero(&ioctl_arg->battinfo, sizeof(ioctl_arg->battinfo)); 399148352Snjl error = acpi_battery_get_battinfo(dev, &ioctl_arg->battinfo); 400151563Snjl } 401118783Snjl break; 402148352Snjl case ACPIIO_BATT_GET_BIF: 403151563Snjl if (dev != NULL) { 404151563Snjl bzero(&ioctl_arg->bif, sizeof(ioctl_arg->bif)); 405148352Snjl error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bif); 406151563Snjl 407151563Snjl /* 408151563Snjl * Remove invalid characters. Perhaps this should be done 409151563Snjl * within a convenience function so all callers get the 410151563Snjl * benefit. 411151563Snjl */ 412151563Snjl acpi_battery_clean_str(ioctl_arg->bif.model, 413151563Snjl sizeof(ioctl_arg->bif.model)); 414151563Snjl acpi_battery_clean_str(ioctl_arg->bif.serial, 415151563Snjl sizeof(ioctl_arg->bif.serial)); 416151563Snjl acpi_battery_clean_str(ioctl_arg->bif.type, 417151563Snjl sizeof(ioctl_arg->bif.type)); 418151563Snjl acpi_battery_clean_str(ioctl_arg->bif.oeminfo, 419151563Snjl sizeof(ioctl_arg->bif.oeminfo)); 420151563Snjl } 421148352Snjl break; 422148352Snjl case ACPIIO_BATT_GET_BST: 423151563Snjl if (dev != NULL) { 424151563Snjl bzero(&ioctl_arg->bst, sizeof(ioctl_arg->bst)); 425148352Snjl error = ACPI_BATT_GET_STATUS(dev, &ioctl_arg->bst); 426151563Snjl } 427148352Snjl break; 428118783Snjl default: 429118783Snjl error = EINVAL; 430118783Snjl } 431110894Stakawata 432253642Savg mtx_unlock(&Giant); 433118783Snjl return (error); 43479282Smsmith} 43579282Smsmith 43679282Smsmithstatic int 43779282Smsmithacpi_battery_sysctl(SYSCTL_HANDLER_ARGS) 43879282Smsmith{ 439143771Snjl int val, error; 44079282Smsmith 441148352Snjl acpi_battery_get_battinfo(NULL, &acpi_battery_battinfo); 442118783Snjl val = *(u_int *)oidp->oid_arg1; 443118783Snjl error = sysctl_handle_int(oidp, &val, 0, req); 444118783Snjl return (error); 44579282Smsmith} 44679282Smsmith 44779282Smsmithstatic int 448148352Snjlacpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS) 449148352Snjl{ 450148352Snjl int count, error; 451148352Snjl 452148352Snjl count = acpi_battery_get_units(); 453148352Snjl error = sysctl_handle_int(oidp, &count, 0, req); 454148352Snjl return (error); 455148352Snjl} 456148352Snjl 457148352Snjlstatic int 45879282Smsmithacpi_battery_init(void) 45979282Smsmith{ 460118783Snjl struct acpi_softc *sc; 461118783Snjl device_t dev; 462118783Snjl int error; 46379282Smsmith 464133614Snjl ACPI_SERIAL_ASSERT(battery); 465133614Snjl 466133614Snjl error = ENXIO; 467118783Snjl dev = devclass_get_device(devclass_find("acpi"), 0); 468118783Snjl if (dev == NULL) 469133614Snjl goto out; 470118783Snjl sc = device_get_softc(dev); 47179282Smsmith 472118783Snjl error = acpi_register_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl, 473133614Snjl NULL); 474118783Snjl if (error != 0) 475133614Snjl goto out; 476148352Snjl error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl, 477133614Snjl NULL); 478118783Snjl if (error != 0) 479133614Snjl goto out; 480148352Snjl error = acpi_register_ioctl(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl, NULL); 481118783Snjl if (error != 0) 482133614Snjl goto out; 483148352Snjl error = acpi_register_ioctl(ACPIIO_BATT_GET_BST, acpi_battery_ioctl, NULL); 484148352Snjl if (error != 0) 485148352Snjl goto out; 48679282Smsmith 487148352Snjl sysctl_ctx_init(&acpi_battery_sysctl_ctx); 488148352Snjl acpi_battery_sysctl_tree = SYSCTL_ADD_NODE(&acpi_battery_sysctl_ctx, 489133614Snjl SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "battery", CTLFLAG_RD, 490148492Snjl 0, "battery status and info"); 491148352Snjl SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx, 492148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 493118783Snjl OID_AUTO, "life", CTLTYPE_INT | CTLFLAG_RD, 494148492Snjl &acpi_battery_battinfo.cap, 0, acpi_battery_sysctl, "I", 495148492Snjl "percent capacity remaining"); 496148352Snjl SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx, 497148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 498118783Snjl OID_AUTO, "time", CTLTYPE_INT | CTLFLAG_RD, 499148492Snjl &acpi_battery_battinfo.min, 0, acpi_battery_sysctl, "I", 500148492Snjl "remaining time in minutes"); 501148352Snjl SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx, 502148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 503118783Snjl OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RD, 504148492Snjl &acpi_battery_battinfo.state, 0, acpi_battery_sysctl, "I", 505148492Snjl "current status flags"); 506148352Snjl SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx, 507148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 508148352Snjl OID_AUTO, "units", CTLTYPE_INT | CTLFLAG_RD, 509148492Snjl NULL, 0, acpi_battery_units_sysctl, "I", "number of batteries"); 510148352Snjl SYSCTL_ADD_INT(&acpi_battery_sysctl_ctx, 511148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 512159476Snjl OID_AUTO, "info_expire", CTLFLAG_RW, 513148492Snjl &acpi_battery_info_expire, 0, 514148492Snjl "time in seconds until info is refreshed"); 51579282Smsmith 516133614Snjl acpi_batteries_initted = TRUE; 517133614Snjl 518133614Snjlout: 519148352Snjl if (error != 0) { 520148352Snjl acpi_deregister_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl); 521148352Snjl acpi_deregister_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl); 522148352Snjl acpi_deregister_ioctl(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl); 523148352Snjl acpi_deregister_ioctl(ACPIIO_BATT_GET_BST, acpi_battery_ioctl); 524133614Snjl } 525133614Snjl return (error); 52679282Smsmith} 527