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/acpi/acpi_bat.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 /*      $NetBSD: acpi_bat.c,v 1.36.2.1 2004/07/02 17:27:10 he Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Charles M. Hannum of By Noon Software, Inc.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the NetBSD
   21  *      Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * Copyright 2001 Bill Sommerfeld.
   41  * All rights reserved.
   42  *
   43  * Redistribution and use in source and binary forms, with or without
   44  * modification, are permitted provided that the following conditions
   45  * are met:
   46  * 1. Redistributions of source code must retain the above copyright
   47  *    notice, this list of conditions and the following disclaimer.
   48  * 2. Redistributions in binary form must reproduce the above copyright
   49  *    notice, this list of conditions and the following disclaimer in the
   50  *    documentation and/or other materials provided with the distribution.
   51  * 3. All advertising materials mentioning features or use of this software
   52  *    must display the following acknowledgement:
   53  *      This product includes software developed for the NetBSD Project by
   54  *      Wasabi Systems, Inc.
   55  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
   56  *    or promote products derived from this software without specific prior
   57  *    written permission.
   58  *
   59  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
   60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   61  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   62  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
   63  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   64  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   65  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   66  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   67  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   68  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   69  * POSSIBILITY OF SUCH DAMAGE.
   70  */
   71 
   72 #if 0
   73 #define ACPI_BAT_DEBUG
   74 #endif
   75 
   76 /*
   77  * ACPI Battery Driver.
   78  *
   79  * ACPI defines two different battery device interfaces: "Control
   80  * Method" batteries, in which AML methods are defined in order to get
   81  * battery status and set battery alarm thresholds, and a "Smart
   82  * Battery" device, which is an SMbus device accessed through the ACPI
   83  * Embedded Controller device.
   84  *
   85  * This driver is for the "Control Method"-style battery only.
   86  */
   87 
   88 #include <sys/cdefs.h>
   89 __KERNEL_RCSID(0, "$NetBSD: acpi_bat.c,v 1.36.2.1 2004/07/02 17:27:10 he Exp $");
   90 
   91 #include <sys/param.h>
   92 #include <sys/systm.h>
   93 #include <sys/kernel.h>         /* for hz */
   94 #include <sys/device.h>
   95 #include <dev/sysmon/sysmonvar.h>
   96 
   97 #include <dev/acpi/acpica.h>
   98 #include <dev/acpi/acpireg.h>
   99 #include <dev/acpi/acpivar.h>
  100 
  101 /* sensor indexes */
  102 #define ACPIBAT_PRESENT         0
  103 #define ACPIBAT_DCAPACITY       1
  104 #define ACPIBAT_LFCCAPACITY     2
  105 #define ACPIBAT_TECHNOLOGY      3
  106 #define ACPIBAT_DVOLTAGE        4
  107 #define ACPIBAT_WCAPACITY       5
  108 #define ACPIBAT_LCAPACITY       6
  109 #define ACPIBAT_VOLTAGE         7
  110 #define ACPIBAT_CHARGERATE      8
  111 #define ACPIBAT_DISCHARGERATE   9
  112 #define ACPIBAT_CAPACITY        10
  113 #define ACPIBAT_CHARGING        11
  114 #define ACPIBAT_DISCHARGING     12
  115 #define ACPIBAT_NSENSORS        13  /* number of sensors */
  116 
  117 const struct envsys_range acpibat_range_amp[] = {
  118         { 0, 1,         ENVSYS_SVOLTS_DC },
  119         { 1, 2,         ENVSYS_SAMPS },
  120         { 2, 3,         ENVSYS_SAMPHOUR },
  121         { 1, 0,         -1 },
  122 };
  123 
  124 const struct envsys_range acpibat_range_watt[] = {
  125         { 0, 1,         ENVSYS_SVOLTS_DC },
  126         { 1, 2,         ENVSYS_SWATTS },
  127         { 2, 3,         ENVSYS_SWATTHOUR },
  128         { 1, 0,         -1 },
  129 };
  130 
  131 struct acpibat_softc {
  132         struct device sc_dev;           /* base device glue */
  133         struct acpi_devnode *sc_node;   /* our ACPI devnode */
  134         int sc_flags;                   /* see below */
  135         int sc_available;               /* available information level */
  136 
  137         struct sysmon_envsys sc_sysmon;
  138         struct envsys_basic_info sc_info[ACPIBAT_NSENSORS];
  139         struct envsys_tre_data sc_data[ACPIBAT_NSENSORS];
  140 
  141         struct simplelock sc_lock;
  142 
  143         struct timeval sc_lastupdate, sc_updateinterval;
  144 };
  145 
  146 static const char * const bat_hid[] = {
  147         "PNP0C0A",
  148         NULL
  149 };
  150 
  151 /*
  152  * These flags are used to examine the battery device data returned from
  153  * the ACPI interface, specifically the "battery status"
  154  */
  155 #define ACPIBAT_PWRUNIT_MA      0x00000001  /* mA not mW */
  156 
  157 /*
  158  * These flags are used to examine the battery charge/discharge/critical
  159  * state returned from a get-status command.
  160  */
  161 #define ACPIBAT_ST_DISCHARGING  0x00000001  /* battery is discharging */
  162 #define ACPIBAT_ST_CHARGING     0x00000002  /* battery is charging */
  163 #define ACPIBAT_ST_CRITICAL     0x00000004  /* battery is critical */
  164 
  165 /*
  166  * Flags for battery status from _STA return
  167  */
  168 #define ACPIBAT_STA_PRESENT     0x00000010  /* battery present */
  169 
  170 /*
  171  * These flags are used to set internal state in our softc.
  172  */
  173 #define ABAT_F_VERBOSE          0x01    /* verbose events */
  174 #define ABAT_F_PWRUNIT_MA       0x02    /* mA instead of mW */
  175 #define ABAT_F_PRESENT          0x04    /* is the battery present? */
  176 #define ABAT_F_LOCKED           0x08    /* is locked? */
  177 
  178 #define ABAT_SET(sc, f)         (void)((sc)->sc_flags |= (f))
  179 #define ABAT_CLEAR(sc, f)       (void)((sc)->sc_flags &= ~(f))
  180 #define ABAT_ISSET(sc, f)       ((sc)->sc_flags & (f))
  181 
  182 /*
  183  * Available info level
  184  */
  185 
  186 #define ABAT_ALV_NONE           0       /* none is available */
  187 #define ABAT_ALV_PRESENCE       1       /* presence info is available */
  188 #define ABAT_ALV_INFO           2       /* battery info is available */
  189 #define ABAT_ALV_STAT           3       /* battery status is available */
  190 
  191 #define ABAT_ASSERT_LOCKED(sc)                                  \
  192 do {                                                            \
  193         if (!((sc)->sc_flags & ABAT_F_LOCKED))                  \
  194                 panic("acpi_bat (expected to be locked)");      \
  195 } while(/*CONSTCOND*/0)
  196 #define ABAT_ASSERT_UNLOCKED(sc)                                \
  197 do {                                                            \
  198         if (((sc)->sc_flags & ABAT_F_LOCKED))                   \
  199                 panic("acpi_bat (expected to be unlocked)");    \
  200 } while(/*CONSTCOND*/0)
  201 #define ABAT_LOCK(sc, s)                        \
  202 do {                                            \
  203         ABAT_ASSERT_UNLOCKED(sc);               \
  204         (s) = splhigh();                        \
  205         simple_lock(&(sc)->sc_lock);            \
  206         ABAT_SET((sc), ABAT_F_LOCKED);          \
  207 } while(/*CONSTCOND*/0)
  208 #define ABAT_UNLOCK(sc, s)                      \
  209 do {                                            \
  210         ABAT_ASSERT_LOCKED(sc);                 \
  211         ABAT_CLEAR((sc), ABAT_F_LOCKED);        \
  212         simple_unlock(&(sc)->sc_lock);          \
  213         splx((s));                              \
  214 } while(/*CONSTCOND*/0)
  215 
  216 int     acpibat_match(struct device *, struct cfdata *, void *);
  217 void    acpibat_attach(struct device *, struct device *, void *);
  218 
  219 CFATTACH_DECL(acpibat, sizeof(struct acpibat_softc),
  220     acpibat_match, acpibat_attach, NULL, NULL);
  221 
  222 static void acpibat_clear_presence(struct acpibat_softc *);
  223 static void acpibat_clear_info(struct acpibat_softc *);
  224 static void acpibat_clear_stat(struct acpibat_softc *);
  225 static int acpibat_battery_present(struct acpibat_softc *);
  226 static ACPI_STATUS acpibat_get_status(struct acpibat_softc *);
  227 static ACPI_STATUS acpibat_get_info(struct acpibat_softc *);
  228 static void acpibat_print_info(struct acpibat_softc *);
  229 static void acpibat_print_stat(struct acpibat_softc *);
  230 static void acpibat_update(void *);
  231 
  232 static void acpibat_init_envsys(struct acpibat_softc *);
  233 static void acpibat_notify_handler(ACPI_HANDLE, UINT32, void *context);
  234 static int acpibat_gtredata(struct sysmon_envsys *, struct envsys_tre_data *);
  235 static int acpibat_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
  236 
  237 /*
  238  * acpibat_match:
  239  *
  240  *      Autoconfiguration `match' routine.
  241  */
  242 int
  243 acpibat_match(struct device *parent, struct cfdata *match, void *aux)
  244 {
  245         struct acpi_attach_args *aa = aux;
  246 
  247         if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
  248                 return (0);
  249 
  250         return (acpi_match_hid(aa->aa_node->ad_devinfo, bat_hid));
  251 }
  252 
  253 /*
  254  * acpibat_attach:
  255  *
  256  *      Autoconfiguration `attach' routine.
  257  */
  258 void
  259 acpibat_attach(struct device *parent, struct device *self, void *aux)
  260 {
  261         struct acpibat_softc *sc = (void *) self;
  262         struct acpi_attach_args *aa = aux;
  263         ACPI_STATUS rv;
  264 
  265         printf(": ACPI Battery (Control Method)\n");
  266 
  267         sc->sc_node = aa->aa_node;
  268         simple_lock_init(&sc->sc_lock);
  269 
  270         rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle,
  271                                       ACPI_DEVICE_NOTIFY,
  272                                       acpibat_notify_handler, sc);
  273         if (ACPI_FAILURE(rv)) {
  274                 printf("%s: unable to register DEVICE NOTIFY handler: %s\n",
  275                        sc->sc_dev.dv_xname, AcpiFormatException(rv));
  276                 return;
  277         }
  278 
  279         /* XXX See acpibat_notify_handler() */
  280         rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle,
  281                                       ACPI_SYSTEM_NOTIFY,
  282                                       acpibat_notify_handler, sc);
  283         if (ACPI_FAILURE(rv)) {
  284                 printf("%s: unable to register SYSTEM NOTIFY handler: %s\n",
  285                        sc->sc_dev.dv_xname, AcpiFormatException(rv));
  286                 return;
  287         }
  288 
  289 #ifdef ACPI_BAT_DEBUG
  290         ABAT_SET(sc, ABAT_F_VERBOSE);
  291 #endif
  292 
  293         acpibat_init_envsys(sc);
  294 }
  295 
  296 /*
  297  * clear informations
  298  */
  299 
  300 void
  301 acpibat_clear_presence(struct acpibat_softc *sc)
  302 {
  303 
  304         ABAT_ASSERT_LOCKED(sc);
  305 
  306         acpibat_clear_info(sc);
  307         sc->sc_available = ABAT_ALV_NONE;
  308         ABAT_CLEAR(sc, ABAT_F_PRESENT);
  309 }
  310 
  311 void
  312 acpibat_clear_info(struct acpibat_softc *sc)
  313 {
  314 
  315         ABAT_ASSERT_LOCKED(sc);
  316 
  317         acpibat_clear_stat(sc);
  318         if (sc->sc_available>ABAT_ALV_PRESENCE)
  319                 sc->sc_available = ABAT_ALV_PRESENCE;
  320         sc->sc_data[ACPIBAT_DCAPACITY].validflags &= ~ENVSYS_FCURVALID;
  321         sc->sc_data[ACPIBAT_LFCCAPACITY].validflags &= ~ENVSYS_FCURVALID;
  322         sc->sc_data[ACPIBAT_CAPACITY].validflags &= ~ENVSYS_FMAXVALID;
  323         sc->sc_data[ACPIBAT_TECHNOLOGY].validflags &= ~ENVSYS_FCURVALID;
  324         sc->sc_data[ACPIBAT_DVOLTAGE].validflags &= ~ENVSYS_FCURVALID;
  325         sc->sc_data[ACPIBAT_WCAPACITY].validflags &= ~(ENVSYS_FCURVALID | ENVSYS_FMAXVALID | ENVSYS_FFRACVALID);
  326         sc->sc_data[ACPIBAT_LCAPACITY].validflags &= ~(ENVSYS_FCURVALID | ENVSYS_FMAXVALID | ENVSYS_FFRACVALID);
  327 }
  328 
  329 void
  330 acpibat_clear_stat(struct acpibat_softc *sc)
  331 {
  332 
  333         ABAT_ASSERT_LOCKED(sc);
  334 
  335         if (sc->sc_available>ABAT_ALV_INFO)
  336                 sc->sc_available = ABAT_ALV_INFO;
  337         sc->sc_data[ACPIBAT_CHARGERATE].validflags &= ~ENVSYS_FCURVALID;
  338         sc->sc_data[ACPIBAT_DISCHARGERATE].validflags &= ~ENVSYS_FCURVALID;
  339         sc->sc_data[ACPIBAT_CAPACITY].validflags &= ~(ENVSYS_FCURVALID | ENVSYS_FFRACVALID);
  340         sc->sc_data[ACPIBAT_CAPACITY].warnflags = 0;
  341         sc->sc_data[ACPIBAT_VOLTAGE].validflags &= ~ENVSYS_FCURVALID;
  342         sc->sc_data[ACPIBAT_CHARGING].validflags &= ~ENVSYS_FCURVALID;
  343         sc->sc_data[ACPIBAT_DISCHARGING].validflags &= ~ENVSYS_FCURVALID;
  344 }
  345 
  346 
  347 /*
  348  * returns 0 for no battery, 1 for present, and -1 on error
  349  */
  350 int
  351 acpibat_battery_present(struct acpibat_softc *sc)
  352 {
  353         u_int32_t sta;
  354         int s;
  355         ACPI_INTEGER val;
  356         ACPI_STATUS rv;
  357 
  358         rv = acpi_eval_integer(sc->sc_node->ad_handle, "_STA", &val);
  359         if (ACPI_FAILURE(rv)) {
  360                 printf("%s: failed to evaluate _STA: %s\n",
  361                        sc->sc_dev.dv_xname, AcpiFormatException(rv));
  362                 return (-1);
  363         }
  364 
  365         sta = (u_int32_t)val;
  366 
  367         ABAT_LOCK(sc, s);
  368         sc->sc_available = ABAT_ALV_PRESENCE;
  369         if (sta & ACPIBAT_STA_PRESENT) {
  370                 ABAT_SET(sc, ABAT_F_PRESENT);
  371                 sc->sc_data[ACPIBAT_PRESENT].cur.data_s = 1;
  372         } else
  373                 sc->sc_data[ACPIBAT_PRESENT].cur.data_s = 0;
  374         sc->sc_data[ACPIBAT_PRESENT].validflags |= ENVSYS_FCURVALID;
  375         ABAT_UNLOCK(sc, s);
  376 
  377         return ((sta & ACPIBAT_STA_PRESENT)?1:0);
  378 }
  379 
  380 /*
  381  * acpibat_get_info
  382  *
  383  *      Get, and possibly display, the battery info.
  384  */
  385 
  386 ACPI_STATUS
  387 acpibat_get_info(struct acpibat_softc *sc)
  388 {
  389         ACPI_OBJECT *p1, *p2;
  390         ACPI_STATUS rv;
  391         ACPI_BUFFER buf;
  392         int capunit, rateunit, s;
  393 
  394         rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BIF", &buf);
  395         if (ACPI_FAILURE(rv)) {
  396                 printf("%s: failed to evaluate _BIF: %s\n",
  397                     sc->sc_dev.dv_xname, AcpiFormatException(rv));
  398                 return (rv);
  399         }
  400         p1 = (ACPI_OBJECT *)buf.Pointer;
  401 
  402         if (p1->Type != ACPI_TYPE_PACKAGE) {
  403                 printf("%s: expected PACKAGE, got %d\n", sc->sc_dev.dv_xname,
  404                     p1->Type);
  405                 goto out;
  406         }
  407         if (p1->Package.Count < 13) {
  408                 printf("%s: expected 13 elts, got %d\n",
  409                     sc->sc_dev.dv_xname, p1->Package.Count);
  410                 goto out;
  411         }
  412         p2 = p1->Package.Elements;
  413 
  414         ABAT_LOCK(sc, s);
  415         if ((p2[0].Integer.Value & ACPIBAT_PWRUNIT_MA) != 0) {
  416                 ABAT_SET(sc, ABAT_F_PWRUNIT_MA);
  417                 sc->sc_sysmon.sme_ranges = acpibat_range_amp;
  418                 capunit = ENVSYS_SAMPHOUR;
  419                 rateunit = ENVSYS_SAMPS;
  420         } else {
  421                 ABAT_CLEAR(sc, ABAT_F_PWRUNIT_MA);
  422                 sc->sc_sysmon.sme_ranges = acpibat_range_watt;
  423                 capunit = ENVSYS_SWATTHOUR;
  424                 rateunit = ENVSYS_SWATTS;
  425         }
  426 
  427 #define INITDATA(index, unit) \
  428         sc->sc_data[index].units = unit;                                \
  429         sc->sc_info[index].units = unit;
  430 
  431         INITDATA(ACPIBAT_DCAPACITY, capunit);
  432         INITDATA(ACPIBAT_LFCCAPACITY, capunit);
  433         INITDATA(ACPIBAT_WCAPACITY, capunit);
  434         INITDATA(ACPIBAT_LCAPACITY, capunit);
  435         INITDATA(ACPIBAT_CHARGERATE, rateunit);
  436         INITDATA(ACPIBAT_DISCHARGERATE, rateunit);
  437         INITDATA(ACPIBAT_CAPACITY, capunit);
  438 
  439 #undef INITDATA
  440 
  441         sc->sc_data[ACPIBAT_DCAPACITY].cur.data_s = p2[1].Integer.Value * 1000;
  442         sc->sc_data[ACPIBAT_DCAPACITY].validflags |= ENVSYS_FCURVALID;
  443         sc->sc_data[ACPIBAT_LFCCAPACITY].cur.data_s = p2[2].Integer.Value * 1000;
  444         sc->sc_data[ACPIBAT_LFCCAPACITY].validflags |= ENVSYS_FCURVALID;
  445         sc->sc_data[ACPIBAT_CAPACITY].max.data_s = p2[2].Integer.Value * 1000;
  446         sc->sc_data[ACPIBAT_CAPACITY].validflags |= ENVSYS_FMAXVALID;
  447         sc->sc_data[ACPIBAT_TECHNOLOGY].cur.data_s = p2[3].Integer.Value;
  448         sc->sc_data[ACPIBAT_TECHNOLOGY].validflags |= ENVSYS_FCURVALID;
  449         sc->sc_data[ACPIBAT_DVOLTAGE].cur.data_s = p2[4].Integer.Value * 1000;
  450         sc->sc_data[ACPIBAT_DVOLTAGE].validflags |= ENVSYS_FCURVALID;
  451         sc->sc_data[ACPIBAT_WCAPACITY].cur.data_s = p2[5].Integer.Value * 1000;
  452         sc->sc_data[ACPIBAT_WCAPACITY].max.data_s = p2[2].Integer.Value * 1000;
  453         sc->sc_data[ACPIBAT_WCAPACITY].validflags |= ENVSYS_FCURVALID | ENVSYS_FMAXVALID | ENVSYS_FFRACVALID;
  454         sc->sc_data[ACPIBAT_LCAPACITY].cur.data_s = p2[6].Integer.Value * 1000;
  455         sc->sc_data[ACPIBAT_LCAPACITY].max.data_s = p2[2].Integer.Value * 1000;
  456         sc->sc_data[ACPIBAT_LCAPACITY].validflags |= ENVSYS_FCURVALID | ENVSYS_FMAXVALID | ENVSYS_FFRACVALID;
  457         sc->sc_available = ABAT_ALV_INFO;
  458         ABAT_UNLOCK(sc, s);
  459 
  460         printf("%s: battery info: %s, %s, %s, %s\n", sc->sc_dev.dv_xname,
  461             p2[12].String.Pointer, p2[11].String.Pointer,
  462             p2[9].String.Pointer, p2[10].String.Pointer);
  463 
  464         rv = AE_OK;
  465 
  466 out:
  467         AcpiOsFree(buf.Pointer);
  468         return (rv);
  469 }
  470 
  471 /*
  472  * acpibat_get_status:
  473  *
  474  *      Get, and possibly display, the current battery line status.
  475  */
  476 ACPI_STATUS
  477 acpibat_get_status(struct acpibat_softc *sc)
  478 {
  479         int flags, status, s;
  480         ACPI_OBJECT *p1, *p2;
  481         ACPI_STATUS rv;
  482         ACPI_BUFFER buf;
  483 
  484         rv = acpi_eval_struct(sc->sc_node->ad_handle, "_BST", &buf);
  485         if (ACPI_FAILURE(rv)) {
  486                 printf("%s: failed to evaluate _BST: %s\n",
  487                     sc->sc_dev.dv_xname, AcpiFormatException(rv));
  488                 return (rv);
  489         }
  490         p1 = (ACPI_OBJECT *)buf.Pointer;
  491 
  492         if (p1->Type != ACPI_TYPE_PACKAGE) {
  493                 printf("bat: expected PACKAGE, got %d\n", p1->Type);
  494                 rv = AE_ERROR;
  495                 goto out;
  496         }
  497         if (p1->Package.Count < 4) {
  498                 printf("bat: expected 4 elts, got %d\n", p1->Package.Count);
  499                 rv = AE_ERROR;
  500                 goto out;
  501         }
  502         p2 = p1->Package.Elements;
  503 
  504         ABAT_LOCK(sc, s);
  505         status = p2[0].Integer.Value;
  506         sc->sc_data[ACPIBAT_CHARGERATE].validflags &= ~ENVSYS_FCURVALID;
  507         sc->sc_data[ACPIBAT_DISCHARGERATE].validflags &= ~ENVSYS_FCURVALID;
  508         if (p2[1].Integer.Value != -1) {
  509                 if (status & ACPIBAT_ST_CHARGING) {
  510                         sc->sc_data[ACPIBAT_CHARGERATE].cur.data_s = p2[1].Integer.Value * 1000;
  511                         sc->sc_data[ACPIBAT_CHARGERATE].validflags |= ENVSYS_FCURVALID;
  512                 } else if (status & ACPIBAT_ST_DISCHARGING) {
  513                         sc->sc_data[ACPIBAT_DISCHARGERATE].cur.data_s = p2[1].Integer.Value * 1000;
  514                         sc->sc_data[ACPIBAT_DISCHARGERATE].validflags |= ENVSYS_FCURVALID;
  515                 }
  516         }
  517         sc->sc_data[ACPIBAT_CAPACITY].cur.data_s = p2[2].Integer.Value * 1000;
  518         sc->sc_data[ACPIBAT_CAPACITY].validflags |= ENVSYS_FCURVALID | ENVSYS_FFRACVALID;
  519         sc->sc_data[ACPIBAT_VOLTAGE].cur.data_s = p2[3].Integer.Value * 1000;
  520         sc->sc_data[ACPIBAT_VOLTAGE].validflags |= ENVSYS_FCURVALID;
  521         flags = 0;
  522         if (sc->sc_data[ACPIBAT_CAPACITY].cur.data_s <
  523             sc->sc_data[ACPIBAT_WCAPACITY].cur.data_s)
  524                 flags |= ENVSYS_WARN_UNDER;
  525         if (status & ACPIBAT_ST_CRITICAL)
  526                 flags |= ENVSYS_WARN_CRITUNDER;
  527         sc->sc_data[ACPIBAT_CAPACITY].warnflags = flags;
  528         sc->sc_data[ACPIBAT_CHARGING].cur.data_s =
  529             ((status & ACPIBAT_ST_CHARGING) != 0);
  530         sc->sc_data[ACPIBAT_CHARGING].validflags |= ENVSYS_FCURVALID;
  531         sc->sc_data[ACPIBAT_DISCHARGING].cur.data_s =
  532             ((status & ACPIBAT_ST_DISCHARGING) != 0);
  533         sc->sc_data[ACPIBAT_DISCHARGING].validflags |= ENVSYS_FCURVALID;
  534         sc->sc_available = ABAT_ALV_STAT;
  535         ABAT_UNLOCK(sc, s);
  536 
  537         rv = AE_OK;
  538 
  539 out:
  540         AcpiOsFree(buf.Pointer);
  541         return (rv);
  542 }
  543 
  544 #define SCALE(x)        ((x)/1000000), (((x)%1000000)/1000)
  545 #define CAPUNITS(sc)    (ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"Ah":"Wh")
  546 #define RATEUNITS(sc)   (ABAT_ISSET((sc), ABAT_F_PWRUNIT_MA)?"A":"W")
  547 static void
  548 acpibat_print_info(struct acpibat_softc *sc)
  549 {
  550         const char *tech;
  551 
  552         if (sc->sc_data[ACPIBAT_TECHNOLOGY].cur.data_s)
  553                 tech = "secondary";
  554         else
  555                 tech = "primary";
  556 
  557         printf("%s: %s battery, Design %d.%03d%s, Last full %d.%03d%s"
  558                "Warn %d.%03d%s Low %d.%03d%s\n",
  559                sc->sc_dev.dv_xname, tech,
  560                SCALE(sc->sc_data[ACPIBAT_DCAPACITY].cur.data_s), CAPUNITS(sc),
  561                SCALE(sc->sc_data[ACPIBAT_LFCCAPACITY].cur.data_s),CAPUNITS(sc),
  562                SCALE(sc->sc_data[ACPIBAT_WCAPACITY].cur.data_s), CAPUNITS(sc),
  563                SCALE(sc->sc_data[ACPIBAT_LCAPACITY].cur.data_s), CAPUNITS(sc));
  564 }
  565 
  566 static void
  567 acpibat_print_stat(struct acpibat_softc *sc)
  568 {
  569         const char *capstat, *chargestat;
  570         int percent, denom;
  571 
  572         percent = 0;
  573 
  574         if (sc->sc_data[ACPIBAT_CAPACITY].warnflags&ENVSYS_WARN_CRITUNDER)
  575                 capstat = "CRITICAL ";
  576         else if (sc->sc_data[ACPIBAT_CAPACITY].warnflags&ENVSYS_WARN_UNDER)
  577                 capstat = "UNDER ";
  578         else
  579                 capstat = "";
  580         if (sc->sc_data[ACPIBAT_CHARGING].cur.data_s)
  581                 chargestat = "charging";
  582         else if (sc->sc_data[ACPIBAT_DISCHARGING].cur.data_s)
  583                 chargestat = "discharging";
  584         else
  585                 chargestat = "idling";
  586         denom = sc->sc_data[ACPIBAT_DCAPACITY].cur.data_s / 100;
  587         if (denom > 0)
  588                 percent = (sc->sc_data[ACPIBAT_CAPACITY].cur.data_s) / denom;
  589         printf("%s: %s%s: %d.%03dV cap %d.%03d%s (%d%%) rate %d.%03d%s\n",
  590                sc->sc_dev.dv_xname,
  591                capstat, chargestat,
  592                SCALE(sc->sc_data[ACPIBAT_VOLTAGE].cur.data_s),
  593                SCALE(sc->sc_data[ACPIBAT_CAPACITY].cur.data_s), CAPUNITS(sc),
  594                percent,
  595                SCALE(sc->sc_data[ACPIBAT_CHARGING].cur.data_s ?
  596                      sc->sc_data[ACPIBAT_CHARGERATE].cur.data_s :
  597                      sc->sc_data[ACPIBAT_DISCHARGING].cur.data_s ?
  598                      sc->sc_data[ACPIBAT_DISCHARGERATE].cur.data_s : 0),
  599                      RATEUNITS(sc));
  600 }
  601 
  602 static void
  603 acpibat_update(void *arg)
  604 {
  605         struct acpibat_softc *sc = arg;
  606 
  607         if (sc->sc_available < ABAT_ALV_INFO) {
  608                 /* current information is invalid */
  609 #if 0
  610                 /*
  611                  * XXX: The driver sometimes unaware that the battery exist.
  612                  * (i.e. just after the boot or resuming)
  613                  * Thus, the driver should always check it here.
  614                  */
  615                 if (sc->sc_available < ABAT_ALV_PRESENCE)
  616 #endif
  617                         /* presence is invalid */
  618                         if (acpibat_battery_present(sc)<0) {
  619                                 /* error */
  620                                 printf("%s: cannot get battery presence.\n",
  621                                        sc->sc_dev.dv_xname);
  622                                 return;
  623                         }
  624                 if (ABAT_ISSET(sc, ABAT_F_PRESENT)) {
  625                         /* the battery is present. */
  626                         if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
  627                                 printf("%s: battery is present.\n",
  628                                        sc->sc_dev.dv_xname);
  629                         if (ACPI_FAILURE(acpibat_get_info(sc)))
  630                                 return;
  631                         if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
  632                                 acpibat_print_info(sc);
  633                 } else {
  634                         /* the battery is not present. */
  635                         if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
  636                                 printf("%s: battery is not present.\n",
  637                                        sc->sc_dev.dv_xname);
  638                         return;
  639                 }
  640         } else {
  641                 /* current information is valid */
  642                 if (!ABAT_ISSET(sc, ABAT_F_PRESENT)) {
  643                         /* the battery is not present. */
  644                         return;
  645                 }
  646         }
  647 
  648         if (ACPI_FAILURE(acpibat_get_status(sc)))
  649                 return;
  650 
  651         if (ABAT_ISSET(sc, ABAT_F_VERBOSE))
  652                 acpibat_print_stat(sc);
  653 }
  654 
  655 /*
  656  * acpibat_notify_handler:
  657  *
  658  *      Callback from ACPI interrupt handler to notify us of an event.
  659  */
  660 void
  661 acpibat_notify_handler(ACPI_HANDLE handle, UINT32 notify, void *context)
  662 {
  663         struct acpibat_softc *sc = context;
  664         int rv, s;
  665 
  666 #ifdef ACPI_BAT_DEBUG
  667         printf("%s: received notify message: 0x%x\n",
  668                sc->sc_dev.dv_xname, notify);
  669 #endif
  670 
  671         switch (notify) {
  672         case ACPI_NOTIFY_BusCheck:
  673                 break;
  674 
  675         case ACPI_NOTIFY_DeviceCheck:
  676         case ACPI_NOTIFY_BatteryInformationChanged:
  677                 ABAT_LOCK(sc, s);
  678                 acpibat_clear_presence(sc);
  679                 ABAT_UNLOCK(sc, s);
  680                 rv = AcpiOsQueueForExecution(OSD_PRIORITY_LO,
  681                                              acpibat_update, sc);
  682                 if (ACPI_FAILURE(rv))
  683                         printf("%s: unable to queue status check: %s\n",
  684                                sc->sc_dev.dv_xname, AcpiFormatException(rv));
  685                 break;
  686 
  687         case ACPI_NOTIFY_BatteryStatusChanged:
  688                 ABAT_LOCK(sc, s);
  689                 acpibat_clear_stat(sc);
  690                 ABAT_UNLOCK(sc, s);
  691                 rv = AcpiOsQueueForExecution(OSD_PRIORITY_LO,
  692                                              acpibat_update, sc);
  693                 if (ACPI_FAILURE(rv))
  694                         printf("%s: unable to queue status check: %s\n",
  695                                sc->sc_dev.dv_xname, AcpiFormatException(rv));
  696                 break;
  697 
  698         default:
  699                 printf("%s: received unknown notify message: 0x%x\n",
  700                        sc->sc_dev.dv_xname, notify);
  701         }
  702 }
  703 
  704 void
  705 acpibat_init_envsys(struct acpibat_softc *sc)
  706 {
  707         int capunit, rateunit;
  708 
  709 #if 0
  710         if (sc->sc_flags & ABAT_F_PWRUNIT_MA) {
  711 #endif
  712                 /* XXX */
  713                 sc->sc_sysmon.sme_ranges = acpibat_range_amp;
  714                 capunit = ENVSYS_SAMPHOUR;
  715                 rateunit = ENVSYS_SAMPS;
  716 #if 0
  717         } else {
  718                 sc->sc_sysmon.sme_ranges = acpibat_range_watt;
  719                 capunit = ENVSYS_SWATTHOUR;
  720                 rateunit = ENVSYS_SWATTS;
  721         }
  722 #endif
  723 
  724 #define INITDATA(index, unit, string) \
  725         sc->sc_data[index].sensor = index;                              \
  726         sc->sc_data[index].units = unit;                                \
  727         sc->sc_data[index].validflags = ENVSYS_FVALID;                  \
  728         sc->sc_data[index].warnflags = 0;                               \
  729         sc->sc_info[index].sensor = index;                              \
  730         sc->sc_info[index].units = unit;                                \
  731         sc->sc_info[index].validflags = ENVSYS_FVALID;                  \
  732         snprintf(sc->sc_info[index].desc, sizeof(sc->sc_info->desc),    \
  733             "%s %s", sc->sc_dev.dv_xname, string);                      \
  734 
  735         INITDATA(ACPIBAT_PRESENT, ENVSYS_INDICATOR, "present");
  736         INITDATA(ACPIBAT_DCAPACITY, capunit, "design cap");
  737         INITDATA(ACPIBAT_LFCCAPACITY, capunit, "last full cap");
  738         INITDATA(ACPIBAT_TECHNOLOGY, ENVSYS_INTEGER, "technology");
  739         INITDATA(ACPIBAT_DVOLTAGE, ENVSYS_SVOLTS_DC, "design voltage");
  740         INITDATA(ACPIBAT_WCAPACITY, capunit, "warn cap");
  741         INITDATA(ACPIBAT_LCAPACITY, capunit, "low cap");
  742         INITDATA(ACPIBAT_VOLTAGE, ENVSYS_SVOLTS_DC, "voltage");
  743         INITDATA(ACPIBAT_CHARGERATE, rateunit, "charge rate");
  744         INITDATA(ACPIBAT_DISCHARGERATE, rateunit, "discharge rate");
  745         INITDATA(ACPIBAT_CAPACITY, capunit, "charge");
  746         INITDATA(ACPIBAT_CHARGING, ENVSYS_INDICATOR, "charging");
  747         INITDATA(ACPIBAT_DISCHARGING, ENVSYS_INDICATOR, "discharging");
  748 
  749 #undef INITDATA
  750 
  751         sc->sc_sysmon.sme_sensor_info = sc->sc_info;
  752         sc->sc_sysmon.sme_sensor_data = sc->sc_data;
  753         sc->sc_sysmon.sme_cookie = sc;
  754         sc->sc_sysmon.sme_gtredata = acpibat_gtredata;
  755         sc->sc_sysmon.sme_streinfo = acpibat_streinfo;
  756         sc->sc_sysmon.sme_nsensors = ACPIBAT_NSENSORS;
  757         sc->sc_sysmon.sme_envsys_version = 1000;
  758 
  759         sc->sc_updateinterval.tv_sec = 1;
  760         sc->sc_updateinterval.tv_usec = 0;
  761 
  762         if (sysmon_envsys_register(&sc->sc_sysmon))
  763                 printf("%s: unable to register with sysmon\n",
  764                     sc->sc_dev.dv_xname);
  765 }
  766 
  767 int
  768 acpibat_gtredata(struct sysmon_envsys *sme, struct envsys_tre_data *tred)
  769 {
  770         struct acpibat_softc *sc = sme->sme_cookie;
  771 
  772         if (ratecheck(&sc->sc_lastupdate, &sc->sc_updateinterval))
  773                 acpibat_update(sc);
  774 
  775         /* XXX locking */
  776         *tred = sc->sc_data[tred->sensor];
  777         /* XXX locking */
  778 
  779         return (0);
  780 }
  781 
  782 int
  783 acpibat_streinfo(struct sysmon_envsys *sme, struct envsys_basic_info *binfo)
  784 {
  785 
  786         /* XXX Not implemented */
  787         binfo->validflags = 0;
  788 
  789         return (0);
  790 }

Cache object: 77fca70b1b534fb478583396fd568007


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