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