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

Cache object: 8e9fffd4288242cf4415c399ca6ff6f0


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