170271Stakawata/*- 2148352Snjl * Copyright (c) 2005 Nate Lawson 378662Siwasaki * Copyright (c) 2000 Munehiro Matsuda 470271Stakawata * Copyright (c) 2000 Takanori Watanabe 570271Stakawata * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 670271Stakawata * All rights reserved. 770271Stakawata * 870271Stakawata * Redistribution and use in source and binary forms, with or without 970271Stakawata * modification, are permitted provided that the following conditions 1070271Stakawata * are met: 1170271Stakawata * 1. Redistributions of source code must retain the above copyright 1270271Stakawata * notice, this list of conditions and the following disclaimer. 1370271Stakawata * 2. Redistributions in binary form must reproduce the above copyright 1470271Stakawata * notice, this list of conditions and the following disclaimer in the 1570271Stakawata * documentation and/or other materials provided with the distribution. 1670271Stakawata * 1770271Stakawata * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1870271Stakawata * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1970271Stakawata * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2070271Stakawata * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2170271Stakawata * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2270271Stakawata * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2370271Stakawata * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2470271Stakawata * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2570271Stakawata * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2670271Stakawata * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2770271Stakawata * SUCH DAMAGE. 2870271Stakawata */ 2970271Stakawata 30148352Snjl#include <sys/cdefs.h> 31148352Snjl__FBSDID("$FreeBSD: stable/10/sys/dev/acpica/acpi_cmbat.c 315264 2017-03-14 15:56:19Z hselasky $"); 32148352Snjl 3370271Stakawata#include "opt_acpi.h" 3470271Stakawata#include <sys/param.h> 3570271Stakawata#include <sys/kernel.h> 36129879Sphk#include <sys/module.h> 3770271Stakawata#include <sys/bus.h> 3870271Stakawata#include <sys/ioccom.h> 3970271Stakawata 4070271Stakawata#include <machine/bus.h> 4170271Stakawata#include <sys/rman.h> 4270271Stakawata#include <sys/malloc.h> 4370271Stakawata 44193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 45193530Sjkim 4670271Stakawata#include <dev/acpica/acpivar.h> 4770271Stakawata#include <dev/acpica/acpiio.h> 4870271Stakawata 49227293Sedstatic MALLOC_DEFINE(M_ACPICMBAT, "acpicmbat", 50227293Sed "ACPI control method battery data"); 5185729Siwasaki 52118783Snjl/* Number of times to retry initialization before giving up. */ 53118783Snjl#define ACPI_CMBAT_RETRY_MAX 6 54118783Snjl 55118783Snjl/* Check the battery once a minute. */ 56133615Snjl#define CMBAT_POLLRATE (60 * hz) 5785325Siwasaki 58118783Snjl/* Hooks for the ACPI CA debugging infrastructure */ 5985738Siwasaki#define _COMPONENT ACPI_BATTERY 6091121SmsmithACPI_MODULE_NAME("BATTERY") 6177432Smsmith 62133615Snjl#define ACPI_BATTERY_BST_CHANGE 0x80 63133615Snjl#define ACPI_BATTERY_BIF_CHANGE 0x81 6470340Siwasaki 6585738Siwasakistruct acpi_cmbat_softc { 66118783Snjl device_t dev; 67148352Snjl int flags; 6885738Siwasaki 69118783Snjl struct acpi_bif bif; 70118783Snjl struct acpi_bst bst; 71118783Snjl struct timespec bst_lastupdated; 7285738Siwasaki}; 7385738Siwasaki 74133615SnjlACPI_SERIAL_DECL(cmbat, "ACPI cmbat"); 7585738Siwasaki 76148352Snjlstatic int acpi_cmbat_probe(device_t dev); 77148352Snjlstatic int acpi_cmbat_attach(device_t dev); 78148352Snjlstatic int acpi_cmbat_detach(device_t dev); 79148352Snjlstatic int acpi_cmbat_resume(device_t dev); 80148352Snjlstatic void acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, 81148352Snjl void *context); 82148352Snjlstatic int acpi_cmbat_info_expired(struct timespec *lastupdated); 83148352Snjlstatic void acpi_cmbat_info_updated(struct timespec *lastupdated); 84152705Snjlstatic void acpi_cmbat_get_bst(void *arg); 85152818Snjlstatic void acpi_cmbat_get_bif_task(void *arg); 86152705Snjlstatic void acpi_cmbat_get_bif(void *arg); 87148352Snjlstatic int acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp); 88148352Snjlstatic int acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp); 89148352Snjlstatic void acpi_cmbat_init_battery(void *arg); 9085738Siwasaki 91118926Snjlstatic device_method_t acpi_cmbat_methods[] = { 92118926Snjl /* Device interface */ 93118926Snjl DEVMETHOD(device_probe, acpi_cmbat_probe), 94118926Snjl DEVMETHOD(device_attach, acpi_cmbat_attach), 95132049Snjl DEVMETHOD(device_detach, acpi_cmbat_detach), 96118926Snjl DEVMETHOD(device_resume, acpi_cmbat_resume), 97118926Snjl 98148352Snjl /* ACPI battery interface */ 99148352Snjl DEVMETHOD(acpi_batt_get_info, acpi_cmbat_bif), 100148352Snjl DEVMETHOD(acpi_batt_get_status, acpi_cmbat_bst), 101148352Snjl 102246128Ssbz DEVMETHOD_END 103118926Snjl}; 104118926Snjl 105118926Snjlstatic driver_t acpi_cmbat_driver = { 106148352Snjl "battery", 107118926Snjl acpi_cmbat_methods, 108118926Snjl sizeof(struct acpi_cmbat_softc), 109118926Snjl}; 110118926Snjl 111118926Snjlstatic devclass_t acpi_cmbat_devclass; 112118926SnjlDRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0); 113128071SnjlMODULE_DEPEND(acpi_cmbat, acpi, 1, 1, 1); 114118926Snjl 115118926Snjlstatic int 116148352Snjlacpi_cmbat_probe(device_t dev) 117148352Snjl{ 118148352Snjl static char *cmbat_ids[] = { "PNP0C0A", NULL }; 119148352Snjl 120148352Snjl if (acpi_disabled("cmbat") || 121148352Snjl ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids) == NULL) 122148352Snjl return (ENXIO); 123148352Snjl 124148352Snjl device_set_desc(dev, "ACPI Control Method Battery"); 125148352Snjl return (0); 126148352Snjl} 127148352Snjl 128148352Snjlstatic int 129148352Snjlacpi_cmbat_attach(device_t dev) 130148352Snjl{ 131148352Snjl int error; 132148352Snjl ACPI_HANDLE handle; 133148352Snjl struct acpi_cmbat_softc *sc; 134148352Snjl 135148352Snjl sc = device_get_softc(dev); 136148352Snjl handle = acpi_get_handle(dev); 137148352Snjl sc->dev = dev; 138148352Snjl 139148352Snjl timespecclear(&sc->bst_lastupdated); 140148352Snjl 141148352Snjl error = acpi_battery_register(dev); 142148352Snjl if (error != 0) { 143148352Snjl device_printf(dev, "registering battery failed\n"); 144148352Snjl return (error); 145148352Snjl } 146148352Snjl 147148352Snjl /* 148148352Snjl * Install a system notify handler in addition to the device notify. 149148352Snjl * Toshiba notebook uses this alternate notify for its battery. 150148352Snjl */ 151148352Snjl AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY, 152148352Snjl acpi_cmbat_notify_handler, dev); 153148352Snjl 154167814Sjkim AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev); 155148352Snjl 156148352Snjl return (0); 157148352Snjl} 158148352Snjl 159148352Snjlstatic int 160148352Snjlacpi_cmbat_detach(device_t dev) 161148352Snjl{ 162157778Siwasaki ACPI_HANDLE handle; 163148352Snjl 164157778Siwasaki handle = acpi_get_handle(dev); 165157778Siwasaki AcpiRemoveNotifyHandler(handle, ACPI_ALL_NOTIFY, acpi_cmbat_notify_handler); 166148352Snjl acpi_battery_remove(dev); 167315264Shselasky 168315264Shselasky /* 169315264Shselasky * Force any pending notification handler calls to complete by 170315264Shselasky * requesting cmbat serialisation while freeing and clearing the 171315264Shselasky * softc pointer: 172315264Shselasky */ 173315264Shselasky ACPI_SERIAL_BEGIN(cmbat); 174315264Shselasky device_set_softc(dev, NULL); 175315264Shselasky ACPI_SERIAL_END(cmbat); 176315264Shselasky 177148352Snjl return (0); 178148352Snjl} 179148352Snjl 180148352Snjlstatic int 181148352Snjlacpi_cmbat_resume(device_t dev) 182148352Snjl{ 183148352Snjl 184167814Sjkim AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev); 185148352Snjl return (0); 186148352Snjl} 187148352Snjl 188148352Snjlstatic void 189148352Snjlacpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 190148352Snjl{ 191148352Snjl struct acpi_cmbat_softc *sc; 192148352Snjl device_t dev; 193148352Snjl 194148352Snjl dev = (device_t)context; 195148352Snjl sc = device_get_softc(dev); 196148352Snjl 197148352Snjl switch (notify) { 198148352Snjl case ACPI_NOTIFY_DEVICE_CHECK: 199148352Snjl case ACPI_BATTERY_BST_CHANGE: 200152705Snjl /* 201152705Snjl * Clear the last updated time. The next call to retrieve the 202152705Snjl * battery status will get the new value for us. 203152705Snjl */ 204148352Snjl timespecclear(&sc->bst_lastupdated); 205148352Snjl break; 206148352Snjl case ACPI_NOTIFY_BUS_CHECK: 207148352Snjl case ACPI_BATTERY_BIF_CHANGE: 208152705Snjl /* 209152705Snjl * Queue a callback to get the current battery info from thread 210152705Snjl * context. It's not safe to block in a notify handler. 211152705Snjl */ 212167814Sjkim AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_get_bif_task, dev); 213148352Snjl break; 214148352Snjl } 215148352Snjl 216148352Snjl acpi_UserNotify("CMBAT", h, notify); 217148352Snjl} 218148352Snjl 219148352Snjlstatic int 22078662Siwasakiacpi_cmbat_info_expired(struct timespec *lastupdated) 22178662Siwasaki{ 222118783Snjl struct timespec curtime; 22378662Siwasaki 224133615Snjl ACPI_SERIAL_ASSERT(cmbat); 225133615Snjl 226118783Snjl if (lastupdated == NULL) 227133615Snjl return (TRUE); 228118783Snjl if (!timespecisset(lastupdated)) 229133615Snjl return (TRUE); 23078662Siwasaki 231118783Snjl getnanotime(&curtime); 232118783Snjl timespecsub(&curtime, lastupdated); 233118783Snjl return (curtime.tv_sec < 0 || 234118783Snjl curtime.tv_sec > acpi_battery_get_info_expire()); 23578662Siwasaki} 23678662Siwasaki 237118926Snjlstatic void 23878662Siwasakiacpi_cmbat_info_updated(struct timespec *lastupdated) 23978662Siwasaki{ 240133615Snjl 241133615Snjl ACPI_SERIAL_ASSERT(cmbat); 242133615Snjl 243118783Snjl if (lastupdated != NULL) 244118783Snjl getnanotime(lastupdated); 24578662Siwasaki} 24678662Siwasaki 24770271Stakawatastatic void 248152705Snjlacpi_cmbat_get_bst(void *arg) 24970271Stakawata{ 250118783Snjl struct acpi_cmbat_softc *sc; 251118783Snjl ACPI_STATUS as; 252123777Snjl ACPI_OBJECT *res; 253118783Snjl ACPI_HANDLE h; 254118783Snjl ACPI_BUFFER bst_buffer; 255152705Snjl device_t dev; 25678662Siwasaki 257133615Snjl ACPI_SERIAL_ASSERT(cmbat); 258133615Snjl 259152705Snjl dev = arg; 260118783Snjl sc = device_get_softc(dev); 261118783Snjl h = acpi_get_handle(dev); 262133615Snjl bst_buffer.Pointer = NULL; 263133615Snjl bst_buffer.Length = ACPI_ALLOCATE_BUFFER; 26485738Siwasaki 265118783Snjl if (!acpi_cmbat_info_expired(&sc->bst_lastupdated)) 266133615Snjl goto end; 26778662Siwasaki 268118783Snjl as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer); 269118783Snjl if (ACPI_FAILURE(as)) { 270118783Snjl ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 27188420Siwasaki "error fetching current battery status -- %s\n", 27288420Siwasaki AcpiFormatException(as)); 273118783Snjl goto end; 274118783Snjl } 27570271Stakawata 276118783Snjl res = (ACPI_OBJECT *)bst_buffer.Pointer; 277123777Snjl if (!ACPI_PKG_VALID(res, 4)) { 278118783Snjl ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 27986552Siwasaki "battery status corrupted\n"); 280118783Snjl goto end; 281118783Snjl } 28270271Stakawata 283123777Snjl if (acpi_PkgInt32(res, 0, &sc->bst.state) != 0) 284123777Snjl goto end; 285123777Snjl if (acpi_PkgInt32(res, 1, &sc->bst.rate) != 0) 286123777Snjl goto end; 287123777Snjl if (acpi_PkgInt32(res, 2, &sc->bst.cap) != 0) 288123777Snjl goto end; 289123777Snjl if (acpi_PkgInt32(res, 3, &sc->bst.volt) != 0) 290123777Snjl goto end; 291118783Snjl acpi_cmbat_info_updated(&sc->bst_lastupdated); 292118783Snjl 293216503Savg /* Clear out undefined/extended bits that might be set by hardware. */ 294216503Savg sc->bst.state &= ACPI_BATT_STAT_BST_MASK; 295216503Savg if ((sc->bst.state & ACPI_BATT_STAT_INVALID) == ACPI_BATT_STAT_INVALID) 296216503Savg ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 297216503Savg "battery reports simultaneous charging and discharging\n"); 298216503Savg 299139057Snjl /* XXX If all batteries are critical, perhaps we should suspend. */ 300139057Snjl if (sc->bst.state & ACPI_BATT_STAT_CRITICAL) { 301139057Snjl if ((sc->flags & ACPI_BATT_STAT_CRITICAL) == 0) { 302139057Snjl sc->flags |= ACPI_BATT_STAT_CRITICAL; 303139057Snjl device_printf(dev, "critically low charge!\n"); 304139057Snjl } 305139057Snjl } else 306139057Snjl sc->flags &= ~ACPI_BATT_STAT_CRITICAL; 307136369Snjl 30870271Stakawataend: 309118783Snjl if (bst_buffer.Pointer != NULL) 310118783Snjl AcpiOsFree(bst_buffer.Pointer); 31170271Stakawata} 31270271Stakawata 313152818Snjl/* XXX There should be a cleaner way to do this locking. */ 31470271Stakawatastatic void 315152818Snjlacpi_cmbat_get_bif_task(void *arg) 316152818Snjl{ 317152818Snjl 318152818Snjl ACPI_SERIAL_BEGIN(cmbat); 319152818Snjl acpi_cmbat_get_bif(arg); 320152818Snjl ACPI_SERIAL_END(cmbat); 321152818Snjl} 322152818Snjl 323152818Snjlstatic void 324152705Snjlacpi_cmbat_get_bif(void *arg) 32570271Stakawata{ 326118783Snjl struct acpi_cmbat_softc *sc; 327118783Snjl ACPI_STATUS as; 328123777Snjl ACPI_OBJECT *res; 329118783Snjl ACPI_HANDLE h; 330118783Snjl ACPI_BUFFER bif_buffer; 331152705Snjl device_t dev; 33270271Stakawata 333133615Snjl ACPI_SERIAL_ASSERT(cmbat); 334133615Snjl 335152705Snjl dev = arg; 336118783Snjl sc = device_get_softc(dev); 337118783Snjl h = acpi_get_handle(dev); 338133615Snjl bif_buffer.Pointer = NULL; 339133615Snjl bif_buffer.Length = ACPI_ALLOCATE_BUFFER; 34085738Siwasaki 341118783Snjl as = AcpiEvaluateObject(h, "_BIF", NULL, &bif_buffer); 342118783Snjl if (ACPI_FAILURE(as)) { 343118783Snjl ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 34488420Siwasaki "error fetching current battery info -- %s\n", 34588420Siwasaki AcpiFormatException(as)); 346118783Snjl goto end; 347118783Snjl } 34870271Stakawata 349118783Snjl res = (ACPI_OBJECT *)bif_buffer.Pointer; 350123777Snjl if (!ACPI_PKG_VALID(res, 13)) { 351118783Snjl ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 35286552Siwasaki "battery info corrupted\n"); 353118783Snjl goto end; 354118783Snjl } 35578662Siwasaki 356133615Snjl if (acpi_PkgInt32(res, 0, &sc->bif.units) != 0) 357123777Snjl goto end; 358133615Snjl if (acpi_PkgInt32(res, 1, &sc->bif.dcap) != 0) 359123777Snjl goto end; 360133615Snjl if (acpi_PkgInt32(res, 2, &sc->bif.lfcap) != 0) 361123777Snjl goto end; 362133615Snjl if (acpi_PkgInt32(res, 3, &sc->bif.btech) != 0) 363123777Snjl goto end; 364133615Snjl if (acpi_PkgInt32(res, 4, &sc->bif.dvol) != 0) 365123777Snjl goto end; 366133615Snjl if (acpi_PkgInt32(res, 5, &sc->bif.wcap) != 0) 367123777Snjl goto end; 368133615Snjl if (acpi_PkgInt32(res, 6, &sc->bif.lcap) != 0) 369123777Snjl goto end; 370133615Snjl if (acpi_PkgInt32(res, 7, &sc->bif.gra1) != 0) 371123777Snjl goto end; 372133615Snjl if (acpi_PkgInt32(res, 8, &sc->bif.gra2) != 0) 373123777Snjl goto end; 374123777Snjl if (acpi_PkgStr(res, 9, sc->bif.model, ACPI_CMBAT_MAXSTRLEN) != 0) 375123777Snjl goto end; 376123777Snjl if (acpi_PkgStr(res, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN) != 0) 377123777Snjl goto end; 378123777Snjl if (acpi_PkgStr(res, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN) != 0) 379123777Snjl goto end; 380123777Snjl if (acpi_PkgStr(res, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0) 381123777Snjl goto end; 382118783Snjl 38370271Stakawataend: 384118783Snjl if (bif_buffer.Pointer != NULL) 385118783Snjl AcpiOsFree(bif_buffer.Pointer); 38670271Stakawata} 38770271Stakawata 38870271Stakawatastatic int 389148352Snjlacpi_cmbat_bif(device_t dev, struct acpi_bif *bifp) 39070271Stakawata{ 391118783Snjl struct acpi_cmbat_softc *sc; 39278662Siwasaki 393133615Snjl sc = device_get_softc(dev); 394119974Snjl 395152705Snjl /* 396152705Snjl * Just copy the data. The only value that should change is the 397152705Snjl * last-full capacity, so we only update when we get a notify that says 398152705Snjl * the info has changed. Many systems apparently take a long time to 399152705Snjl * process a _BIF call so we avoid it if possible. 400152705Snjl */ 401133615Snjl ACPI_SERIAL_BEGIN(cmbat); 402148352Snjl bifp->units = sc->bif.units; 403148352Snjl bifp->dcap = sc->bif.dcap; 404148352Snjl bifp->lfcap = sc->bif.lfcap; 405148352Snjl bifp->btech = sc->bif.btech; 406148352Snjl bifp->dvol = sc->bif.dvol; 407148352Snjl bifp->wcap = sc->bif.wcap; 408148352Snjl bifp->lcap = sc->bif.lcap; 409148352Snjl bifp->gra1 = sc->bif.gra1; 410148352Snjl bifp->gra2 = sc->bif.gra2; 411148352Snjl strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model)); 412148352Snjl strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial)); 413148352Snjl strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type)); 414148352Snjl strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo)); 415133615Snjl ACPI_SERIAL_END(cmbat); 416133615Snjl 417118783Snjl return (0); 41870271Stakawata} 41970271Stakawata 42085325Siwasakistatic int 421148352Snjlacpi_cmbat_bst(device_t dev, struct acpi_bst *bstp) 422132049Snjl{ 423132049Snjl struct acpi_cmbat_softc *sc; 424132049Snjl 425132049Snjl sc = device_get_softc(dev); 426132049Snjl 427133615Snjl ACPI_SERIAL_BEGIN(cmbat); 428148352Snjl if (acpi_BatteryIsPresent(dev)) { 429148352Snjl acpi_cmbat_get_bst(dev); 430148352Snjl bstp->state = sc->bst.state; 431148352Snjl bstp->rate = sc->bst.rate; 432148352Snjl bstp->cap = sc->bst.cap; 433148352Snjl bstp->volt = sc->bst.volt; 434148352Snjl } else 435148352Snjl bstp->state = ACPI_BATT_STAT_NOT_PRESENT; 436133615Snjl ACPI_SERIAL_END(cmbat); 43778662Siwasaki 438118783Snjl return (0); 43970340Siwasaki} 44078662Siwasaki 441106377Siwasakistatic void 442106377Siwasakiacpi_cmbat_init_battery(void *arg) 443106377Siwasaki{ 444133615Snjl struct acpi_cmbat_softc *sc; 445148352Snjl int retry, valid; 446133615Snjl device_t dev; 447106377Siwasaki 448133615Snjl dev = (device_t)arg; 449118783Snjl ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 450118783Snjl "battery initialization start\n"); 451106377Siwasaki 452148352Snjl /* 453148352Snjl * Try repeatedly to get valid data from the battery. Since the 454148352Snjl * embedded controller isn't always ready just after boot, we may have 455148352Snjl * to wait a while. 456148352Snjl */ 457138300Smarks for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) { 458315264Shselasky /* 459315264Shselasky * Batteries on DOCK can be ejected w/ DOCK during retrying. 460315264Shselasky * 461315264Shselasky * If there is a valid softc pointer the device may be in 462315264Shselasky * attaching, attached or detaching state. If the state is 463315264Shselasky * different from attached retry getting the device state 464315264Shselasky * until it becomes stable. This solves a race if the ACPI 465315264Shselasky * notification handler is called during attach, because 466315264Shselasky * device_is_attached() doesn't return non-zero until after 467315264Shselasky * the attach code has been executed. 468315264Shselasky */ 469315264Shselasky ACPI_SERIAL_BEGIN(cmbat); 470315264Shselasky sc = device_get_softc(dev); 471315264Shselasky if (sc == NULL) { 472315264Shselasky ACPI_SERIAL_END(cmbat); 473157774Siwasaki return; 474315264Shselasky } 475157774Siwasaki 476315264Shselasky if (!acpi_BatteryIsPresent(dev) || !device_is_attached(dev)) { 477315264Shselasky ACPI_SERIAL_END(cmbat); 478118783Snjl continue; 479315264Shselasky } 480106377Siwasaki 481152705Snjl /* 482152705Snjl * Only query the battery if this is the first try or the specific 483152705Snjl * type of info is still invalid. 484152705Snjl */ 485152705Snjl if (retry == 0 || !acpi_battery_bst_valid(&sc->bst)) { 486152705Snjl timespecclear(&sc->bst_lastupdated); 487152705Snjl acpi_cmbat_get_bst(dev); 488152705Snjl } 489152705Snjl if (retry == 0 || !acpi_battery_bif_valid(&sc->bif)) 490152705Snjl acpi_cmbat_get_bif(dev); 491152705Snjl 492148352Snjl valid = acpi_battery_bst_valid(&sc->bst) && 493148352Snjl acpi_battery_bif_valid(&sc->bif); 494133615Snjl ACPI_SERIAL_END(cmbat); 495106377Siwasaki 496148352Snjl if (valid) 497133615Snjl break; 498118783Snjl } 499106377Siwasaki 500118783Snjl if (retry == ACPI_CMBAT_RETRY_MAX) { 501118783Snjl ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 502118783Snjl "battery initialization failed, giving up\n"); 503118783Snjl } else { 504118783Snjl ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 505118783Snjl "battery initialization done, tried %d times\n", retry + 1); 506118783Snjl } 507106377Siwasaki} 508