xref: /freebsd/sys/dev/acpica/acpi_cmbat.c (revision ce6a89e27cd190313be39bb479880aeda4778436)
1 /*-
2  * Copyright (c) 2005 Nate Lawson
3  * Copyright (c) 2000 Munehiro Matsuda
4  * Copyright (c) 2000 Takanori Watanabe
5  * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include "opt_acpi.h"
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/bus.h>
38 #include <sys/ioccom.h>
39 
40 #include <machine/bus.h>
41 #include <sys/rman.h>
42 #include <sys/malloc.h>
43 
44 #include <contrib/dev/acpica/include/acpi.h>
45 
46 #include <dev/acpica/acpivar.h>
47 #include <dev/acpica/acpiio.h>
48 
49 static MALLOC_DEFINE(M_ACPICMBAT, "acpicmbat",
50     "ACPI control method battery data");
51 
52 /* Number of times to retry initialization before giving up. */
53 #define ACPI_CMBAT_RETRY_MAX	6
54 
55 /* Check the battery once a minute. */
56 #define	CMBAT_POLLRATE		(60 * hz)
57 
58 /* Hooks for the ACPI CA debugging infrastructure */
59 #define	_COMPONENT	ACPI_BATTERY
60 ACPI_MODULE_NAME("BATTERY")
61 
62 #define	ACPI_BATTERY_BST_CHANGE	0x80
63 #define	ACPI_BATTERY_BIF_CHANGE	0x81
64 #define	ACPI_BATTERY_BIX_CHANGE	ACPI_BATTERY_BIF_CHANGE
65 
66 struct acpi_cmbat_softc {
67     device_t	    dev;
68     int		    flags;
69 
70     struct acpi_bix bix;
71     struct acpi_bst bst;
72     struct timespec bst_lastupdated;
73 };
74 
75 ACPI_SERIAL_DECL(cmbat, "ACPI cmbat");
76 
77 static int		acpi_cmbat_probe(device_t dev);
78 static int		acpi_cmbat_attach(device_t dev);
79 static int		acpi_cmbat_detach(device_t dev);
80 static int		acpi_cmbat_resume(device_t dev);
81 static void		acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify,
82 			    void *context);
83 static int		acpi_cmbat_info_expired(struct timespec *lastupdated);
84 static void		acpi_cmbat_info_updated(struct timespec *lastupdated);
85 static void		acpi_cmbat_get_bst(void *arg);
86 static void		acpi_cmbat_get_bix_task(void *arg);
87 static void		acpi_cmbat_get_bix(void *arg);
88 static int		acpi_cmbat_bst(device_t, struct acpi_bst *);
89 static int		acpi_cmbat_bix(device_t, void *, size_t);
90 static void		acpi_cmbat_init_battery(void *arg);
91 
92 static device_method_t acpi_cmbat_methods[] = {
93     /* Device interface */
94     DEVMETHOD(device_probe,	acpi_cmbat_probe),
95     DEVMETHOD(device_attach,	acpi_cmbat_attach),
96     DEVMETHOD(device_detach,	acpi_cmbat_detach),
97     DEVMETHOD(device_resume,	acpi_cmbat_resume),
98 
99     /* ACPI battery interface */
100     DEVMETHOD(acpi_batt_get_info, acpi_cmbat_bix),
101     DEVMETHOD(acpi_batt_get_status, acpi_cmbat_bst),
102 
103     DEVMETHOD_END
104 };
105 
106 static driver_t acpi_cmbat_driver = {
107     "battery",
108     acpi_cmbat_methods,
109     sizeof(struct acpi_cmbat_softc),
110 };
111 
112 static devclass_t acpi_cmbat_devclass;
113 DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0);
114 MODULE_DEPEND(acpi_cmbat, acpi, 1, 1, 1);
115 
116 static int
117 acpi_cmbat_probe(device_t dev)
118 {
119     static char *cmbat_ids[] = { "PNP0C0A", NULL };
120     int rv;
121 
122     if (acpi_disabled("cmbat"))
123 	return (ENXIO);
124     rv = ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids, NULL);
125     if (rv <= 0)
126 	device_set_desc(dev, "ACPI Control Method Battery");
127     return (rv);
128 }
129 
130 static int
131 acpi_cmbat_attach(device_t dev)
132 {
133     int		error;
134     ACPI_HANDLE	handle;
135     struct acpi_cmbat_softc *sc;
136 
137     sc = device_get_softc(dev);
138     handle = acpi_get_handle(dev);
139     sc->dev = dev;
140 
141     timespecclear(&sc->bst_lastupdated);
142 
143     error = acpi_battery_register(dev);
144     if (error != 0) {
145     	device_printf(dev, "registering battery failed\n");
146 	return (error);
147     }
148 
149     /*
150      * Install a system notify handler in addition to the device notify.
151      * Toshiba notebook uses this alternate notify for its battery.
152      */
153     AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY,
154 	acpi_cmbat_notify_handler, dev);
155 
156     AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev);
157 
158     return (0);
159 }
160 
161 static int
162 acpi_cmbat_detach(device_t dev)
163 {
164     ACPI_HANDLE	handle;
165 
166     handle = acpi_get_handle(dev);
167     AcpiRemoveNotifyHandler(handle, ACPI_ALL_NOTIFY, acpi_cmbat_notify_handler);
168     acpi_battery_remove(dev);
169 
170     /*
171      * Force any pending notification handler calls to complete by
172      * requesting cmbat serialisation while freeing and clearing the
173      * softc pointer:
174      */
175     ACPI_SERIAL_BEGIN(cmbat);
176     device_set_softc(dev, NULL);
177     ACPI_SERIAL_END(cmbat);
178 
179     return (0);
180 }
181 
182 static int
183 acpi_cmbat_resume(device_t dev)
184 {
185 
186     AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev);
187     return (0);
188 }
189 
190 static void
191 acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
192 {
193     struct acpi_cmbat_softc *sc;
194     device_t dev;
195 
196     dev = (device_t)context;
197     sc = device_get_softc(dev);
198 
199     switch (notify) {
200     case ACPI_NOTIFY_DEVICE_CHECK:
201     case ACPI_BATTERY_BST_CHANGE:
202 	/*
203 	 * Clear the last updated time.  The next call to retrieve the
204 	 * battery status will get the new value for us.
205 	 */
206 	timespecclear(&sc->bst_lastupdated);
207 	break;
208     case ACPI_NOTIFY_BUS_CHECK:
209     case ACPI_BATTERY_BIX_CHANGE:
210 	/*
211 	 * Queue a callback to get the current battery info from thread
212 	 * context.  It's not safe to block in a notify handler.
213 	 */
214 	AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_get_bix_task, dev);
215 	break;
216     }
217 
218     acpi_UserNotify("CMBAT", h, notify);
219 }
220 
221 static int
222 acpi_cmbat_info_expired(struct timespec *lastupdated)
223 {
224     struct timespec	curtime;
225 
226     ACPI_SERIAL_ASSERT(cmbat);
227 
228     if (lastupdated == NULL)
229 	return (TRUE);
230     if (!timespecisset(lastupdated))
231 	return (TRUE);
232 
233     getnanotime(&curtime);
234     timespecsub(&curtime, lastupdated, &curtime);
235     return (curtime.tv_sec < 0 ||
236 	    curtime.tv_sec > acpi_battery_get_info_expire());
237 }
238 
239 static void
240 acpi_cmbat_info_updated(struct timespec *lastupdated)
241 {
242 
243     ACPI_SERIAL_ASSERT(cmbat);
244 
245     if (lastupdated != NULL)
246 	getnanotime(lastupdated);
247 }
248 
249 static void
250 acpi_cmbat_get_bst(void *arg)
251 {
252     struct acpi_cmbat_softc *sc;
253     ACPI_STATUS	as;
254     ACPI_OBJECT	*res;
255     ACPI_HANDLE	h;
256     ACPI_BUFFER	bst_buffer;
257     device_t dev;
258 
259     ACPI_SERIAL_ASSERT(cmbat);
260 
261     dev = arg;
262     sc = device_get_softc(dev);
263     h = acpi_get_handle(dev);
264     bst_buffer.Pointer = NULL;
265     bst_buffer.Length = ACPI_ALLOCATE_BUFFER;
266 
267     if (!acpi_cmbat_info_expired(&sc->bst_lastupdated))
268 	goto end;
269 
270     as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer);
271     if (ACPI_FAILURE(as)) {
272 	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
273 	    "error fetching current battery status -- %s\n",
274 	    AcpiFormatException(as));
275 	goto end;
276     }
277 
278     res = (ACPI_OBJECT *)bst_buffer.Pointer;
279     if (!ACPI_PKG_VALID(res, 4)) {
280 	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
281 	    "battery status corrupted\n");
282 	goto end;
283     }
284 
285     if (acpi_PkgInt32(res, 0, &sc->bst.state) != 0)
286 	goto end;
287     if (acpi_PkgInt32(res, 1, &sc->bst.rate) != 0)
288 	goto end;
289     if (acpi_PkgInt32(res, 2, &sc->bst.cap) != 0)
290 	goto end;
291     if (acpi_PkgInt32(res, 3, &sc->bst.volt) != 0)
292 	goto end;
293     acpi_cmbat_info_updated(&sc->bst_lastupdated);
294 
295     /* Clear out undefined/extended bits that might be set by hardware. */
296     sc->bst.state &= ACPI_BATT_STAT_BST_MASK;
297     if ((sc->bst.state & ACPI_BATT_STAT_INVALID) == ACPI_BATT_STAT_INVALID)
298 	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
299 	    "battery reports simultaneous charging and discharging\n");
300 
301     /* XXX If all batteries are critical, perhaps we should suspend. */
302     if (sc->bst.state & ACPI_BATT_STAT_CRITICAL) {
303     	if ((sc->flags & ACPI_BATT_STAT_CRITICAL) == 0) {
304 	    sc->flags |= ACPI_BATT_STAT_CRITICAL;
305 	    device_printf(dev, "critically low charge!\n");
306 	}
307     } else
308 	sc->flags &= ~ACPI_BATT_STAT_CRITICAL;
309 
310 end:
311     AcpiOsFree(bst_buffer.Pointer);
312 }
313 
314 /* XXX There should be a cleaner way to do this locking. */
315 static void
316 acpi_cmbat_get_bix_task(void *arg)
317 {
318 
319     ACPI_SERIAL_BEGIN(cmbat);
320     acpi_cmbat_get_bix(arg);
321     ACPI_SERIAL_END(cmbat);
322 }
323 
324 static void
325 acpi_cmbat_get_bix(void *arg)
326 {
327     struct acpi_cmbat_softc *sc;
328     ACPI_STATUS	as;
329     ACPI_OBJECT	*res;
330     ACPI_HANDLE	h;
331     ACPI_BUFFER	bix_buffer;
332     device_t dev;
333     int i, n;
334     const struct {
335 	    enum { _BIX, _BIF } type;
336 	    char *name;
337     } bobjs[] = {
338 	    { _BIX, "_BIX"},
339 	    { _BIF, "_BIF"},
340     };
341 
342     ACPI_SERIAL_ASSERT(cmbat);
343 
344     dev = arg;
345     sc = device_get_softc(dev);
346     h = acpi_get_handle(dev);
347     bix_buffer.Pointer = NULL;
348     bix_buffer.Length = ACPI_ALLOCATE_BUFFER;
349 
350     for (n = 0; n < sizeof(bobjs); n++) {
351 	as = AcpiEvaluateObject(h, bobjs[n].name, NULL, &bix_buffer);
352 	if (!ACPI_FAILURE(as)) {
353 	    res = (ACPI_OBJECT *)bix_buffer.Pointer;
354 	    break;
355 	}
356 	AcpiOsFree(bix_buffer.Pointer);
357         bix_buffer.Pointer = NULL;
358         bix_buffer.Length = ACPI_ALLOCATE_BUFFER;
359     }
360     /* Both _BIF and _BIX were not found. */
361     if (n == sizeof(bobjs)) {
362 	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
363 	    "error fetching current battery info -- %s\n",
364 	    AcpiFormatException(as));
365 	goto end;
366     }
367 
368     /*
369      * ACPI _BIX and _BIF revision mismatch check:
370      *
371      * 1. _BIF has no revision field.  The number of fields must be 13.
372      *
373      * 2. _BIX has a revision field.  As of ACPI 6.3 it must be "0" or
374      *    "1".  The number of fields will be checked---20 and 21,
375      *    respectively.
376      *
377      *    If the revision number is grater than "1" and the number of
378      *    fields is grater than 21, it will be treated as compatible with
379      *    ACPI 6.0 _BIX.  If not, it will be ignored.
380      */
381     i = 0;
382     switch (bobjs[n].type) {
383     case _BIX:
384 	if (acpi_PkgInt16(res, i++, &sc->bix.rev) != 0) {
385 	    ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
386 		"_BIX revision error\n");
387 	    goto end;
388 	}
389 #define	ACPI_BIX_REV_MISMATCH_ERR(x, r) do {			\
390 	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),	\
391 	    "_BIX revision mismatch (%u != %u)\n", x, r);	\
392 	goto end;						\
393 	} while (0)
394 
395 	if (ACPI_PKG_VALID_EQ(res, 21)) {	/* ACPI 6.0 _BIX */
396 	    /*
397 	     * Some models have rev.0 _BIX with 21 members.
398 	     * In that case, treat the first 20 members as rev.0 _BIX.
399 	     */
400 	    if (sc->bix.rev != ACPI_BIX_REV_0 &&
401 	        sc->bix.rev != ACPI_BIX_REV_1)
402 		ACPI_BIX_REV_MISMATCH_ERR(sc->bix.rev, ACPI_BIX_REV_1);
403 	} else if (ACPI_PKG_VALID_EQ(res, 20)) {/* ACPI 4.0 _BIX */
404 	    if (sc->bix.rev != ACPI_BIX_REV_0)
405 		ACPI_BIX_REV_MISMATCH_ERR(sc->bix.rev, ACPI_BIX_REV_0);
406 	} else if (ACPI_PKG_VALID(res, 22)) {
407 	    /* _BIX with 22 or more members. */
408 	    if (ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_1 + 1)) {
409 		/*
410 		 * Unknown revision number.
411 		 * Assume 21 members are compatible with 6.0 _BIX.
412 		 */
413 		ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
414 		    "Unknown _BIX revision(%u). "
415 		    "Assuming compatible with revision %u.\n",
416 		    sc->bix.rev, ACPI_BIX_REV_1);
417 	    } else {
418 		/*
419 		 * Known revision number.  Ignore the extra members.
420 		 */
421 		ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
422 		    "Extra objects found in _BIX were ignored.\n");
423 	    }
424 	} else {
425 		/* Invalid _BIX.  Ignore it. */
426 		ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
427 		    "Invalid _BIX found (rev=%u, count=%u).  Ignored.\n",
428 		    sc->bix.rev, res->Package.Count);
429 		goto end;
430 	}
431 	break;
432 #undef	ACPI_BIX_REV_MISMATCH_ERR
433     case _BIF:
434 	if (ACPI_PKG_VALID_EQ(res, 13))	/* _BIF */
435 	    sc->bix.rev = ACPI_BIX_REV_BIF;
436 	else {
437 		ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
438 		    "Invalid _BIF found (count=%u).  Ignored.\n",
439 		    res->Package.Count);
440 		goto end;
441 	}
442 	break;
443     }
444 
445     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
446 	"rev = %04x\n", sc->bix.rev);
447 #define	BIX_GETU32(NAME)	do {			\
448     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),	\
449 	#NAME " = %u\n", sc->bix.NAME);			\
450     if (acpi_PkgInt32(res, i++, &sc->bix.NAME) != 0)	\
451 	    goto end;					\
452     } while (0)
453 
454     BIX_GETU32(units);
455     BIX_GETU32(dcap);
456     BIX_GETU32(lfcap);
457     BIX_GETU32(btech);
458     BIX_GETU32(dvol);
459     BIX_GETU32(wcap);
460     BIX_GETU32(lcap);
461     if (ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_0)) {
462 	    BIX_GETU32(cycles);
463 	    BIX_GETU32(accuracy);
464 	    BIX_GETU32(stmax);
465 	    BIX_GETU32(stmin);
466 	    BIX_GETU32(aimax);
467 	    BIX_GETU32(aimin);
468     }
469     BIX_GETU32(gra1);
470     BIX_GETU32(gra2);
471     if (acpi_PkgStr(res, i++, sc->bix.model, ACPI_CMBAT_MAXSTRLEN) != 0)
472 	    goto end;
473     if (acpi_PkgStr(res, i++, sc->bix.serial, ACPI_CMBAT_MAXSTRLEN) != 0)
474 	    goto end;
475     if (acpi_PkgStr(res, i++, sc->bix.type, ACPI_CMBAT_MAXSTRLEN) != 0)
476 	    goto end;
477     if (acpi_PkgStr(res, i++, sc->bix.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0)
478 	    goto end;
479     if (ACPI_BIX_REV_MIN_CHECK(sc->bix.rev, ACPI_BIX_REV_1))
480 	    BIX_GETU32(scap);
481 #undef	BIX_GETU32
482 end:
483     AcpiOsFree(bix_buffer.Pointer);
484 }
485 
486 static int
487 acpi_cmbat_bix(device_t dev, void *bix, size_t len)
488 {
489     struct acpi_cmbat_softc *sc;
490 
491     if (len != sizeof(struct acpi_bix) &&
492 	len != sizeof(struct acpi_bif))
493 	    return (-1);
494 
495     sc = device_get_softc(dev);
496 
497     /*
498      * Just copy the data.  The only value that should change is the
499      * last-full capacity, so we only update when we get a notify that says
500      * the info has changed.  Many systems apparently take a long time to
501      * process a _BI[FX] call so we avoid it if possible.
502      */
503     ACPI_SERIAL_BEGIN(cmbat);
504     memcpy(bix, &sc->bix, len);
505     ACPI_SERIAL_END(cmbat);
506 
507     return (0);
508 }
509 
510 static int
511 acpi_cmbat_bst(device_t dev, struct acpi_bst *bst)
512 {
513     struct acpi_cmbat_softc *sc;
514 
515     sc = device_get_softc(dev);
516 
517     ACPI_SERIAL_BEGIN(cmbat);
518     if (acpi_BatteryIsPresent(dev)) {
519 	acpi_cmbat_get_bst(dev);
520 	memcpy(bst, &sc->bst, sizeof(*bst));
521     } else
522 	bst->state = ACPI_BATT_STAT_NOT_PRESENT;
523     ACPI_SERIAL_END(cmbat);
524 
525     return (0);
526 }
527 
528 static void
529 acpi_cmbat_init_battery(void *arg)
530 {
531     struct acpi_cmbat_softc *sc;
532     int		retry, valid;
533     device_t	dev;
534 
535     dev = (device_t)arg;
536     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
537 	"battery enitialization start\n");
538 
539     /*
540      * Try repeatedly to get valid data from the battery.  Since the
541      * embedded controller isn't always ready just after boot, we may have
542      * to wait a while.
543      */
544     for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) {
545 	/*
546 	 * Batteries on DOCK can be ejected w/ DOCK during retrying.
547 	 *
548 	 * If there is a valid softc pointer the device may be in
549 	 * attaching, attached or detaching state. If the state is
550 	 * different from attached retry getting the device state
551 	 * until it becomes stable. This solves a race if the ACPI
552 	 * notification handler is called during attach, because
553 	 * device_is_attached() doesn't return non-zero until after
554 	 * the attach code has been executed.
555 	 */
556 	ACPI_SERIAL_BEGIN(cmbat);
557 	sc = device_get_softc(dev);
558 	if (sc == NULL) {
559 	    ACPI_SERIAL_END(cmbat);
560 	    return;
561 	}
562 
563 	if (!acpi_BatteryIsPresent(dev) || !device_is_attached(dev)) {
564 	    ACPI_SERIAL_END(cmbat);
565 	    continue;
566 	}
567 
568 	/*
569 	 * Only query the battery if this is the first try or the specific
570 	 * type of info is still invalid.
571 	 */
572 	if (retry == 0 || !acpi_battery_bst_valid(&sc->bst)) {
573 	    timespecclear(&sc->bst_lastupdated);
574 	    acpi_cmbat_get_bst(dev);
575 	}
576 	if (retry == 0 || !acpi_battery_bix_valid(&sc->bix))
577 	    acpi_cmbat_get_bix(dev);
578 
579 	valid = acpi_battery_bst_valid(&sc->bst) &&
580 	    acpi_battery_bix_valid(&sc->bix);
581 	ACPI_SERIAL_END(cmbat);
582 
583 	if (valid)
584 	    break;
585     }
586 
587     if (retry == ACPI_CMBAT_RETRY_MAX) {
588 	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
589 	    "battery initialization failed, giving up\n");
590     } else {
591 	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
592 	    "battery initialization done, tried %d times\n", retry + 1);
593     }
594 }
595