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

Cache object: c64c760dc7548e0f5a21a5c7ec0a8e39


[ 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.