Bring in the FreeBSD-5 ACPICA code as a module. Note: not hooked up yet,
[dragonfly.git] / sys / dev / acpica5 / acpi_cmbat.c
1 /*-
2  * Copyright (c) 2000 Munehiro Matsuda
3  * Copyright (c) 2000 Takanori Watanabe
4  * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/dev/acpica/acpi_cmbat.c,v 1.27 2003/12/23 18:27:35 njl Exp $
29  * $DragonFly: src/sys/dev/acpica5/acpi_cmbat.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
30  */
31
32 #include "opt_acpi.h"
33 #include <sys/param.h>
34 #include <sys/kernel.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 "acpi.h"
43 #include <dev/acpica5/acpivar.h>
44 #include <dev/acpica5/acpiio.h>
45
46 MALLOC_DEFINE(M_ACPICMBAT, "acpicmbat", "ACPI control method battery data");
47
48 /* Number of times to retry initialization before giving up. */
49 #define ACPI_CMBAT_RETRY_MAX    6
50
51 /* Check the battery once a minute. */
52 #define CMBAT_POLLRATE  (60 * hz)
53
54 /* Hooks for the ACPI CA debugging infrastructure */
55 #define _COMPONENT      ACPI_BATTERY
56 ACPI_MODULE_NAME("BATTERY")
57
58 #define ACPI_BATTERY_BST_CHANGE 0x80
59 #define ACPI_BATTERY_BIF_CHANGE 0x81
60
61 struct acpi_cmbat_softc {
62     device_t        dev;
63
64     struct acpi_bif bif;
65     struct acpi_bst bst;
66     struct timespec bif_lastupdated;
67     struct timespec bst_lastupdated;
68     int             bif_updating;
69     int             bst_updating;
70
71     int             present;
72     int             cap;
73     int             min;
74     int             full_charge_time;
75     int             initializing;
76 };
77
78 static struct timespec  acpi_cmbat_info_lastupdated;
79
80 /* XXX: devclass_get_maxunit() don't give us the current allocated units. */
81 static int              acpi_cmbat_units = 0;
82
83 static int              acpi_cmbat_info_expired(struct timespec *);
84 static void             acpi_cmbat_info_updated(struct timespec *);
85 static void             acpi_cmbat_get_bst(void *);
86 static void             acpi_cmbat_get_bif(void *);
87 static void             acpi_cmbat_notify_handler(ACPI_HANDLE, UINT32, void *);
88 static int              acpi_cmbat_probe(device_t);
89 static int              acpi_cmbat_attach(device_t);
90 static int              acpi_cmbat_resume(device_t);
91 static int              acpi_cmbat_ioctl(u_long, caddr_t, void *);
92 static int              acpi_cmbat_is_bst_valid(struct acpi_bst*);
93 static int              acpi_cmbat_is_bif_valid(struct acpi_bif*);
94 static int              acpi_cmbat_get_total_battinfo(struct acpi_battinfo *);
95 static void             acpi_cmbat_init_battery(void *);
96
97 static device_method_t acpi_cmbat_methods[] = {
98     /* Device interface */
99     DEVMETHOD(device_probe,     acpi_cmbat_probe),
100     DEVMETHOD(device_attach,    acpi_cmbat_attach),
101     DEVMETHOD(device_resume,    acpi_cmbat_resume),
102
103     {0, 0}
104 };
105
106 static driver_t acpi_cmbat_driver = {
107     "acpi_cmbat",
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
115 static int
116 acpi_cmbat_info_expired(struct timespec *lastupdated)
117 {
118     struct timespec     curtime;
119
120     if (lastupdated == NULL)
121         return (1);
122     if (!timespecisset(lastupdated))
123         return (1);
124
125     getnanotime(&curtime);
126     timespecsub(&curtime, lastupdated);
127     return (curtime.tv_sec < 0 ||
128             curtime.tv_sec > acpi_battery_get_info_expire());
129 }
130
131
132 static void
133 acpi_cmbat_info_updated(struct timespec *lastupdated)
134 {
135     if (lastupdated != NULL)
136         getnanotime(lastupdated);
137 }
138
139 static void
140 acpi_cmbat_get_bst(void *context)
141 {
142     device_t    dev;
143     struct acpi_cmbat_softc *sc;
144     ACPI_STATUS as;
145     ACPI_OBJECT *res;
146     ACPI_HANDLE h;
147     ACPI_BUFFER bst_buffer;
148
149     dev = context;
150     sc = device_get_softc(dev);
151     h = acpi_get_handle(dev);
152
153     if (!acpi_cmbat_info_expired(&sc->bst_lastupdated))
154         return;
155     if (sc->bst_updating)
156         return;
157     sc->bst_updating = 1;
158
159     bst_buffer.Pointer = NULL;
160     bst_buffer.Length = ACPI_ALLOCATE_BUFFER;
161     as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer);
162     if (ACPI_FAILURE(as)) {
163         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
164                     "error fetching current battery status -- %s\n",
165                     AcpiFormatException(as));
166         goto end;
167     }
168
169     res = (ACPI_OBJECT *)bst_buffer.Pointer;
170     if (!ACPI_PKG_VALID(res, 4)) {
171         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
172                     "battery status corrupted\n");
173         goto end;
174     }
175
176     if (acpi_PkgInt32(res, 0, &sc->bst.state) != 0)
177         goto end;
178     if (acpi_PkgInt32(res, 1, &sc->bst.rate) != 0)
179         goto end;
180     if (acpi_PkgInt32(res, 2, &sc->bst.cap) != 0)
181         goto end;
182     if (acpi_PkgInt32(res, 3, &sc->bst.volt) != 0)
183         goto end;
184     acpi_cmbat_info_updated(&sc->bst_lastupdated);
185
186 end:
187     if (bst_buffer.Pointer != NULL)
188         AcpiOsFree(bst_buffer.Pointer);
189     sc->bst_updating = 0;
190 }
191
192 static void
193 acpi_cmbat_get_bif(void *context)
194 {
195     device_t    dev;
196     struct acpi_cmbat_softc *sc;
197     ACPI_STATUS as;
198     ACPI_OBJECT *res;
199     ACPI_HANDLE h;
200     ACPI_BUFFER bif_buffer;
201
202     dev = context;
203     sc = device_get_softc(dev);
204     h = acpi_get_handle(dev);
205
206     if (!acpi_cmbat_info_expired(&sc->bif_lastupdated))
207         return;
208     if (sc->bif_updating)
209         return;
210     sc->bif_updating = 1;
211
212     bif_buffer.Pointer = NULL;
213     bif_buffer.Length = ACPI_ALLOCATE_BUFFER;
214     as = AcpiEvaluateObject(h, "_BIF", NULL, &bif_buffer);
215     if (ACPI_FAILURE(as)) {
216         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
217                     "error fetching current battery info -- %s\n",
218                     AcpiFormatException(as));
219         goto end;
220     }
221
222     res = (ACPI_OBJECT *)bif_buffer.Pointer;
223     if (!ACPI_PKG_VALID(res, 13)) {
224         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
225                     "battery info corrupted\n");
226         goto end;
227     }
228
229     if (acpi_PkgInt32(res,  0, &sc->bif.units) != 0)
230         goto end;
231     if (acpi_PkgInt32(res,  1, &sc->bif.dcap) != 0)
232         goto end;
233     if (acpi_PkgInt32(res,  2, &sc->bif.lfcap) != 0)
234         goto end;
235     if (acpi_PkgInt32(res,  3, &sc->bif.btech) != 0)
236         goto end;
237     if (acpi_PkgInt32(res,  4, &sc->bif.dvol) != 0)
238         goto end;
239     if (acpi_PkgInt32(res,  5, &sc->bif.wcap) != 0)
240         goto end;
241     if (acpi_PkgInt32(res,  6, &sc->bif.lcap) != 0)
242         goto end;
243     if (acpi_PkgInt32(res,  7, &sc->bif.gra1) != 0)
244         goto end;
245     if (acpi_PkgInt32(res,  8, &sc->bif.gra2) != 0)
246         goto end;
247     if (acpi_PkgStr(res,  9, sc->bif.model, ACPI_CMBAT_MAXSTRLEN) != 0)
248         goto end;
249     if (acpi_PkgStr(res, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN) != 0)
250         goto end;
251     if (acpi_PkgStr(res, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN) != 0)
252         goto end;
253     if (acpi_PkgStr(res, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0)
254         goto end;
255     acpi_cmbat_info_updated(&sc->bif_lastupdated);
256
257 end:
258     if (bif_buffer.Pointer != NULL)
259         AcpiOsFree(bif_buffer.Pointer);
260     sc->bif_updating = 0;
261 }
262
263 static void
264 acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
265 {
266     device_t dev;
267     struct acpi_cmbat_softc     *sc;
268
269     dev = (device_t)context;
270     if ((sc = device_get_softc(dev)) == NULL)
271         return;
272
273     acpi_UserNotify("CMBAT", h, notify);
274
275     switch (notify) {
276     case ACPI_NOTIFY_DEVICE_CHECK:
277     case ACPI_BATTERY_BST_CHANGE:
278         timespecclear(&sc->bst_lastupdated);
279         break;
280     case ACPI_NOTIFY_BUS_CHECK:
281     case ACPI_BATTERY_BIF_CHANGE:
282         timespecclear(&sc->bif_lastupdated);
283         AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_get_bif, dev);
284         break;
285     default:
286         break;
287     }
288 }
289
290 static int
291 acpi_cmbat_probe(device_t dev)
292 {
293     if (acpi_get_type(dev) == ACPI_TYPE_DEVICE &&
294         !acpi_disabled("cmbat") && acpi_MatchHid(dev, "PNP0C0A")) {
295
296         device_set_desc(dev, "Control Method Battery");
297         return (0);
298     }
299     return (ENXIO);
300 }
301
302 static int
303 acpi_cmbat_attach(device_t dev)
304 {
305     int         error;
306     ACPI_HANDLE handle;
307     struct acpi_cmbat_softc *sc;
308
309     if ((sc = device_get_softc(dev)) == NULL)
310         return (ENXIO);
311
312     handle = acpi_get_handle(dev);
313
314     /*
315      * Install a system notify handler in addition to the device notify.
316      * Toshiba notebook uses this alternate notify for its battery.
317      */
318     AcpiInstallNotifyHandler(handle, ACPI_SYSTEM_NOTIFY,
319                              acpi_cmbat_notify_handler, dev);
320     AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY,
321                              acpi_cmbat_notify_handler, dev);
322
323     sc->bif_updating = sc->bst_updating = 0;
324     sc->dev = dev;
325
326     timespecclear(&sc->bif_lastupdated);
327     timespecclear(&sc->bst_lastupdated);
328
329     if (acpi_cmbat_units == 0) {
330         error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BIF,
331                                     acpi_cmbat_ioctl, NULL);
332         if (error != 0)
333             return (error);
334         error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BST,
335                                     acpi_cmbat_ioctl, NULL);
336         if (error != 0)
337                 return (error);
338     }
339
340     error = acpi_battery_register(ACPI_BATT_TYPE_CMBAT, acpi_cmbat_units);
341     if (error != 0)
342         return (error);
343
344     acpi_cmbat_units++;
345     timespecclear(&acpi_cmbat_info_lastupdated);
346     sc->initializing = 0;
347     AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
348
349     return (0);
350 }
351
352 static int
353 acpi_cmbat_resume(device_t dev)
354 {
355     AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
356     return (0);
357 }
358
359 static int
360 acpi_cmbat_ioctl(u_long cmd, caddr_t addr, void *arg)
361 {
362     device_t    dev;
363     union acpi_battery_ioctl_arg *ioctl_arg;
364     struct acpi_cmbat_softc *sc;
365     struct acpi_bif     *bifp;
366     struct acpi_bst     *bstp;
367
368     ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
369     dev = devclass_get_device(acpi_cmbat_devclass, ioctl_arg->unit);
370     if (dev == NULL)
371         return (ENXIO);
372     sc = device_get_softc(dev);
373     if (sc == NULL)
374         return (ENXIO);
375
376     /*
377      * No security check required: information retrieval only.  If
378      * new functions are added here, a check might be required.
379      */
380     switch (cmd) {
381     case ACPIIO_CMBAT_GET_BIF:
382         acpi_cmbat_get_bif(dev);
383         bifp = &ioctl_arg->bif;
384         bifp->units = sc->bif.units;
385         bifp->dcap = sc->bif.dcap;
386         bifp->lfcap = sc->bif.lfcap;
387         bifp->btech = sc->bif.btech;
388         bifp->dvol = sc->bif.dvol;
389         bifp->wcap = sc->bif.wcap;
390         bifp->lcap = sc->bif.lcap;
391         bifp->gra1 = sc->bif.gra1;
392         bifp->gra2 = sc->bif.gra2;
393         strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model));
394         strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial));
395         strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type));
396         strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo));
397         break;
398     case ACPIIO_CMBAT_GET_BST:
399         bstp = &ioctl_arg->bst;
400         if (acpi_BatteryIsPresent(dev)) {
401             acpi_cmbat_get_bst(dev);
402             bstp->state = sc->bst.state;
403             bstp->rate = sc->bst.rate;
404             bstp->cap = sc->bst.cap;
405             bstp->volt = sc->bst.volt;
406         } else {
407             bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
408         }
409         break;
410     default:
411         break;
412     }
413
414     return (0);
415 }
416
417 static int
418 acpi_cmbat_is_bst_valid(struct acpi_bst *bst)
419 {
420     if (bst->state >= ACPI_BATT_STAT_MAX || bst->cap == 0xffffffff ||
421         bst->volt == 0xffffffff)
422
423         return (0);
424     else
425         return (1);
426 }
427
428 static int
429 acpi_cmbat_is_bif_valid(struct acpi_bif *bif)
430 {
431     if (bif->lfcap == 0)
432         return (0);
433     else
434         return (1);
435 }
436
437 static int
438 acpi_cmbat_get_total_battinfo(struct acpi_battinfo *battinfo)
439 {
440     int         i;
441     int         error;
442     int         batt_stat;
443     int         valid_rate, valid_units;
444     int         cap, min;
445     int         total_cap, total_min, total_full;
446     device_t    dev;
447     struct acpi_cmbat_softc *sc;
448     static int  bat_units = 0;
449     static struct acpi_cmbat_softc **bat = NULL;
450
451     cap = min = -1;
452     batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
453     error = 0;
454
455     /* Allocate array of softc pointers */
456     if (bat_units != acpi_cmbat_units) {
457         if (bat != NULL) {
458             free(bat, M_ACPICMBAT);
459             bat = NULL;
460         }
461         bat_units = 0;
462     }
463     if (bat == NULL) {
464         bat_units = acpi_cmbat_units;
465         bat = malloc(sizeof(struct acpi_cmbat_softc *) * bat_units,
466                      M_ACPICMBAT, M_NOWAIT);
467         if (bat == NULL) {
468             error = ENOMEM;
469             goto out;
470         }
471
472         /* Collect softc pointers */
473         for (i = 0; i < acpi_cmbat_units; i++) {
474             if ((dev = devclass_get_device(acpi_cmbat_devclass, i)) == NULL) {
475                 error = ENXIO;
476                 goto out;
477             }
478             if ((sc = device_get_softc(dev)) == NULL) {
479                 error = ENXIO;
480                 goto out;
481             }
482             bat[i] = sc;
483         }
484     }
485
486     /* Get battery status, valid rate and valid units */
487     batt_stat = valid_rate = valid_units = 0;
488     for (i = 0; i < acpi_cmbat_units; i++) {
489         bat[i]->present = acpi_BatteryIsPresent(bat[i]->dev);
490         if (!bat[i]->present)
491             continue;
492
493         acpi_cmbat_get_bst(bat[i]->dev);
494
495         /* If battery not installed, we get strange values */
496         if (!acpi_cmbat_is_bst_valid(&(bat[i]->bst)) ||
497             !acpi_cmbat_is_bif_valid(&(bat[i]->bif))) {
498
499             bat[i]->present = 0;
500             continue;
501         }
502
503         valid_units++;
504         bat[i]->cap = 100 * bat[i]->bst.cap / bat[i]->bif.lfcap;
505         batt_stat |= bat[i]->bst.state;
506
507         if (bat[i]->bst.rate > 0) {
508             /*
509              * XXX Hack to calculate total battery time.
510              * Systems with 2 or more battries, they may get used
511              * one by one, thus bst.rate is set only to the one
512              * in use. For remaining batteries bst.rate = 0, which
513              * makes it impossible to calculate remaining time.
514              * Some other systems may need sum of bst.rate in
515              * dis-charging state.
516              * There for we sum up the bst.rate that is valid
517              * (in dis-charging state), and use the sum to
518              * calcutate remaining batteries' time.
519              */
520             if (bat[i]->bst.state & ACPI_BATT_STAT_DISCHARG)
521                 valid_rate += bat[i]->bst.rate;
522         }
523     }
524
525     /* Calculate total battery capacity and time */
526     total_cap = total_min = total_full = 0;
527     for (i = 0; i < acpi_cmbat_units; i++) {
528         if (!bat[i]->present)
529             continue;
530
531         if (valid_rate > 0) {
532             /* Use the sum of bst.rate */
533             bat[i]->min = 60 * bat[i]->bst.cap / valid_rate;
534         } else if (bat[i]->full_charge_time > 0) {
535             bat[i]->min = (bat[i]->full_charge_time * bat[i]->cap) / 100;
536         } else {
537             /* Couldn't find valid rate and full battery time */
538             bat[i]->min = 0;
539         }
540         total_min += bat[i]->min;
541         total_cap += bat[i]->cap;
542         total_full += bat[i]->full_charge_time;
543     }
544
545     /* Battery life */
546     if (valid_units == 0) {
547         cap = -1;
548         batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
549     } else {
550         cap = total_cap / valid_units;
551     }
552
553     /* Battery time */
554     if (valid_units == 0) {
555         min = -1;
556     } else if (valid_rate == 0 || (batt_stat & ACPI_BATT_STAT_CHARGING)) {
557         if (total_full == 0)
558             min = -1;
559         else
560             min = (total_full * cap) / 100;
561     } else {
562         min = total_min;
563     }
564     acpi_cmbat_info_updated(&acpi_cmbat_info_lastupdated);
565
566 out:
567     battinfo->cap = cap;
568     battinfo->min = min;
569     battinfo->state = batt_stat;
570
571     return (error);
572 }
573
574 static void
575 acpi_cmbat_init_battery(void *arg)
576 {
577     int         retry;
578     device_t    dev = (device_t)arg;
579     struct acpi_cmbat_softc *sc = device_get_softc(dev);
580
581     if (sc->initializing)
582         return;
583
584     sc->initializing = 1;
585     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
586                 "battery initialization start\n");
587
588     for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10, 0)) {
589         sc->present = acpi_BatteryIsPresent(dev);
590         if (!sc->present)
591             continue;
592
593         timespecclear(&sc->bst_lastupdated);
594         timespecclear(&sc->bif_lastupdated);
595
596         acpi_cmbat_get_bst(dev);
597         if (!acpi_cmbat_is_bst_valid(&sc->bst))
598             continue;
599
600         acpi_cmbat_get_bif(dev);
601         if (!acpi_cmbat_is_bif_valid(&sc->bif))
602             continue;
603         break;
604     }
605
606     sc->initializing = 0;
607     if (retry == ACPI_CMBAT_RETRY_MAX) {
608         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
609                     "battery initialization failed, giving up\n");
610     } else {
611         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
612                     "battery initialization done, tried %d times\n", retry + 1);
613     }
614 }
615
616 /*
617  * Public interfaces.
618  */
619 int
620 acpi_cmbat_get_battinfo(int unit, struct acpi_battinfo *battinfo)
621 {
622     int         error;
623     device_t    dev;
624     struct acpi_cmbat_softc *sc;
625
626     if (unit == -1)
627         return (acpi_cmbat_get_total_battinfo(battinfo));
628
629     if (acpi_cmbat_info_expired(&acpi_cmbat_info_lastupdated)) {
630         error = acpi_cmbat_get_total_battinfo(battinfo);
631         if (error)
632             goto out;
633     }
634
635     error = 0;
636     if (unit >= acpi_cmbat_units) {
637         error = ENXIO;
638         goto out;
639     }
640
641     if ((dev = devclass_get_device(acpi_cmbat_devclass, unit)) == NULL) {
642         error = ENXIO;
643         goto out;
644     }
645     if ((sc = device_get_softc(dev)) == NULL) {
646         error = ENXIO;
647         goto out;
648     }
649
650     if (!sc->present) {
651         battinfo->cap = -1;
652         battinfo->min = -1;
653         battinfo->state = ACPI_BATT_STAT_NOT_PRESENT;
654     } else {
655         battinfo->cap = sc->cap;
656         battinfo->min = sc->min;
657         battinfo->state = sc->bst.state;
658     }
659
660 out:
661     return (error);
662 }