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$
   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         /*
  409          * No security check required: information retrieval only.  If
  410          * new functions are added here, a check might be required.
  411          */
  412         
  413         switch (cmd) {
  414         case ACPIIO_CMBAT_GET_BIF:
  415                 acpi_cmbat_get_bif(dev);
  416                 bifp = &ioctl_arg->bif;
  417                 bifp->unit = sc->bif.unit;
  418                 bifp->dcap = sc->bif.dcap;
  419                 bifp->lfcap = sc->bif.lfcap;
  420                 bifp->btech = sc->bif.btech;
  421                 bifp->dvol = sc->bif.dvol;
  422                 bifp->wcap = sc->bif.wcap;
  423                 bifp->lcap = sc->bif.lcap;
  424                 bifp->gra1 = sc->bif.gra1;
  425                 bifp->gra2 = sc->bif.gra2;
  426                 strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model));
  427                 strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial));
  428                 strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type));
  429                 strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo));
  430                 break;
  431 
  432         case ACPIIO_CMBAT_GET_BST:
  433                 bstp = &ioctl_arg->bst;
  434                 if (acpi_BatteryIsPresent(dev)) {
  435                         acpi_cmbat_get_bst(dev);
  436                         bstp->state = sc->bst.state;
  437                         bstp->rate = sc->bst.rate;
  438                         bstp->cap = sc->bst.cap;
  439                         bstp->volt = sc->bst.volt;
  440                 } else
  441                         bstp->state = ACPI_BATT_STAT_NOT_PRESENT;
  442                 break;
  443         }
  444 
  445         return (0);
  446 }
  447 
  448 static __inline int
  449 acpi_cmbat_is_bst_valid(struct acpi_bst *bst)
  450 {
  451         if (bst->state >= ACPI_BATT_STAT_MAX ||
  452             bst->cap == 0xffffffff ||
  453             bst->volt == 0xffffffff) {
  454                 return (0);
  455         }
  456 
  457         return (1);
  458 }
  459 
  460 static __inline int
  461 acpi_cmbat_is_bif_valid(struct acpi_bif *bif)
  462 {
  463         if (bif->lfcap == 0) {
  464                 return (0);
  465         }
  466 
  467         return (1);
  468 }
  469 
  470 static int
  471 acpi_cmbat_get_total_battinfo(struct acpi_battinfo *battinfo)
  472 {
  473         int             i;
  474         int             error;
  475         int             batt_stat;
  476         int             valid_rate, valid_units;
  477         int             cap, min;
  478         int             total_cap, total_min, total_full;
  479         device_t        dev;
  480         struct acpi_cmbat_softc *sc;
  481         static int      bat_units = 0;
  482         static struct acpi_cmbat_softc **bat = NULL;
  483 
  484         cap = min = -1;
  485         batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
  486         error = 0;
  487 
  488         /* Allocate array of softc pointers */
  489         if (bat_units != acpi_cmbat_units) {
  490                 if (bat != NULL) {
  491                         free(bat, M_ACPICMBAT);
  492                         bat = NULL;
  493                 }
  494                 bat_units = 0;
  495         }
  496         if (bat == NULL) {
  497                 bat_units = acpi_cmbat_units;
  498                 bat = malloc(sizeof(struct acpi_cmbat_softc *) * bat_units,
  499                              M_ACPICMBAT, M_NOWAIT);
  500                 if (bat == NULL) {
  501                         error = ENOMEM;
  502                         goto out;
  503                 }
  504 
  505                 /* Collect softc pointers */
  506                 for (i = 0; i < acpi_cmbat_units; i++) {
  507                         if ((dev = devclass_get_device(acpi_cmbat_devclass, i)) == NULL) {
  508                                 error = ENXIO;
  509                                 goto out;
  510                         }
  511 
  512                         if ((sc = device_get_softc(dev)) == NULL) {
  513                                 error = ENXIO;
  514                                 goto out;
  515                         }
  516 
  517                         bat[i] = sc;
  518                 }
  519         }
  520 
  521         /* Get battery status, valid rate and valid units */
  522         batt_stat = valid_rate = valid_units = 0;
  523         for (i = 0; i < acpi_cmbat_units; i++) {
  524                 bat[i]->present = acpi_BatteryIsPresent(bat[i]->dev);
  525                 if (!bat[i]->present)
  526                         continue;
  527 
  528                 acpi_cmbat_get_bst(bat[i]->dev);
  529 
  530                 /* If battey not installed, we get strange values */
  531                 if (!acpi_cmbat_is_bst_valid(&(bat[i]->bst)) ||
  532                     !acpi_cmbat_is_bif_valid(&(bat[i]->bif))) {
  533                         bat[i]->present = 0;
  534                         continue;
  535                 }
  536 
  537                 valid_units++;
  538 
  539                 bat[i]->cap = 100 * bat[i]->bst.cap / bat[i]->bif.lfcap;
  540 
  541                 batt_stat |= bat[i]->bst.state;
  542 
  543                 if (bat[i]->bst.rate > 0) {
  544                         /*
  545                          * XXX Hack to calculate total battery time.
  546                          * Systems with 2 or more battries, they may get used
  547                          * one by one, thus bst.rate is set only to the one
  548                          * in use. For remaining batteries bst.rate = 0, which
  549                          * makes it impossible to calculate remaining time.
  550                          * Some other systems may need sum of bst.rate in
  551                          * dis-charging state.
  552                          * There for we sum up the bst.rate that is valid
  553                          * (in dis-charging state), and use the sum to
  554                          * calcutate remaining batteries' time.
  555                          */
  556                         if (bat[i]->bst.state & ACPI_BATT_STAT_DISCHARG) {
  557                                 valid_rate += bat[i]->bst.rate;
  558                         }
  559                 }
  560         }
  561 
  562         /* Calculate total battery capacity and time */
  563         total_cap = total_min = total_full = 0;
  564         for (i = 0; i < acpi_cmbat_units; i++) {
  565                 if (!bat[i]->present) {
  566                         continue;
  567                 }
  568 
  569                 if (valid_rate > 0) {
  570                         /* Use the sum of bst.rate */
  571                         bat[i]->min = 60 * bat[i]->bst.cap / valid_rate;
  572                 } else if (bat[i]->full_charge_time > 0) {
  573                         bat[i]->min = (bat[i]->full_charge_time * bat[i]->cap) / 100;
  574                 } else {
  575                         /* Couldn't find valid rate and full battery time */
  576                         bat[i]->min = 0;
  577                 }
  578                 total_min += bat[i]->min;
  579                 total_cap += bat[i]->cap;
  580                 total_full += bat[i]->full_charge_time;
  581         }
  582 
  583         /* Battery life */
  584         if (valid_units == 0) {
  585                 cap = -1;
  586                 batt_stat = ACPI_BATT_STAT_NOT_PRESENT;
  587         } else {
  588                 cap = total_cap / valid_units;
  589         }
  590 
  591         /* Battery time */
  592         if (valid_units == 0) {
  593                 min = -1;
  594         } else if (valid_rate == 0 || (batt_stat & ACPI_BATT_STAT_CHARGING)) {
  595                 if (total_full == 0) {
  596                         min = -1;
  597                 } else {
  598                         min = (total_full * cap) / 100;
  599                 }
  600         } else {
  601                 min = total_min;
  602         }
  603 
  604         acpi_cmbat_info_updated(&acpi_cmbat_info_lastupdated);
  605 out:
  606         battinfo->cap = cap;
  607         battinfo->min = min;
  608         battinfo->state = batt_stat;
  609 
  610         return (error);
  611 }
  612 
  613 static void
  614 acpi_cmbat_init_battery(void *arg)
  615 {
  616         int             retry;
  617         device_t        dev = (device_t)arg;
  618         struct acpi_cmbat_softc *sc = device_get_softc(dev);
  619 #define ACPI_CMBAT_RETRY_MAX    6
  620 
  621         if (sc->initializing) {
  622                 return;
  623         }
  624 
  625         sc->initializing = 1;
  626 
  627         ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  628                     "battery initialization start\n");
  629 
  630         for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10, 0)) {
  631                 sc->present = acpi_BatteryIsPresent(dev);
  632                 if (!sc->present) {
  633                         continue;
  634                 }
  635 
  636                 timespecclear(&sc->bst_lastupdated);
  637                 timespecclear(&sc->bif_lastupdated);
  638 
  639                 acpi_cmbat_get_bst(dev);
  640 
  641                 if (!acpi_cmbat_is_bst_valid(&sc->bst)) {
  642                         continue;
  643                 }
  644 
  645                 acpi_cmbat_get_bif(dev);
  646 
  647                 if (!acpi_cmbat_is_bif_valid(&sc->bif)) {
  648                         continue;
  649                 }
  650 
  651                 break;
  652         }
  653 
  654         if (retry == ACPI_CMBAT_RETRY_MAX)
  655                 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  656                             "battery initialization failed, giving up\n");
  657         else
  658                 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
  659                             "battery initialization done, tried %d times\n",
  660                             retry+1);
  661 
  662         sc->initializing = 0;
  663 }
  664 
  665 /*
  666  * Public interfaces.
  667  */
  668 
  669 int
  670 acpi_cmbat_get_battinfo(int unit, struct acpi_battinfo *battinfo)
  671 {
  672         int             error;
  673         device_t        dev;
  674         struct acpi_cmbat_softc *sc;
  675 
  676         if (unit == -1) {
  677                 return (acpi_cmbat_get_total_battinfo(battinfo));
  678         }
  679 
  680         if (acpi_cmbat_info_expired(&acpi_cmbat_info_lastupdated)) {
  681                 error = acpi_cmbat_get_total_battinfo(battinfo);
  682                 if (error) {
  683                         goto out;
  684                 }
  685         }
  686 
  687         error = 0;
  688         if (unit >= acpi_cmbat_units) {
  689                 error = ENXIO;
  690                 goto out;
  691         }
  692 
  693         if ((dev = devclass_get_device(acpi_cmbat_devclass, unit)) == NULL) {
  694                 error = ENXIO;
  695                 goto out;
  696         }
  697 
  698         if ((sc = device_get_softc(dev)) == NULL) {
  699                 error = ENXIO;
  700                 goto out;
  701         }
  702 
  703         if (!sc->present) {
  704                 battinfo->cap = -1;
  705                 battinfo->min = -1;
  706                 battinfo->state = ACPI_BATT_STAT_NOT_PRESENT;
  707         } else {
  708                 battinfo->cap = sc->cap;
  709                 battinfo->min = sc->min;
  710                 battinfo->state = sc->bst.state;
  711         }
  712 out:
  713         return (error);
  714 }
  715 

Cache object: 7aee06decd652593dea361ebbe56d701


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