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$");
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);
167148352Snjl    return (0);
168148352Snjl}
169148352Snjl
170148352Snjlstatic int
171148352Snjlacpi_cmbat_resume(device_t dev)
172148352Snjl{
173148352Snjl
174167814Sjkim    AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev);
175148352Snjl    return (0);
176148352Snjl}
177148352Snjl
178148352Snjlstatic void
179148352Snjlacpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
180148352Snjl{
181148352Snjl    struct acpi_cmbat_softc *sc;
182148352Snjl    device_t dev;
183148352Snjl
184148352Snjl    dev = (device_t)context;
185148352Snjl    sc = device_get_softc(dev);
186148352Snjl
187148352Snjl    switch (notify) {
188148352Snjl    case ACPI_NOTIFY_DEVICE_CHECK:
189148352Snjl    case ACPI_BATTERY_BST_CHANGE:
190152705Snjl	/*
191152705Snjl	 * Clear the last updated time.  The next call to retrieve the
192152705Snjl	 * battery status will get the new value for us.
193152705Snjl	 */
194148352Snjl	timespecclear(&sc->bst_lastupdated);
195148352Snjl	break;
196148352Snjl    case ACPI_NOTIFY_BUS_CHECK:
197148352Snjl    case ACPI_BATTERY_BIF_CHANGE:
198152705Snjl	/*
199152705Snjl	 * Queue a callback to get the current battery info from thread
200152705Snjl	 * context.  It's not safe to block in a notify handler.
201152705Snjl	 */
202167814Sjkim	AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_get_bif_task, dev);
203148352Snjl	break;
204148352Snjl    }
205148352Snjl
206148352Snjl    acpi_UserNotify("CMBAT", h, notify);
207148352Snjl}
208148352Snjl
209148352Snjlstatic int
21078662Siwasakiacpi_cmbat_info_expired(struct timespec *lastupdated)
21178662Siwasaki{
212118783Snjl    struct timespec	curtime;
21378662Siwasaki
214133615Snjl    ACPI_SERIAL_ASSERT(cmbat);
215133615Snjl
216118783Snjl    if (lastupdated == NULL)
217133615Snjl	return (TRUE);
218118783Snjl    if (!timespecisset(lastupdated))
219133615Snjl	return (TRUE);
22078662Siwasaki
221118783Snjl    getnanotime(&curtime);
222118783Snjl    timespecsub(&curtime, lastupdated);
223118783Snjl    return (curtime.tv_sec < 0 ||
224118783Snjl	    curtime.tv_sec > acpi_battery_get_info_expire());
22578662Siwasaki}
22678662Siwasaki
227118926Snjlstatic void
22878662Siwasakiacpi_cmbat_info_updated(struct timespec *lastupdated)
22978662Siwasaki{
230133615Snjl
231133615Snjl    ACPI_SERIAL_ASSERT(cmbat);
232133615Snjl
233118783Snjl    if (lastupdated != NULL)
234118783Snjl	getnanotime(lastupdated);
23578662Siwasaki}
23678662Siwasaki
23770271Stakawatastatic void
238152705Snjlacpi_cmbat_get_bst(void *arg)
23970271Stakawata{
240118783Snjl    struct acpi_cmbat_softc *sc;
241118783Snjl    ACPI_STATUS	as;
242123777Snjl    ACPI_OBJECT	*res;
243118783Snjl    ACPI_HANDLE	h;
244118783Snjl    ACPI_BUFFER	bst_buffer;
245152705Snjl    device_t dev;
24678662Siwasaki
247133615Snjl    ACPI_SERIAL_ASSERT(cmbat);
248133615Snjl
249152705Snjl    dev = arg;
250118783Snjl    sc = device_get_softc(dev);
251118783Snjl    h = acpi_get_handle(dev);
252133615Snjl    bst_buffer.Pointer = NULL;
253133615Snjl    bst_buffer.Length = ACPI_ALLOCATE_BUFFER;
25485738Siwasaki
255118783Snjl    if (!acpi_cmbat_info_expired(&sc->bst_lastupdated))
256133615Snjl	goto end;
25778662Siwasaki
258118783Snjl    as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer);
259118783Snjl    if (ACPI_FAILURE(as)) {
260118783Snjl	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
26188420Siwasaki		    "error fetching current battery status -- %s\n",
26288420Siwasaki		    AcpiFormatException(as));
263118783Snjl	goto end;
264118783Snjl    }
26570271Stakawata
266118783Snjl    res = (ACPI_OBJECT *)bst_buffer.Pointer;
267123777Snjl    if (!ACPI_PKG_VALID(res, 4)) {
268118783Snjl	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
26986552Siwasaki		    "battery status corrupted\n");
270118783Snjl	goto end;
271118783Snjl    }
27270271Stakawata
273123777Snjl    if (acpi_PkgInt32(res, 0, &sc->bst.state) != 0)
274123777Snjl	goto end;
275123777Snjl    if (acpi_PkgInt32(res, 1, &sc->bst.rate) != 0)
276123777Snjl	goto end;
277123777Snjl    if (acpi_PkgInt32(res, 2, &sc->bst.cap) != 0)
278123777Snjl	goto end;
279123777Snjl    if (acpi_PkgInt32(res, 3, &sc->bst.volt) != 0)
280123777Snjl	goto end;
281118783Snjl    acpi_cmbat_info_updated(&sc->bst_lastupdated);
282118783Snjl
283216503Savg    /* Clear out undefined/extended bits that might be set by hardware. */
284216503Savg    sc->bst.state &= ACPI_BATT_STAT_BST_MASK;
285216503Savg    if ((sc->bst.state & ACPI_BATT_STAT_INVALID) == ACPI_BATT_STAT_INVALID)
286216503Savg	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
287216503Savg	    "battery reports simultaneous charging and discharging\n");
288216503Savg
289139057Snjl    /* XXX If all batteries are critical, perhaps we should suspend. */
290139057Snjl    if (sc->bst.state & ACPI_BATT_STAT_CRITICAL) {
291139057Snjl    	if ((sc->flags & ACPI_BATT_STAT_CRITICAL) == 0) {
292139057Snjl	    sc->flags |= ACPI_BATT_STAT_CRITICAL;
293139057Snjl	    device_printf(dev, "critically low charge!\n");
294139057Snjl	}
295139057Snjl    } else
296139057Snjl	sc->flags &= ~ACPI_BATT_STAT_CRITICAL;
297136369Snjl
29870271Stakawataend:
299118783Snjl    if (bst_buffer.Pointer != NULL)
300118783Snjl	AcpiOsFree(bst_buffer.Pointer);
30170271Stakawata}
30270271Stakawata
303152818Snjl/* XXX There should be a cleaner way to do this locking. */
30470271Stakawatastatic void
305152818Snjlacpi_cmbat_get_bif_task(void *arg)
306152818Snjl{
307152818Snjl
308152818Snjl    ACPI_SERIAL_BEGIN(cmbat);
309152818Snjl    acpi_cmbat_get_bif(arg);
310152818Snjl    ACPI_SERIAL_END(cmbat);
311152818Snjl}
312152818Snjl
313152818Snjlstatic void
314152705Snjlacpi_cmbat_get_bif(void *arg)
31570271Stakawata{
316118783Snjl    struct acpi_cmbat_softc *sc;
317118783Snjl    ACPI_STATUS	as;
318123777Snjl    ACPI_OBJECT	*res;
319118783Snjl    ACPI_HANDLE	h;
320118783Snjl    ACPI_BUFFER	bif_buffer;
321152705Snjl    device_t dev;
32270271Stakawata
323133615Snjl    ACPI_SERIAL_ASSERT(cmbat);
324133615Snjl
325152705Snjl    dev = arg;
326118783Snjl    sc = device_get_softc(dev);
327118783Snjl    h = acpi_get_handle(dev);
328133615Snjl    bif_buffer.Pointer = NULL;
329133615Snjl    bif_buffer.Length = ACPI_ALLOCATE_BUFFER;
33085738Siwasaki
331118783Snjl    as = AcpiEvaluateObject(h, "_BIF", NULL, &bif_buffer);
332118783Snjl    if (ACPI_FAILURE(as)) {
333118783Snjl	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
33488420Siwasaki		    "error fetching current battery info -- %s\n",
33588420Siwasaki		    AcpiFormatException(as));
336118783Snjl	goto end;
337118783Snjl    }
33870271Stakawata
339118783Snjl    res = (ACPI_OBJECT *)bif_buffer.Pointer;
340123777Snjl    if (!ACPI_PKG_VALID(res, 13)) {
341118783Snjl	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
34286552Siwasaki		    "battery info corrupted\n");
343118783Snjl	goto end;
344118783Snjl    }
34578662Siwasaki
346133615Snjl    if (acpi_PkgInt32(res, 0, &sc->bif.units) != 0)
347123777Snjl	goto end;
348133615Snjl    if (acpi_PkgInt32(res, 1, &sc->bif.dcap) != 0)
349123777Snjl	goto end;
350133615Snjl    if (acpi_PkgInt32(res, 2, &sc->bif.lfcap) != 0)
351123777Snjl	goto end;
352133615Snjl    if (acpi_PkgInt32(res, 3, &sc->bif.btech) != 0)
353123777Snjl	goto end;
354133615Snjl    if (acpi_PkgInt32(res, 4, &sc->bif.dvol) != 0)
355123777Snjl	goto end;
356133615Snjl    if (acpi_PkgInt32(res, 5, &sc->bif.wcap) != 0)
357123777Snjl	goto end;
358133615Snjl    if (acpi_PkgInt32(res, 6, &sc->bif.lcap) != 0)
359123777Snjl	goto end;
360133615Snjl    if (acpi_PkgInt32(res, 7, &sc->bif.gra1) != 0)
361123777Snjl	goto end;
362133615Snjl    if (acpi_PkgInt32(res, 8, &sc->bif.gra2) != 0)
363123777Snjl	goto end;
364123777Snjl    if (acpi_PkgStr(res,  9, sc->bif.model, ACPI_CMBAT_MAXSTRLEN) != 0)
365123777Snjl	goto end;
366123777Snjl    if (acpi_PkgStr(res, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN) != 0)
367123777Snjl	goto end;
368123777Snjl    if (acpi_PkgStr(res, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN) != 0)
369123777Snjl	goto end;
370123777Snjl    if (acpi_PkgStr(res, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0)
371123777Snjl	goto end;
372118783Snjl
37370271Stakawataend:
374118783Snjl    if (bif_buffer.Pointer != NULL)
375118783Snjl	AcpiOsFree(bif_buffer.Pointer);
37670271Stakawata}
37770271Stakawata
37870271Stakawatastatic int
379148352Snjlacpi_cmbat_bif(device_t dev, struct acpi_bif *bifp)
38070271Stakawata{
381118783Snjl    struct acpi_cmbat_softc *sc;
38278662Siwasaki
383133615Snjl    sc = device_get_softc(dev);
384119974Snjl
385152705Snjl    /*
386152705Snjl     * Just copy the data.  The only value that should change is the
387152705Snjl     * last-full capacity, so we only update when we get a notify that says
388152705Snjl     * the info has changed.  Many systems apparently take a long time to
389152705Snjl     * process a _BIF call so we avoid it if possible.
390152705Snjl     */
391133615Snjl    ACPI_SERIAL_BEGIN(cmbat);
392148352Snjl    bifp->units = sc->bif.units;
393148352Snjl    bifp->dcap = sc->bif.dcap;
394148352Snjl    bifp->lfcap = sc->bif.lfcap;
395148352Snjl    bifp->btech = sc->bif.btech;
396148352Snjl    bifp->dvol = sc->bif.dvol;
397148352Snjl    bifp->wcap = sc->bif.wcap;
398148352Snjl    bifp->lcap = sc->bif.lcap;
399148352Snjl    bifp->gra1 = sc->bif.gra1;
400148352Snjl    bifp->gra2 = sc->bif.gra2;
401148352Snjl    strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model));
402148352Snjl    strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial));
403148352Snjl    strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type));
404148352Snjl    strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo));
405133615Snjl    ACPI_SERIAL_END(cmbat);
406133615Snjl
407118783Snjl    return (0);
40870271Stakawata}
40970271Stakawata
41085325Siwasakistatic int
411148352Snjlacpi_cmbat_bst(device_t dev, struct acpi_bst *bstp)
412132049Snjl{
413132049Snjl    struct acpi_cmbat_softc *sc;
414132049Snjl
415132049Snjl    sc = device_get_softc(dev);
416132049Snjl
417133615Snjl    ACPI_SERIAL_BEGIN(cmbat);
418148352Snjl    if (acpi_BatteryIsPresent(dev)) {
419148352Snjl	acpi_cmbat_get_bst(dev);
420148352Snjl	bstp->state = sc->bst.state;
421148352Snjl	bstp->rate = sc->bst.rate;
422148352Snjl	bstp->cap = sc->bst.cap;
423148352Snjl	bstp->volt = sc->bst.volt;
424148352Snjl    } else
425148352Snjl	bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
426133615Snjl    ACPI_SERIAL_END(cmbat);
42778662Siwasaki
428118783Snjl    return (0);
42970340Siwasaki}
43078662Siwasaki
431106377Siwasakistatic void
432106377Siwasakiacpi_cmbat_init_battery(void *arg)
433106377Siwasaki{
434133615Snjl    struct acpi_cmbat_softc *sc;
435148352Snjl    int		retry, valid;
436133615Snjl    device_t	dev;
437106377Siwasaki
438133615Snjl    dev = (device_t)arg;
439133615Snjl    sc = device_get_softc(dev);
440118783Snjl    ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
441118783Snjl		"battery initialization start\n");
442106377Siwasaki
443148352Snjl    /*
444148352Snjl     * Try repeatedly to get valid data from the battery.  Since the
445148352Snjl     * embedded controller isn't always ready just after boot, we may have
446148352Snjl     * to wait a while.
447148352Snjl     */
448138300Smarks    for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) {
449157774Siwasaki	/* batteries on DOCK can be ejected w/ DOCK during retrying */
450157774Siwasaki	if (!device_is_attached(dev))
451157774Siwasaki	    return;
452157774Siwasaki
453148352Snjl	if (!acpi_BatteryIsPresent(dev))
454118783Snjl	    continue;
455106377Siwasaki
456152705Snjl	/*
457152705Snjl	 * Only query the battery if this is the first try or the specific
458152705Snjl	 * type of info is still invalid.
459152705Snjl	 */
460133615Snjl	ACPI_SERIAL_BEGIN(cmbat);
461152705Snjl	if (retry == 0 || !acpi_battery_bst_valid(&sc->bst)) {
462152705Snjl	    timespecclear(&sc->bst_lastupdated);
463152705Snjl	    acpi_cmbat_get_bst(dev);
464152705Snjl	}
465152705Snjl	if (retry == 0 || !acpi_battery_bif_valid(&sc->bif))
466152705Snjl	    acpi_cmbat_get_bif(dev);
467152705Snjl
468148352Snjl	valid = acpi_battery_bst_valid(&sc->bst) &&
469148352Snjl	    acpi_battery_bif_valid(&sc->bif);
470133615Snjl	ACPI_SERIAL_END(cmbat);
471106377Siwasaki
472148352Snjl	if (valid)
473133615Snjl	    break;
474118783Snjl    }
475106377Siwasaki
476118783Snjl    if (retry == ACPI_CMBAT_RETRY_MAX) {
477118783Snjl	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
478118783Snjl		    "battery initialization failed, giving up\n");
479118783Snjl    } else {
480118783Snjl	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
481118783Snjl		    "battery initialization done, tried %d times\n", retry + 1);
482118783Snjl    }
483106377Siwasaki}
484