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: releng/10.2/sys/dev/acpica/acpi_battery.c 227992 2011-11-26 13:43:50Z dumbbell $"); 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 208227992Sdumbbell /* 209227992Sdumbbell * The calculation above may set bif->lfcap to zero. This was 210227992Sdumbbell * seen on a laptop with a broken battery. The result of the 211227992Sdumbbell * division was rounded to zero. 212227992Sdumbbell */ 213227992Sdumbbell if (!acpi_battery_bif_valid(bif)) 214227992Sdumbbell continue; 215227992Sdumbbell 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 363151563Snjl /* For commands that use the ioctl_arg struct, validate it first. */ 364148352Snjl error = ENXIO; 365151563Snjl unit = 0; 366151563Snjl dev = NULL; 367151563Snjl ioctl_arg = NULL; 368151563Snjl if (IOCPARM_LEN(cmd) == sizeof(*ioctl_arg)) { 369151563Snjl ioctl_arg = (union acpi_battery_ioctl_arg *)addr; 370151563Snjl unit = ioctl_arg->unit; 371151563Snjl if (unit != ACPI_BATTERY_ALL_UNITS) 372151563Snjl dev = acpi_battery_find_dev(unit); 373151563Snjl } 374110894Stakawata 375118783Snjl /* 376118783Snjl * No security check required: information retrieval only. If 377118783Snjl * new functions are added here, a check might be required. 378118783Snjl */ 379118783Snjl switch (cmd) { 380118783Snjl case ACPIIO_BATT_GET_UNITS: 381118783Snjl *(int *)addr = acpi_battery_get_units(); 382165457Simp error = 0; 383118783Snjl break; 384118783Snjl case ACPIIO_BATT_GET_BATTINFO: 385151563Snjl if (dev != NULL || unit == ACPI_BATTERY_ALL_UNITS) { 386151563Snjl bzero(&ioctl_arg->battinfo, sizeof(ioctl_arg->battinfo)); 387148352Snjl error = acpi_battery_get_battinfo(dev, &ioctl_arg->battinfo); 388151563Snjl } 389118783Snjl break; 390148352Snjl case ACPIIO_BATT_GET_BIF: 391151563Snjl if (dev != NULL) { 392151563Snjl bzero(&ioctl_arg->bif, sizeof(ioctl_arg->bif)); 393148352Snjl error = ACPI_BATT_GET_INFO(dev, &ioctl_arg->bif); 394151563Snjl 395151563Snjl /* 396151563Snjl * Remove invalid characters. Perhaps this should be done 397151563Snjl * within a convenience function so all callers get the 398151563Snjl * benefit. 399151563Snjl */ 400151563Snjl acpi_battery_clean_str(ioctl_arg->bif.model, 401151563Snjl sizeof(ioctl_arg->bif.model)); 402151563Snjl acpi_battery_clean_str(ioctl_arg->bif.serial, 403151563Snjl sizeof(ioctl_arg->bif.serial)); 404151563Snjl acpi_battery_clean_str(ioctl_arg->bif.type, 405151563Snjl sizeof(ioctl_arg->bif.type)); 406151563Snjl acpi_battery_clean_str(ioctl_arg->bif.oeminfo, 407151563Snjl sizeof(ioctl_arg->bif.oeminfo)); 408151563Snjl } 409148352Snjl break; 410148352Snjl case ACPIIO_BATT_GET_BST: 411151563Snjl if (dev != NULL) { 412151563Snjl bzero(&ioctl_arg->bst, sizeof(ioctl_arg->bst)); 413148352Snjl error = ACPI_BATT_GET_STATUS(dev, &ioctl_arg->bst); 414151563Snjl } 415148352Snjl break; 416118783Snjl default: 417118783Snjl error = EINVAL; 418118783Snjl } 419110894Stakawata 420118783Snjl return (error); 42179282Smsmith} 42279282Smsmith 42379282Smsmithstatic int 42479282Smsmithacpi_battery_sysctl(SYSCTL_HANDLER_ARGS) 42579282Smsmith{ 426143771Snjl int val, error; 42779282Smsmith 428148352Snjl acpi_battery_get_battinfo(NULL, &acpi_battery_battinfo); 429118783Snjl val = *(u_int *)oidp->oid_arg1; 430118783Snjl error = sysctl_handle_int(oidp, &val, 0, req); 431118783Snjl return (error); 43279282Smsmith} 43379282Smsmith 43479282Smsmithstatic int 435148352Snjlacpi_battery_units_sysctl(SYSCTL_HANDLER_ARGS) 436148352Snjl{ 437148352Snjl int count, error; 438148352Snjl 439148352Snjl count = acpi_battery_get_units(); 440148352Snjl error = sysctl_handle_int(oidp, &count, 0, req); 441148352Snjl return (error); 442148352Snjl} 443148352Snjl 444148352Snjlstatic int 44579282Smsmithacpi_battery_init(void) 44679282Smsmith{ 447118783Snjl struct acpi_softc *sc; 448118783Snjl device_t dev; 449118783Snjl int error; 45079282Smsmith 451133614Snjl ACPI_SERIAL_ASSERT(battery); 452133614Snjl 453133614Snjl error = ENXIO; 454118783Snjl dev = devclass_get_device(devclass_find("acpi"), 0); 455118783Snjl if (dev == NULL) 456133614Snjl goto out; 457118783Snjl sc = device_get_softc(dev); 45879282Smsmith 459118783Snjl error = acpi_register_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl, 460133614Snjl NULL); 461118783Snjl if (error != 0) 462133614Snjl goto out; 463148352Snjl error = acpi_register_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl, 464133614Snjl NULL); 465118783Snjl if (error != 0) 466133614Snjl goto out; 467148352Snjl error = acpi_register_ioctl(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl, NULL); 468118783Snjl if (error != 0) 469133614Snjl goto out; 470148352Snjl error = acpi_register_ioctl(ACPIIO_BATT_GET_BST, acpi_battery_ioctl, NULL); 471148352Snjl if (error != 0) 472148352Snjl goto out; 47379282Smsmith 474148352Snjl sysctl_ctx_init(&acpi_battery_sysctl_ctx); 475148352Snjl acpi_battery_sysctl_tree = SYSCTL_ADD_NODE(&acpi_battery_sysctl_ctx, 476133614Snjl SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, "battery", CTLFLAG_RD, 477148492Snjl 0, "battery status and info"); 478148352Snjl SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx, 479148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 480118783Snjl OID_AUTO, "life", CTLTYPE_INT | CTLFLAG_RD, 481148492Snjl &acpi_battery_battinfo.cap, 0, acpi_battery_sysctl, "I", 482148492Snjl "percent capacity remaining"); 483148352Snjl SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx, 484148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 485118783Snjl OID_AUTO, "time", CTLTYPE_INT | CTLFLAG_RD, 486148492Snjl &acpi_battery_battinfo.min, 0, acpi_battery_sysctl, "I", 487148492Snjl "remaining time in minutes"); 488148352Snjl SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx, 489148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 490118783Snjl OID_AUTO, "state", CTLTYPE_INT | CTLFLAG_RD, 491148492Snjl &acpi_battery_battinfo.state, 0, acpi_battery_sysctl, "I", 492148492Snjl "current status flags"); 493148352Snjl SYSCTL_ADD_PROC(&acpi_battery_sysctl_ctx, 494148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 495148352Snjl OID_AUTO, "units", CTLTYPE_INT | CTLFLAG_RD, 496148492Snjl NULL, 0, acpi_battery_units_sysctl, "I", "number of batteries"); 497148352Snjl SYSCTL_ADD_INT(&acpi_battery_sysctl_ctx, 498148352Snjl SYSCTL_CHILDREN(acpi_battery_sysctl_tree), 499159476Snjl OID_AUTO, "info_expire", CTLFLAG_RW, 500148492Snjl &acpi_battery_info_expire, 0, 501148492Snjl "time in seconds until info is refreshed"); 50279282Smsmith 503133614Snjl acpi_batteries_initted = TRUE; 504133614Snjl 505133614Snjlout: 506148352Snjl if (error != 0) { 507148352Snjl acpi_deregister_ioctl(ACPIIO_BATT_GET_UNITS, acpi_battery_ioctl); 508148352Snjl acpi_deregister_ioctl(ACPIIO_BATT_GET_BATTINFO, acpi_battery_ioctl); 509148352Snjl acpi_deregister_ioctl(ACPIIO_BATT_GET_BIF, acpi_battery_ioctl); 510148352Snjl acpi_deregister_ioctl(ACPIIO_BATT_GET_BST, acpi_battery_ioctl); 511133614Snjl } 512133614Snjl return (error); 51379282Smsmith} 514