The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/acpica/acpi_cmbat.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    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: releng/5.3/sys/dev/acpica/acpi_cmbat.c 133919 2004-08-17 18:36:07Z njl $
   29  */
   30 
   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 "acpi.h"
   43 #include <dev/acpica/acpivar.h>
   44 #include <dev/acpica/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 
   69     int             present;
   70     int             cap;
   71     int             min;
   72     int             full_charge_time;
   73     int             initializing;
   74     int             phys_unit;
   75 };
   76 
   77 static struct timespec  acpi_cmbat_info_lastupdated;
   78 ACPI_SERIAL_DECL(cmbat, "ACPI cmbat");
   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_detach(device_t);
   91 static int              acpi_cmbat_resume(device_t);
   92 static int              acpi_cmbat_ioctl(u_long, caddr_t, void *);
   93 static int              acpi_cmbat_is_bst_valid(struct acpi_bst*);
   94 static int              acpi_cmbat_is_bif_valid(struct acpi_bif*);
   95 static int              acpi_cmbat_get_total_battinfo(struct acpi_battinfo *);
   96 static void             acpi_cmbat_init_battery(void *);
   97 
   98 static device_method_t acpi_cmbat_methods[] = {
   99     /* Device interface */
  100     DEVMETHOD(device_probe,     acpi_cmbat_probe),
  101     DEVMETHOD(device_attach,    acpi_cmbat_attach),
  102     DEVMETHOD(device_detach,    acpi_cmbat_detach),
  103     DEVMETHOD(device_resume,    acpi_cmbat_resume),
  104 
  105     {0, 0}
  106 };
  107 
  108 static driver_t acpi_cmbat_driver = {
  109     "acpi_cmbat",
  110     acpi_cmbat_methods,
  111     sizeof(struct acpi_cmbat_softc),
  112 };
  113 
  114 static devclass_t acpi_cmbat_devclass;
  115 DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0);
  116 MODULE_DEPEND(acpi_cmbat, acpi, 1, 1, 1);
  117 
  118 static int
  119 acpi_cmbat_info_expired(struct timespec *lastupdated)
  120 {
  121     struct timespec     curtime;
  122 
  123     ACPI_SERIAL_ASSERT(cmbat);
  124 
  125     if (lastupdated == NULL)
  126         return (TRUE);
  127     if (!timespecisset(lastupdated))
  128         return (TRUE);
  129 
  130     getnanotime(&curtime);
  131     timespecsub(&curtime, lastupdated);
  132     return (curtime.tv_sec < 0 ||
  133             curtime.tv_sec > acpi_battery_get_info_expire());
  134 }
  135 
  136 static void
  137 acpi_cmbat_info_updated(struct timespec *lastupdated)
  138 {
  139 
  140     ACPI_SERIAL_ASSERT(cmbat);
  141 
  142     if (lastupdated != NULL)
  143         getnanotime(lastupdated);
  144 }
  145 
  146 static void
  147 acpi_cmbat_get_bst(void *context)
  148 {
  149     device_t    dev;
  150     struct acpi_cmbat_softc *sc;
  151     ACPI_STATUS as;
  152     ACPI_OBJECT *res;
  153     ACPI_HANDLE h;
  154     ACPI_BUFFER bst_buffer;
  155 
  156     ACPI_SERIAL_ASSERT(cmbat);
  157 
  158     dev = context;
  159     sc = device_get_softc(dev);
  160     h = acpi_get_handle(dev);
  161     bst_buffer.Pointer = NULL;
  162     bst_buffer.Length = ACPI_ALLOCATE_BUFFER;
  163 
  164     if (!acpi_cmbat_info_expired(&sc->bst_lastupdated))
  165         goto end;
  166 
  167     as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer);
  168     if (ACPI_FAILURE(as)) {
  169         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  170                     "error fetching current battery status -- %s\n",
  171                     AcpiFormatException(as));
  172         goto end;
  173     }
  174 
  175     res = (ACPI_OBJECT *)bst_buffer.Pointer;
  176     if (!ACPI_PKG_VALID(res, 4)) {
  177         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  178                     "battery status corrupted\n");
  179         goto end;
  180     }
  181 
  182     if (acpi_PkgInt32(res, 0, &sc->bst.state) != 0)
  183         goto end;
  184     if (acpi_PkgInt32(res, 1, &sc->bst.rate) != 0)
  185         goto end;
  186     if (acpi_PkgInt32(res, 2, &sc->bst.cap) != 0)
  187         goto end;
  188     if (acpi_PkgInt32(res, 3, &sc->bst.volt) != 0)
  189         goto end;
  190     acpi_cmbat_info_updated(&sc->bst_lastupdated);
  191 
  192 end:
  193     if (bst_buffer.Pointer != NULL)
  194         AcpiOsFree(bst_buffer.Pointer);
  195 }
  196 
  197 static void
  198 acpi_cmbat_get_bif(void *context)
  199 {
  200     device_t    dev;
  201     struct acpi_cmbat_softc *sc;
  202     ACPI_STATUS as;
  203     ACPI_OBJECT *res;
  204     ACPI_HANDLE h;
  205     ACPI_BUFFER bif_buffer;
  206 
  207     ACPI_SERIAL_ASSERT(cmbat);
  208 
  209     dev = context;
  210     sc = device_get_softc(dev);
  211     h = acpi_get_handle(dev);
  212     bif_buffer.Pointer = NULL;
  213     bif_buffer.Length = ACPI_ALLOCATE_BUFFER;
  214 
  215     if (!acpi_cmbat_info_expired(&sc->bif_lastupdated))
  216         goto end;
  217 
  218     as = AcpiEvaluateObject(h, "_BIF", NULL, &bif_buffer);
  219     if (ACPI_FAILURE(as)) {
  220         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  221                     "error fetching current battery info -- %s\n",
  222                     AcpiFormatException(as));
  223         goto end;
  224     }
  225 
  226     res = (ACPI_OBJECT *)bif_buffer.Pointer;
  227     if (!ACPI_PKG_VALID(res, 13)) {
  228         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  229                     "battery info corrupted\n");
  230         goto end;
  231     }
  232 
  233     if (acpi_PkgInt32(res, 0, &sc->bif.units) != 0)
  234         goto end;
  235     if (acpi_PkgInt32(res, 1, &sc->bif.dcap) != 0)
  236         goto end;
  237     if (acpi_PkgInt32(res, 2, &sc->bif.lfcap) != 0)
  238         goto end;
  239     if (acpi_PkgInt32(res, 3, &sc->bif.btech) != 0)
  240         goto end;
  241     if (acpi_PkgInt32(res, 4, &sc->bif.dvol) != 0)
  242         goto end;
  243     if (acpi_PkgInt32(res, 5, &sc->bif.wcap) != 0)
  244         goto end;
  245     if (acpi_PkgInt32(res, 6, &sc->bif.lcap) != 0)
  246         goto end;
  247     if (acpi_PkgInt32(res, 7, &sc->bif.gra1) != 0)
  248         goto end;
  249     if (acpi_PkgInt32(res, 8, &sc->bif.gra2) != 0)
  250         goto end;
  251     if (acpi_PkgStr(res,  9, sc->bif.model, ACPI_CMBAT_MAXSTRLEN) != 0)
  252         goto end;
  253     if (acpi_PkgStr(res, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN) != 0)
  254         goto end;
  255     if (acpi_PkgStr(res, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN) != 0)
  256         goto end;
  257     if (acpi_PkgStr(res, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0)
  258         goto end;
  259     acpi_cmbat_info_updated(&sc->bif_lastupdated);
  260 
  261 end:
  262     if (bif_buffer.Pointer != NULL)
  263         AcpiOsFree(bif_buffer.Pointer);
  264 }
  265 
  266 static void
  267 acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
  268 {
  269     device_t dev;
  270     struct acpi_cmbat_softc     *sc;
  271 
  272     dev = (device_t)context;
  273     sc = device_get_softc(dev);
  274 
  275     acpi_UserNotify("CMBAT", h, notify);
  276 
  277     /*
  278      * Clear the appropriate last updated time.  The next call to retrieve
  279      * the battery status will get the new value for us.  We don't need to
  280      * acquire a lock since we are only clearing the time stamp and since
  281      * calling _BST/_BIF can trigger a notify, we could deadlock also.
  282      */
  283     switch (notify) {
  284     case ACPI_NOTIFY_DEVICE_CHECK:
  285     case ACPI_BATTERY_BST_CHANGE:
  286         timespecclear(&sc->bst_lastupdated);
  287         break;
  288     case ACPI_NOTIFY_BUS_CHECK:
  289     case ACPI_BATTERY_BIF_CHANGE:
  290         timespecclear(&sc->bif_lastupdated);
  291         break;
  292     default:
  293         break;
  294     }
  295 }
  296 
  297 static int
  298 acpi_cmbat_probe(device_t dev)
  299 {
  300     static char *cmbat_ids[] = { "PNP0C0A", NULL };
  301 
  302     if (acpi_disabled("cmbat") ||
  303         ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids) == NULL)
  304         return (ENXIO);
  305 
  306     device_set_desc(dev, "Control Method Battery");
  307     return (0);
  308 }
  309 
  310 static int
  311 acpi_cmbat_attach(device_t dev)
  312 {
  313     int         error;
  314     ACPI_HANDLE handle;
  315     struct acpi_cmbat_softc *sc;
  316 
  317     sc = device_get_softc(dev);
  318     handle = acpi_get_handle(dev);
  319     sc->dev = dev;
  320 
  321     /*
  322      * Install a system notify handler in addition to the device notify.
  323      * Toshiba notebook uses this alternate notify for its battery.
  324      */
  325     AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY,
  326                              acpi_cmbat_notify_handler, dev);
  327 
  328     ACPI_SERIAL_BEGIN(cmbat);
  329     timespecclear(&sc->bif_lastupdated);
  330     timespecclear(&sc->bst_lastupdated);
  331 
  332     if (acpi_cmbat_units == 0) {
  333         error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BIF,
  334                                     acpi_cmbat_ioctl, NULL);
  335         if (error != 0) {
  336             device_printf(dev, "register bif ioctl failed\n");
  337             return (error);
  338         }
  339         error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BST,
  340                                     acpi_cmbat_ioctl, NULL);
  341         if (error != 0) {
  342             device_printf(dev, "register bst ioctl failed\n");
  343             return (error);
  344         }
  345     }
  346 
  347     sc->phys_unit = acpi_cmbat_units;
  348     error = acpi_battery_register(ACPI_BATT_TYPE_CMBAT, sc->phys_unit);
  349     if (error != 0) {
  350         device_printf(dev, "registering battery %d failed\n", sc->phys_unit);
  351         return (error);
  352     }
  353     acpi_cmbat_units++;
  354     timespecclear(&acpi_cmbat_info_lastupdated);
  355     ACPI_SERIAL_END(cmbat);
  356 
  357     AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
  358 
  359     return (0);
  360 }
  361 
  362 static int
  363 acpi_cmbat_detach(device_t dev)
  364 {
  365     struct acpi_cmbat_softc *sc;
  366 
  367     sc = device_get_softc(dev);
  368     ACPI_SERIAL_BEGIN(cmbat);
  369     acpi_battery_remove(ACPI_BATT_TYPE_CMBAT, sc->phys_unit);
  370     acpi_cmbat_units--;
  371     ACPI_SERIAL_END(cmbat);
  372     return (0);
  373 }
  374 
  375 static int
  376 acpi_cmbat_resume(device_t dev)
  377 {
  378     AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev);
  379     return (0);
  380 }
  381 
  382 static int
  383 acpi_cmbat_ioctl(u_long cmd, caddr_t addr, void *arg)
  384 {
  385     device_t dev;
  386     union acpi_battery_ioctl_arg *ioctl_arg;
  387     struct acpi_cmbat_softc *sc;
  388     struct acpi_bif     *bifp;
  389     struct acpi_bst     *bstp;
  390 
  391     ioctl_arg = (union acpi_battery_ioctl_arg *)addr;
  392     dev = devclass_get_device(acpi_cmbat_devclass, ioctl_arg->unit);
  393     if (dev == NULL)
  394         return (ENXIO);
  395     sc = device_get_softc(dev);
  396 
  397     /*
  398      * No security check required: information retrieval only.  If
  399      * new functions are added here, a check might be required.
  400      */
  401     ACPI_SERIAL_BEGIN(cmbat);
  402     switch (cmd) {
  403     case ACPIIO_CMBAT_GET_BIF:
  404         acpi_cmbat_get_bif(dev);
  405         bifp = &ioctl_arg->bif;
  406         bifp->units = sc->bif.units;
  407         bifp->dcap = sc->bif.dcap;
  408         bifp->lfcap = sc->bif.lfcap;
  409         bifp->btech = sc->bif.btech;
  410         bifp->dvol = sc->bif.dvol;
  411         bifp->wcap = sc->bif.wcap;
  412         bifp->lcap = sc->bif.lcap;
  413         bifp->gra1 = sc->bif.gra1;
  414         bifp->gra2 = sc->bif.gra2;
  415         strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model));
  416         strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial));
  417         strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type));
  418         strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo));
  419         break;
  420     case ACPIIO_CMBAT_GET_BST:
  421         bstp = &ioctl_arg->bst;
  422         if (acpi_BatteryIsPresent(dev)) {
  423             acpi_cmbat_get_bst(dev);
  424             bstp->state = sc->bst.state;
  425             bstp->rate = sc->bst.rate;
  426             bstp->cap = sc->bst.cap;
  427             bstp->volt = sc->bst.volt;
  428         } else {
  429             bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
  430         }
  431         break;
  432     default:
  433         break;
  434     }
  435     ACPI_SERIAL_END(cmbat);
  436 
  437     return (0);
  438 }
  439 
  440 static int
  441 acpi_cmbat_is_bst_valid(struct acpi_bst *bst)
  442 {
  443     if (bst->state >= ACPI_BATT_STAT_MAX || bst->cap == 0xffffffff ||
  444         bst->volt == 0xffffffff)
  445         return (FALSE);
  446     else
  447         return (TRUE);
  448 }
  449 
  450 static int
  451 acpi_cmbat_is_bif_valid(struct acpi_bif *bif)
  452 {
  453     if (bif->lfcap == 0)
  454         return (FALSE);
  455     else
  456         return (TRUE);
  457 }
  458 
  459 static int
  460 acpi_cmbat_get_total_battinfo(struct acpi_battinfo *battinfo)
  461 {
  462     int         i;
  463     int         error;
  464     int         batt_stat;
  465     int         valid_rate, valid_units;
  466     int         cap, min;
  467     int         total_cap, total_min, total_full;
  468     struct acpi_cmbat_softc *sc;
  469 
  470     ACPI_SERIAL_ASSERT(cmbat);
  471 
  472     cap = min = -1;
  473     batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
  474     error = 0;
  475 
  476     /* Get battery status, valid rate and valid units */
  477     batt_stat = valid_rate = valid_units = 0;
  478     for (i = 0; i < acpi_cmbat_units; i++) {
  479         sc = devclass_get_softc(acpi_cmbat_devclass, i);
  480         if (sc == NULL)
  481             continue;
  482         sc->present = acpi_BatteryIsPresent(sc->dev);
  483         if (!sc->present)
  484             continue;
  485         acpi_cmbat_get_bst(sc->dev);
  486 
  487         /* If battery not installed, we get strange values */
  488         if (!acpi_cmbat_is_bst_valid(&sc->bst) ||
  489             !acpi_cmbat_is_bif_valid(&sc->bif)) {
  490             sc->present = FALSE;
  491             continue;
  492         }
  493 
  494         valid_units++;
  495         sc->cap = 100 * sc->bst.cap / sc->bif.lfcap;
  496 
  497         /* 
  498          * Some laptops report the "design-capacity" instead of the 
  499          * "real-capacity" when the battery is fully charged.
  500          * That breaks the above arithmetic as it needs to be 100% maximum.
  501          */
  502         if (sc->cap > 100)
  503             sc->cap = 100;
  504 
  505         batt_stat |= sc->bst.state;
  506 
  507         /*
  508          * XXX Hack to calculate total battery time.
  509          *
  510          * On systems with more than one battery, they may get used
  511          * sequentially, thus bst.rate may only signify the one in use.
  512          * For the remaining batteries, bst.rate will be zero, which
  513          * makes it impossible to calculate the remaining time.  Some
  514          * other systems may need the sum of all the bst.rate values
  515          * when discharging.  Therefore, we sum the bst.rate for valid
  516          * batteries (ones in the discharging state) and use the sum
  517          * to calculate the total remaining time.
  518          */
  519         if (sc->bst.rate > 0) {
  520             if (sc->bst.state & ACPI_BATT_STAT_DISCHARG)
  521                 valid_rate += sc->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         sc = devclass_get_softc(acpi_cmbat_devclass, i);
  529         if (!sc->present)
  530             continue;
  531 
  532         /*
  533          * If any batteries are discharging, use the sum of the bst.rate
  534          * values.  Otherwise, use the full charge time to estimate
  535          * remaining time.  If neither are available, assume no charge.
  536          */
  537         if (valid_rate > 0)
  538             sc->min = 60 * sc->bst.cap / valid_rate;
  539         else if (sc->full_charge_time > 0)
  540             sc->min = (sc->full_charge_time * sc->cap) / 100;
  541         else
  542             sc->min = 0;
  543         total_min += sc->min;
  544         total_cap += sc->cap;
  545         total_full += sc->full_charge_time;
  546     }
  547 
  548     /* Battery life */
  549     if (valid_units == 0) {
  550         cap = -1;
  551         batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
  552     } else
  553         cap = total_cap / valid_units;
  554 
  555     /* Battery time */
  556     if (valid_units == 0)
  557         min = -1;
  558     else if (valid_rate == 0 || (batt_stat & ACPI_BATT_STAT_CHARGING)) {
  559         if (total_full == 0)
  560             min = -1;
  561         else
  562             min = (total_full * cap) / 100;
  563     } else
  564         min = total_min;
  565     acpi_cmbat_info_updated(&acpi_cmbat_info_lastupdated);
  566 
  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     struct acpi_cmbat_softc *sc;
  578     int         retry;
  579     device_t    dev;
  580 
  581     dev = (device_t)arg;
  582     sc = device_get_softc(dev);
  583     ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  584                 "battery initialization start\n");
  585 
  586     for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10, 0)) {
  587         sc->present = acpi_BatteryIsPresent(dev);
  588         if (!sc->present)
  589             continue;
  590 
  591         ACPI_SERIAL_BEGIN(cmbat);
  592         timespecclear(&sc->bst_lastupdated);
  593         timespecclear(&sc->bif_lastupdated);
  594         acpi_cmbat_get_bst(dev);
  595         acpi_cmbat_get_bif(dev);
  596         ACPI_SERIAL_END(cmbat);
  597 
  598         if (acpi_cmbat_is_bst_valid(&sc->bst) &&
  599             acpi_cmbat_is_bif_valid(&sc->bif))
  600             break;
  601     }
  602 
  603     if (retry == ACPI_CMBAT_RETRY_MAX) {
  604         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  605                     "battery initialization failed, giving up\n");
  606     } else {
  607         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  608                     "battery initialization done, tried %d times\n", retry + 1);
  609     }
  610 }
  611 
  612 /*
  613  * Public interfaces.
  614  */
  615 int
  616 acpi_cmbat_get_battinfo(int unit, struct acpi_battinfo *battinfo)
  617 {
  618     int         error;
  619     struct acpi_cmbat_softc *sc;
  620 
  621     ACPI_SERIAL_BEGIN(cmbat);
  622     error = acpi_cmbat_get_total_battinfo(battinfo);
  623     if (unit == -1 || error)
  624         goto out;
  625 
  626     error = ENXIO;
  627     if (unit >= acpi_cmbat_units)
  628         goto out;
  629     if ((sc = devclass_get_softc(acpi_cmbat_devclass, unit)) == NULL)
  630         goto out;
  631 
  632     if (!sc->present) {
  633         battinfo->cap = -1;
  634         battinfo->min = -1;
  635         battinfo->state = ACPI_BATT_STAT_NOT_PRESENT;
  636     } else {
  637         battinfo->cap = sc->cap;
  638         battinfo->min = sc->min;
  639         battinfo->state = sc->bst.state;
  640     }
  641     error = 0;
  642 
  643 out:
  644     ACPI_SERIAL_END(cmbat);
  645     return (error);
  646 }

Cache object: 933a57312e8c9a61efe3f300a76bed96


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.