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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * $FreeBSD: head/sys/dev/acpica/acpi_cmbat.c 246128 2013-01-30 18:01:20Z sbz $
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
41 #include <dev/acpica/acpivar.h>
42 #include <dev/acpica/acpiio.h>
44 /* Number of times to retry initialization before giving up. */
45 #define ACPI_CMBAT_RETRY_MAX 6
47 /* Check the battery once a minute. */
48 #define CMBAT_POLLRATE (60 * hz)
50 /* Hooks for the ACPICA debugging infrastructure */
51 #define _COMPONENT ACPI_BATTERY
52 ACPI_MODULE_NAME("BATTERY")
54 #define ACPI_BATTERY_BST_CHANGE 0x80
55 #define ACPI_BATTERY_BIF_CHANGE 0x81
57 struct acpi_cmbat_softc
{
64 struct timespec bst_lastupdated
;
67 ACPI_SERIAL_DECL(cmbat
, "ACPI cmbat");
69 static int acpi_cmbat_probe(device_t dev
);
70 static int acpi_cmbat_attach(device_t dev
);
71 static int acpi_cmbat_detach(device_t dev
);
72 static int acpi_cmbat_resume(device_t dev
);
73 static void acpi_cmbat_notify_handler(ACPI_HANDLE h
, UINT32 notify
,
75 static int acpi_cmbat_info_expired(struct timespec
*lastupdated
);
76 static void acpi_cmbat_info_updated(struct timespec
*lastupdated
);
77 static void acpi_cmbat_get_bst(void *arg
);
78 static void acpi_cmbat_get_bif_task(void *arg
);
79 static void acpi_cmbat_get_bif(void *arg
);
80 static int acpi_cmbat_bst(device_t dev
, struct acpi_bst
*bstp
);
81 static int acpi_cmbat_bif(device_t dev
, struct acpi_bif
*bifp
);
82 static void acpi_cmbat_init_battery(void *arg
);
84 static device_method_t acpi_cmbat_methods
[] = {
85 /* Device interface */
86 DEVMETHOD(device_probe
, acpi_cmbat_probe
),
87 DEVMETHOD(device_attach
, acpi_cmbat_attach
),
88 DEVMETHOD(device_detach
, acpi_cmbat_detach
),
89 DEVMETHOD(device_resume
, acpi_cmbat_resume
),
91 /* ACPI battery interface */
92 DEVMETHOD(acpi_batt_get_info
, acpi_cmbat_bif
),
93 DEVMETHOD(acpi_batt_get_status
, acpi_cmbat_bst
),
98 static driver_t acpi_cmbat_driver
= {
101 sizeof(struct acpi_cmbat_softc
),
104 static devclass_t acpi_cmbat_devclass
;
105 DRIVER_MODULE(acpi_cmbat
, acpi
, acpi_cmbat_driver
, acpi_cmbat_devclass
, NULL
, NULL
);
106 MODULE_DEPEND(acpi_cmbat
, acpi
, 1, 1, 1);
109 acpi_cmbat_probe(device_t dev
)
111 static char *cmbat_ids
[] = { "PNP0C0A", NULL
};
113 if (acpi_disabled("cmbat") ||
114 ACPI_ID_PROBE(device_get_parent(dev
), dev
, cmbat_ids
) == NULL
)
117 device_set_desc(dev
, "ACPI Control Method Battery");
122 acpi_cmbat_attach(device_t dev
)
125 ACPI_HANDLE handle
, h
;
126 struct acpi_cmbat_softc
*sc
;
128 sc
= device_get_softc(dev
);
129 handle
= acpi_get_handle(dev
);
132 ACPI_SERIAL_INIT(cmbat
);
134 timespecclear(&sc
->bst_lastupdated
);
136 sc
->bix_present
= ACPI_SUCCESS(AcpiGetHandle(handle
, "_BIX", &h
));
138 device_printf(dev
, "supports extended information\n");
140 error
= acpi_battery_register(dev
);
142 device_printf(dev
, "registering battery failed\n");
147 * Install a system notify handler in addition to the device notify.
148 * Toshiba notebook uses this alternate notify for its battery.
150 AcpiInstallNotifyHandler(handle
, ACPI_ALL_NOTIFY
,
151 acpi_cmbat_notify_handler
, dev
);
153 AcpiOsExecute(OSL_NOTIFY_HANDLER
, acpi_cmbat_init_battery
, dev
);
159 acpi_cmbat_detach(device_t dev
)
163 handle
= acpi_get_handle(dev
);
164 AcpiRemoveNotifyHandler(handle
, ACPI_ALL_NOTIFY
, acpi_cmbat_notify_handler
);
165 acpi_battery_remove(dev
);
170 acpi_cmbat_resume(device_t dev
)
173 AcpiOsExecute(OSL_NOTIFY_HANDLER
, acpi_cmbat_init_battery
, dev
);
178 acpi_cmbat_notify_handler(ACPI_HANDLE h
, UINT32 notify
, void *context
)
180 struct acpi_cmbat_softc
*sc
;
183 dev
= (device_t
)context
;
184 sc
= device_get_softc(dev
);
187 case ACPI_NOTIFY_DEVICE_CHECK
:
188 case ACPI_BATTERY_BST_CHANGE
:
190 * Clear the last updated time. The next call to retrieve the
191 * battery status will get the new value for us.
193 timespecclear(&sc
->bst_lastupdated
);
195 case ACPI_NOTIFY_BUS_CHECK
:
196 case ACPI_BATTERY_BIF_CHANGE
:
198 * Queue a callback to get the current battery info from thread
199 * context. It's not safe to block in a notify handler.
201 AcpiOsExecute(OSL_NOTIFY_HANDLER
, acpi_cmbat_get_bif_task
, dev
);
204 device_printf(sc
->dev
, "unknown notify: %#x\n", notify
);
208 acpi_UserNotify("CMBAT", h
, notify
);
212 acpi_cmbat_info_expired(struct timespec
*lastupdated
)
214 struct timespec curtime
;
216 ACPI_SERIAL_ASSERT(cmbat
);
218 if (lastupdated
== NULL
)
220 if (!timespecisset(lastupdated
))
223 getnanotime(&curtime
);
224 timespecsub(&curtime
, lastupdated
);
225 return (curtime
.tv_sec
< 0 ||
226 curtime
.tv_sec
> acpi_battery_get_info_expire());
230 acpi_cmbat_info_updated(struct timespec
*lastupdated
)
233 ACPI_SERIAL_ASSERT(cmbat
);
235 if (lastupdated
!= NULL
)
236 getnanotime(lastupdated
);
240 acpi_cmbat_get_bst(void *arg
)
242 struct acpi_cmbat_softc
*sc
;
246 ACPI_BUFFER bst_buffer
;
249 ACPI_SERIAL_ASSERT(cmbat
);
252 sc
= device_get_softc(dev
);
253 h
= acpi_get_handle(dev
);
254 bst_buffer
.Pointer
= NULL
;
255 bst_buffer
.Length
= ACPI_ALLOCATE_BUFFER
;
257 if (!acpi_cmbat_info_expired(&sc
->bst_lastupdated
))
260 as
= AcpiEvaluateObject(h
, "_BST", NULL
, &bst_buffer
);
261 if (ACPI_FAILURE(as
)) {
262 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
263 "error fetching current battery status -- %s\n",
264 AcpiFormatException(as
));
268 res
= (ACPI_OBJECT
*)bst_buffer
.Pointer
;
269 if (!ACPI_PKG_VALID(res
, 4)) {
270 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
271 "battery status corrupted\n");
275 if (acpi_PkgInt32(res
, 0, &sc
->bst
.state
) != 0)
277 if (acpi_PkgInt32(res
, 1, &sc
->bst
.rate
) != 0)
279 if (acpi_PkgInt32(res
, 2, &sc
->bst
.cap
) != 0)
281 if (acpi_PkgInt32(res
, 3, &sc
->bst
.volt
) != 0)
283 acpi_cmbat_info_updated(&sc
->bst_lastupdated
);
285 /* Clear out undefined/extended bits that might be set by hardware. */
286 sc
->bst
.state
&= ACPI_BATT_STAT_BST_MASK
;
287 if ((sc
->bst
.state
& ACPI_BATT_STAT_INVALID
) == ACPI_BATT_STAT_INVALID
)
288 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
289 "battery reports simultaneous charging and discharging\n");
291 /* XXX If all batteries are critical, perhaps we should suspend. */
292 if (sc
->bst
.state
& ACPI_BATT_STAT_CRITICAL
) {
293 if ((sc
->flags
& ACPI_BATT_STAT_CRITICAL
) == 0) {
294 sc
->flags
|= ACPI_BATT_STAT_CRITICAL
;
295 device_printf(dev
, "critically low charge!\n");
298 sc
->flags
&= ~ACPI_BATT_STAT_CRITICAL
;
301 if (bst_buffer
.Pointer
!= NULL
)
302 AcpiOsFree(bst_buffer
.Pointer
);
305 /* XXX There should be a cleaner way to do this locking. */
307 acpi_cmbat_get_bif_task(void *arg
)
310 ACPI_SERIAL_BEGIN(cmbat
);
311 acpi_cmbat_get_bif(arg
);
312 ACPI_SERIAL_END(cmbat
);
316 acpi_cmbat_get_bif(void *arg
)
318 struct acpi_cmbat_softc
*sc
;
322 ACPI_BUFFER info_buffer
;
326 ACPI_SERIAL_ASSERT(cmbat
);
329 sc
= device_get_softc(dev
);
330 h
= acpi_get_handle(dev
);
331 info_buffer
.Pointer
= NULL
;
332 info_buffer
.Length
= ACPI_ALLOCATE_BUFFER
;
334 as
= AcpiEvaluateObject(h
, sc
->bix_present
? "_BIX" : "_BIF", NULL
,
336 if (ACPI_FAILURE(as
)) {
337 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
338 "error fetching current %sbattery info -- %s\n",
339 sc
->bix_present
? "extended " : "",
340 AcpiFormatException(as
));
344 res
= (ACPI_OBJECT
*)info_buffer
.Pointer
;
345 if (!ACPI_PKG_VALID(res
, sc
->bix_present
? 20 : 13)) {
346 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
347 "%sbattery info corrupted\n",
348 sc
->bix_present
? "extended " : "");
352 i
= sc
->bix_present
? 1 : 0; /* _BIX: Skip Revision field. */
353 if (acpi_PkgInt32(res
, i
++, &sc
->bif
.units
) != 0)
355 if (acpi_PkgInt32(res
, i
++, &sc
->bif
.dcap
) != 0)
357 if (acpi_PkgInt32(res
, i
++, &sc
->bif
.lfcap
) != 0)
359 if (acpi_PkgInt32(res
, i
++, &sc
->bif
.btech
) != 0)
361 if (acpi_PkgInt32(res
, i
++, &sc
->bif
.dvol
) != 0)
363 if (acpi_PkgInt32(res
, i
++, &sc
->bif
.wcap
) != 0)
365 if (acpi_PkgInt32(res
, i
++, &sc
->bif
.lcap
) != 0)
368 i
+= 6; /* _BIX: Continue with Battery Capacity Granularity 1. */
369 if (acpi_PkgInt32(res
, i
++, &sc
->bif
.gra1
) != 0)
371 if (acpi_PkgInt32(res
, i
++, &sc
->bif
.gra2
) != 0)
373 if (acpi_PkgStr(res
, i
++, sc
->bif
.model
, ACPI_CMBAT_MAXSTRLEN
) != 0)
375 if (acpi_PkgStr(res
, i
++, sc
->bif
.serial
, ACPI_CMBAT_MAXSTRLEN
) != 0)
377 if (acpi_PkgStr(res
, i
++, sc
->bif
.type
, ACPI_CMBAT_MAXSTRLEN
) != 0)
379 if (acpi_PkgStr(res
, i
++, sc
->bif
.oeminfo
, ACPI_CMBAT_MAXSTRLEN
) != 0)
381 /* _BIX: Ignore Battery Swapping Capability field. */
384 if (info_buffer
.Pointer
!= NULL
)
385 AcpiOsFree(info_buffer
.Pointer
);
389 acpi_cmbat_bif(device_t dev
, struct acpi_bif
*bifp
)
391 struct acpi_cmbat_softc
*sc
;
393 sc
= device_get_softc(dev
);
396 * Just copy the data. The only value that should change is the
397 * last-full capacity, so we only update when we get a notify that says
398 * the info has changed. Many systems apparently take a long time to
399 * process a _BIF call so we avoid it if possible.
401 ACPI_SERIAL_BEGIN(cmbat
);
402 bifp
->units
= sc
->bif
.units
;
403 bifp
->dcap
= sc
->bif
.dcap
;
404 bifp
->lfcap
= sc
->bif
.lfcap
;
405 bifp
->btech
= sc
->bif
.btech
;
406 bifp
->dvol
= sc
->bif
.dvol
;
407 bifp
->wcap
= sc
->bif
.wcap
;
408 bifp
->lcap
= sc
->bif
.lcap
;
409 bifp
->gra1
= sc
->bif
.gra1
;
410 bifp
->gra2
= sc
->bif
.gra2
;
411 strncpy(bifp
->model
, sc
->bif
.model
, sizeof(sc
->bif
.model
));
412 strncpy(bifp
->serial
, sc
->bif
.serial
, sizeof(sc
->bif
.serial
));
413 strncpy(bifp
->type
, sc
->bif
.type
, sizeof(sc
->bif
.type
));
414 strncpy(bifp
->oeminfo
, sc
->bif
.oeminfo
, sizeof(sc
->bif
.oeminfo
));
415 ACPI_SERIAL_END(cmbat
);
421 acpi_cmbat_bst(device_t dev
, struct acpi_bst
*bstp
)
423 struct acpi_cmbat_softc
*sc
;
425 sc
= device_get_softc(dev
);
427 ACPI_SERIAL_BEGIN(cmbat
);
428 if (acpi_BatteryIsPresent(dev
)) {
429 acpi_cmbat_get_bst(dev
);
430 bstp
->state
= sc
->bst
.state
;
431 bstp
->rate
= sc
->bst
.rate
;
432 bstp
->cap
= sc
->bst
.cap
;
433 bstp
->volt
= sc
->bst
.volt
;
435 bstp
->state
= ACPI_BATT_STAT_NOT_PRESENT
;
436 ACPI_SERIAL_END(cmbat
);
442 acpi_cmbat_init_battery(void *arg
)
444 struct acpi_cmbat_softc
*sc
;
449 sc
= device_get_softc(dev
);
450 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
451 "battery initialization start\n");
454 * Try repeatedly to get valid data from the battery. Since the
455 * embedded controller isn't always ready just after boot, we may have
458 for (retry
= 0; retry
< ACPI_CMBAT_RETRY_MAX
; retry
++, AcpiOsSleep(10000)) {
459 /* batteries on DOCK can be ejected w/ DOCK during retrying */
460 if (!device_is_attached(dev
))
463 if (!acpi_BatteryIsPresent(dev
))
467 * Only query the battery if this is the first try or the specific
468 * type of info is still invalid.
470 ACPI_SERIAL_BEGIN(cmbat
);
471 if (retry
== 0 || !acpi_battery_bst_valid(&sc
->bst
)) {
472 timespecclear(&sc
->bst_lastupdated
);
473 acpi_cmbat_get_bst(dev
);
475 if (retry
== 0 || !acpi_battery_bif_valid(&sc
->bif
))
476 acpi_cmbat_get_bif(dev
);
478 valid
= acpi_battery_bst_valid(&sc
->bst
) &&
479 acpi_battery_bif_valid(&sc
->bif
);
480 ACPI_SERIAL_END(cmbat
);
486 if (retry
== ACPI_CMBAT_RETRY_MAX
) {
487 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
488 "battery initialization failed, giving up\n");
490 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
491 "battery initialization done, tried %d times\n", retry
+ 1);