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
28 * __FBSDID("$FreeBSD: src/sys/dev/acpica/acpi_cmbat.c,v 1.46.8.1 2009/04/15 03:14:26 kensmith Exp $");
31 #include <sys/cdefs.h>
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
38 #include <sys/ioccom.h>
41 #include <sys/malloc.h>
44 #include <dev/acpica5/acpivar.h>
45 #include <dev/acpica5/acpiio.h>
47 MALLOC_DEFINE(M_ACPICMBAT
, "acpicmbat", "ACPI control method battery data");
49 /* Number of times to retry initialization before giving up. */
50 #define ACPI_CMBAT_RETRY_MAX 6
52 /* Check the battery once a minute. */
53 #define CMBAT_POLLRATE (60 * hz)
55 /* Hooks for the ACPI CA debugging infrastructure */
56 #define _COMPONENT ACPI_BATTERY
57 ACPI_MODULE_NAME("BATTERY")
59 #define ACPI_BATTERY_BST_CHANGE 0x80
60 #define ACPI_BATTERY_BIF_CHANGE 0x81
62 struct acpi_cmbat_softc
{
68 struct timespec bst_lastupdated
;
71 ACPI_SERIAL_DECL(cmbat
, "ACPI cmbat");
73 static int acpi_cmbat_probe(device_t dev
);
74 static int acpi_cmbat_attach(device_t dev
);
75 static int acpi_cmbat_detach(device_t dev
);
76 static int acpi_cmbat_resume(device_t dev
);
77 static void acpi_cmbat_notify_handler(ACPI_HANDLE h
, UINT32 notify
,
79 static int acpi_cmbat_info_expired(struct timespec
*lastupdated
);
80 static void acpi_cmbat_info_updated(struct timespec
*lastupdated
);
81 static void acpi_cmbat_get_bst(void *arg
);
82 static void acpi_cmbat_get_bif_task(void *arg
);
83 static void acpi_cmbat_get_bif(void *arg
);
84 static int acpi_cmbat_bst(device_t dev
, struct acpi_bst
*bstp
);
85 static int acpi_cmbat_bif(device_t dev
, struct acpi_bif
*bifp
);
86 static void acpi_cmbat_init_battery(void *arg
);
88 static device_method_t acpi_cmbat_methods
[] = {
89 /* Device interface */
90 DEVMETHOD(device_probe
, acpi_cmbat_probe
),
91 DEVMETHOD(device_attach
, acpi_cmbat_attach
),
92 DEVMETHOD(device_detach
, acpi_cmbat_detach
),
93 DEVMETHOD(device_resume
, acpi_cmbat_resume
),
95 /* ACPI battery interface */
96 DEVMETHOD(acpi_batt_get_info
, acpi_cmbat_bif
),
97 DEVMETHOD(acpi_batt_get_status
, acpi_cmbat_bst
),
102 static driver_t acpi_cmbat_driver
= {
105 sizeof(struct acpi_cmbat_softc
),
108 static devclass_t acpi_cmbat_devclass
;
109 DRIVER_MODULE(acpi_cmbat
, acpi
, acpi_cmbat_driver
, acpi_cmbat_devclass
, 0, 0);
110 MODULE_DEPEND(acpi_cmbat
, acpi
, 1, 1, 1);
113 acpi_cmbat_probe(device_t dev
)
115 static char *cmbat_ids
[] = { "PNP0C0A", NULL
};
117 if (acpi_disabled("cmbat") ||
118 ACPI_ID_PROBE(device_get_parent(dev
), dev
, cmbat_ids
) == NULL
)
121 device_set_desc(dev
, "ACPI Control Method Battery");
126 acpi_cmbat_attach(device_t dev
)
130 struct acpi_cmbat_softc
*sc
;
132 sc
= device_get_softc(dev
);
133 handle
= acpi_get_handle(dev
);
136 timespecclear(&sc
->bst_lastupdated
);
138 error
= acpi_battery_register(dev
);
140 device_printf(dev
, "registering battery failed\n");
145 * Install a system notify handler in addition to the device notify.
146 * Toshiba notebook uses this alternate notify for its battery.
148 AcpiInstallNotifyHandler(handle
, ACPI_ALL_NOTIFY
,
149 acpi_cmbat_notify_handler
, dev
);
151 AcpiOsExecute(OSL_NOTIFY_HANDLER
, acpi_cmbat_init_battery
, dev
);
157 acpi_cmbat_detach(device_t dev
)
161 handle
= acpi_get_handle(dev
);
162 AcpiRemoveNotifyHandler(handle
, ACPI_ALL_NOTIFY
, acpi_cmbat_notify_handler
);
163 acpi_battery_remove(dev
);
168 acpi_cmbat_resume(device_t dev
)
171 AcpiOsExecute(OSL_NOTIFY_HANDLER
, acpi_cmbat_init_battery
, dev
);
176 acpi_cmbat_notify_handler(ACPI_HANDLE h
, UINT32 notify
, void *context
)
178 struct acpi_cmbat_softc
*sc
;
181 dev
= (device_t
)context
;
182 sc
= device_get_softc(dev
);
185 case ACPI_NOTIFY_DEVICE_CHECK
:
186 case ACPI_BATTERY_BST_CHANGE
:
188 * Clear the last updated time. The next call to retrieve the
189 * battery status will get the new value for us.
191 timespecclear(&sc
->bst_lastupdated
);
193 case ACPI_NOTIFY_BUS_CHECK
:
194 case ACPI_BATTERY_BIF_CHANGE
:
196 * Queue a callback to get the current battery info from thread
197 * context. It's not safe to block in a notify handler.
199 AcpiOsExecute(OSL_NOTIFY_HANDLER
, acpi_cmbat_get_bif_task
, dev
);
203 acpi_UserNotify("CMBAT", h
, notify
);
207 acpi_cmbat_info_expired(struct timespec
*lastupdated
)
209 struct timespec curtime
;
211 ACPI_SERIAL_ASSERT(cmbat
);
213 if (lastupdated
== NULL
)
215 if (!timespecisset(lastupdated
))
218 getnanotime(&curtime
);
219 timespecsub(&curtime
, lastupdated
);
220 return (curtime
.tv_sec
< 0 ||
221 curtime
.tv_sec
> acpi_battery_get_info_expire());
225 acpi_cmbat_info_updated(struct timespec
*lastupdated
)
228 ACPI_SERIAL_ASSERT(cmbat
);
230 if (lastupdated
!= NULL
)
231 getnanotime(lastupdated
);
235 acpi_cmbat_get_bst(void *arg
)
237 struct acpi_cmbat_softc
*sc
;
241 ACPI_BUFFER bst_buffer
;
244 ACPI_SERIAL_ASSERT(cmbat
);
247 sc
= device_get_softc(dev
);
248 h
= acpi_get_handle(dev
);
249 bst_buffer
.Pointer
= NULL
;
250 bst_buffer
.Length
= ACPI_ALLOCATE_BUFFER
;
252 if (!acpi_cmbat_info_expired(&sc
->bst_lastupdated
))
255 as
= AcpiEvaluateObject(h
, "_BST", NULL
, &bst_buffer
);
256 if (ACPI_FAILURE(as
)) {
257 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
258 "error fetching current battery status -- %s\n",
259 AcpiFormatException(as
));
263 res
= (ACPI_OBJECT
*)bst_buffer
.Pointer
;
264 if (!ACPI_PKG_VALID(res
, 4)) {
265 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
266 "battery status corrupted\n");
270 if (acpi_PkgInt32(res
, 0, &sc
->bst
.state
) != 0)
272 if (acpi_PkgInt32(res
, 1, &sc
->bst
.rate
) != 0)
274 if (acpi_PkgInt32(res
, 2, &sc
->bst
.cap
) != 0)
276 if (acpi_PkgInt32(res
, 3, &sc
->bst
.volt
) != 0)
278 acpi_cmbat_info_updated(&sc
->bst_lastupdated
);
280 /* XXX If all batteries are critical, perhaps we should suspend. */
281 if (sc
->bst
.state
& ACPI_BATT_STAT_CRITICAL
) {
282 if ((sc
->flags
& ACPI_BATT_STAT_CRITICAL
) == 0) {
283 sc
->flags
|= ACPI_BATT_STAT_CRITICAL
;
284 device_printf(dev
, "critically low charge!\n");
287 sc
->flags
&= ~ACPI_BATT_STAT_CRITICAL
;
290 if (bst_buffer
.Pointer
!= NULL
)
291 AcpiOsFree(bst_buffer
.Pointer
);
294 /* XXX There should be a cleaner way to do this locking. */
296 acpi_cmbat_get_bif_task(void *arg
)
299 ACPI_SERIAL_BEGIN(cmbat
);
300 acpi_cmbat_get_bif(arg
);
301 ACPI_SERIAL_END(cmbat
);
305 acpi_cmbat_get_bif(void *arg
)
307 struct acpi_cmbat_softc
*sc
;
311 ACPI_BUFFER bif_buffer
;
314 ACPI_SERIAL_ASSERT(cmbat
);
317 sc
= device_get_softc(dev
);
318 h
= acpi_get_handle(dev
);
319 bif_buffer
.Pointer
= NULL
;
320 bif_buffer
.Length
= ACPI_ALLOCATE_BUFFER
;
322 as
= AcpiEvaluateObject(h
, "_BIF", NULL
, &bif_buffer
);
323 if (ACPI_FAILURE(as
)) {
324 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
325 "error fetching current battery info -- %s\n",
326 AcpiFormatException(as
));
330 res
= (ACPI_OBJECT
*)bif_buffer
.Pointer
;
331 if (!ACPI_PKG_VALID(res
, 13)) {
332 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
333 "battery info corrupted\n");
337 if (acpi_PkgInt32(res
, 0, &sc
->bif
.units
) != 0)
339 if (acpi_PkgInt32(res
, 1, &sc
->bif
.dcap
) != 0)
341 if (acpi_PkgInt32(res
, 2, &sc
->bif
.lfcap
) != 0)
343 if (acpi_PkgInt32(res
, 3, &sc
->bif
.btech
) != 0)
345 if (acpi_PkgInt32(res
, 4, &sc
->bif
.dvol
) != 0)
347 if (acpi_PkgInt32(res
, 5, &sc
->bif
.wcap
) != 0)
349 if (acpi_PkgInt32(res
, 6, &sc
->bif
.lcap
) != 0)
351 if (acpi_PkgInt32(res
, 7, &sc
->bif
.gra1
) != 0)
353 if (acpi_PkgInt32(res
, 8, &sc
->bif
.gra2
) != 0)
355 if (acpi_PkgStr(res
, 9, sc
->bif
.model
, ACPI_CMBAT_MAXSTRLEN
) != 0)
357 if (acpi_PkgStr(res
, 10, sc
->bif
.serial
, ACPI_CMBAT_MAXSTRLEN
) != 0)
359 if (acpi_PkgStr(res
, 11, sc
->bif
.type
, ACPI_CMBAT_MAXSTRLEN
) != 0)
361 if (acpi_PkgStr(res
, 12, sc
->bif
.oeminfo
, ACPI_CMBAT_MAXSTRLEN
) != 0)
365 if (bif_buffer
.Pointer
!= NULL
)
366 AcpiOsFree(bif_buffer
.Pointer
);
370 acpi_cmbat_bif(device_t dev
, struct acpi_bif
*bifp
)
372 struct acpi_cmbat_softc
*sc
;
374 sc
= device_get_softc(dev
);
377 * Just copy the data. The only value that should change is the
378 * last-full capacity, so we only update when we get a notify that says
379 * the info has changed. Many systems apparently take a long time to
380 * process a _BIF call so we avoid it if possible.
382 ACPI_SERIAL_BEGIN(cmbat
);
383 bifp
->units
= sc
->bif
.units
;
384 bifp
->dcap
= sc
->bif
.dcap
;
385 bifp
->lfcap
= sc
->bif
.lfcap
;
386 bifp
->btech
= sc
->bif
.btech
;
387 bifp
->dvol
= sc
->bif
.dvol
;
388 bifp
->wcap
= sc
->bif
.wcap
;
389 bifp
->lcap
= sc
->bif
.lcap
;
390 bifp
->gra1
= sc
->bif
.gra1
;
391 bifp
->gra2
= sc
->bif
.gra2
;
392 strncpy(bifp
->model
, sc
->bif
.model
, sizeof(sc
->bif
.model
));
393 strncpy(bifp
->serial
, sc
->bif
.serial
, sizeof(sc
->bif
.serial
));
394 strncpy(bifp
->type
, sc
->bif
.type
, sizeof(sc
->bif
.type
));
395 strncpy(bifp
->oeminfo
, sc
->bif
.oeminfo
, sizeof(sc
->bif
.oeminfo
));
396 ACPI_SERIAL_END(cmbat
);
402 acpi_cmbat_bst(device_t dev
, struct acpi_bst
*bstp
)
404 struct acpi_cmbat_softc
*sc
;
406 sc
= device_get_softc(dev
);
408 ACPI_SERIAL_BEGIN(cmbat
);
409 if (acpi_BatteryIsPresent(dev
)) {
410 acpi_cmbat_get_bst(dev
);
411 bstp
->state
= sc
->bst
.state
;
412 bstp
->rate
= sc
->bst
.rate
;
413 bstp
->cap
= sc
->bst
.cap
;
414 bstp
->volt
= sc
->bst
.volt
;
416 bstp
->state
= ACPI_BATT_STAT_NOT_PRESENT
;
417 ACPI_SERIAL_END(cmbat
);
423 acpi_cmbat_init_battery(void *arg
)
425 struct acpi_cmbat_softc
*sc
;
430 sc
= device_get_softc(dev
);
431 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
432 "battery initialization start\n");
435 * Try repeatedly to get valid data from the battery. Since the
436 * embedded controller isn't always ready just after boot, we may have
439 for (retry
= 0; retry
< ACPI_CMBAT_RETRY_MAX
; retry
++, AcpiOsSleep(10000)) {
440 /* batteries on DOCK can be ejected w/ DOCK during retrying */
441 if (!device_is_attached(dev
))
444 if (!acpi_BatteryIsPresent(dev
))
448 * Only query the battery if this is the first try or the specific
449 * type of info is still invalid.
451 ACPI_SERIAL_BEGIN(cmbat
);
452 if (retry
== 0 || !acpi_battery_bst_valid(&sc
->bst
)) {
453 timespecclear(&sc
->bst_lastupdated
);
454 acpi_cmbat_get_bst(dev
);
456 if (retry
== 0 || !acpi_battery_bif_valid(&sc
->bif
))
457 acpi_cmbat_get_bif(dev
);
459 valid
= acpi_battery_bst_valid(&sc
->bst
) &&
460 acpi_battery_bif_valid(&sc
->bif
);
461 ACPI_SERIAL_END(cmbat
);
467 if (retry
== ACPI_CMBAT_RETRY_MAX
) {
468 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
469 "battery initialization failed, giving up\n");
471 ACPI_VPRINT(dev
, acpi_device_get_parent_softc(dev
),
472 "battery initialization done, tried %d times\n", retry
+ 1);