root/dev/acpi/acpitz.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. acpitz_match
  2. acpitz_attach
  3. acpitz_setcpu
  4. acpitz_setfan
  5. acpitz_refresh
  6. acpitz_getreading
  7. acpitz_notify

    1 /* $OpenBSD: acpitz.c,v 1.17 2007/03/26 12:30:48 marco Exp $ */
    2 /*
    3  * Copyright (c) 2006 Can Erkin Acar <canacar@openbsd.org>
    4  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include <sys/param.h>
   20 #include <sys/proc.h>
   21 #include <sys/signalvar.h>
   22 #include <sys/systm.h>
   23 #include <sys/device.h>
   24 #include <sys/malloc.h>
   25 
   26 #include <machine/bus.h>
   27 
   28 #include <dev/acpi/acpireg.h>
   29 #include <dev/acpi/acpivar.h>
   30 #include <dev/acpi/acpidev.h>
   31 #include <dev/acpi/amltypes.h>
   32 #include <dev/acpi/dsdt.h>
   33 
   34 #include <sys/sensors.h>
   35 
   36 #define ACPITZ_MAX_AC           10
   37 
   38 struct acpitz_softc {
   39         struct device           sc_dev;
   40 
   41         struct acpi_softc       *sc_acpi;
   42         struct aml_node         *sc_devnode;
   43 
   44         int                     sc_tmp;
   45         int                     sc_crt;
   46         int                     sc_hot;
   47         int                     sc_ac[ACPITZ_MAX_AC];
   48         int                     sc_ac_stat[ACPITZ_MAX_AC];
   49         int                     sc_pse;
   50         int                     sc_psv;
   51         int                     sc_tc1;
   52         int                     sc_tc2;
   53         int                     sc_lasttmp;
   54         struct ksensor          sc_sens;
   55         struct ksensordev       sc_sensdev;
   56 };
   57 
   58 int     acpitz_match(struct device *, void *, void *);
   59 void    acpitz_attach(struct device *, struct device *, void *);
   60 
   61 struct cfattach acpitz_ca = {
   62         sizeof(struct acpitz_softc), acpitz_match, acpitz_attach
   63 };
   64 
   65 struct cfdriver acpitz_cd = {
   66         NULL, "acpitz", DV_DULL
   67 };
   68 
   69 void    acpitz_monitor(struct acpitz_softc *);
   70 void    acpitz_refresh(void *);
   71 int     acpitz_notify(struct aml_node *, int, void *);
   72 int     acpitz_getreading(struct acpitz_softc *, char *);
   73 int     acpitz_setfan(struct acpitz_softc *, int, char *);
   74 int     acpitz_setcpu(struct acpitz_softc *, int);
   75 
   76 int
   77 acpitz_match(struct device *parent, void *match, void *aux)
   78 {
   79         struct acpi_attach_args *aa = aux;
   80         struct cfdata           *cf = match;
   81 
   82         /* sanity */
   83         if (aa->aaa_name == NULL ||
   84             strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
   85             aa->aaa_table != NULL)
   86                 return (0);
   87 
   88         if (aa->aaa_node->value->type != AML_OBJTYPE_THERMZONE)
   89                 return (0);
   90 
   91         return (1);
   92 }
   93 
   94 void
   95 acpitz_attach(struct device *parent, struct device *self, void *aux)
   96 {
   97         struct acpitz_softc     *sc = (struct acpitz_softc *)self;
   98         struct acpi_attach_args *aa = aux;
   99         int                     i;
  100         char                    name[8];
  101 
  102         sc->sc_acpi = (struct acpi_softc *)parent;
  103         sc->sc_devnode = aa->aaa_node->child;
  104 
  105         sc->sc_lasttmp = -1;
  106         if ((sc->sc_tmp = acpitz_getreading(sc, "_TMP")) == -1) {
  107                 printf(", failed to read _TMP\n");
  108                 return;
  109         }
  110 
  111         if ((sc->sc_crt = acpitz_getreading(sc, "_CRT")) == -1) {
  112                 printf(", no critical temperature defined!\n");
  113                 sc->sc_crt = 0;
  114         } else
  115                 printf(", critical temperature: %d degC\n",
  116                     (sc->sc_crt - 2732) / 10);
  117 
  118         for (i = 0; i < ACPITZ_MAX_AC; i++) {
  119                 snprintf(name, sizeof name, "_AC%d", i);
  120                 sc->sc_ac[i] = acpitz_getreading(sc, name);
  121                 sc->sc_ac_stat[0] = -1;
  122         }
  123 
  124         sc->sc_hot = acpitz_getreading(sc, "_HOT");
  125         sc->sc_tc1 = acpitz_getreading(sc, "_TC1");
  126         sc->sc_tc2 = acpitz_getreading(sc, "_TC2");
  127         sc->sc_psv = acpitz_getreading(sc, "_PSV");
  128 
  129         strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
  130             sizeof(sc->sc_sensdev.xname));
  131         strlcpy(sc->sc_sens.desc, "zone temperature",
  132             sizeof(sc->sc_sens.desc));
  133         sc->sc_sens.type = SENSOR_TEMP;
  134         sensor_attach(&sc->sc_sensdev, &sc->sc_sens);
  135         sensordev_install(&sc->sc_sensdev);
  136         sc->sc_sens.value = 0;
  137 
  138         aml_register_notify(sc->sc_devnode->parent, NULL,
  139             acpitz_notify, sc, ACPIDEV_POLL);
  140 }
  141 
  142 int
  143 acpitz_setcpu(struct acpitz_softc *sc, int trend)
  144 {
  145         struct aml_value res0, *ref;
  146         int x;
  147 
  148         if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSL", 0, NULL, &res0)) {
  149                 printf("%s: _PSL failed\n", DEVNAME(sc));
  150                 goto out;
  151         }
  152         if (res0.type != AML_OBJTYPE_PACKAGE) {
  153                 printf("%s: not a package\n", DEVNAME(sc));
  154                 goto out;
  155         }
  156         for (x = 0; x < res0.length; x++) {
  157                 if (res0.v_package[x]->type != AML_OBJTYPE_OBJREF) {
  158                         printf("%s: _PSL[%d] not a object ref\n", DEVNAME(sc), x);
  159                         continue;
  160                 }
  161                 ref = res0.v_package[x]->v_objref.ref;
  162                 if (ref->type != AML_OBJTYPE_PROCESSOR)
  163                         printf("%s: _PSL[%d] not a CPU\n", DEVNAME(sc), x);
  164         }
  165  out:
  166         aml_freevalue(&res0);
  167         return (0);
  168 }
  169 
  170 int
  171 acpitz_setfan(struct acpitz_softc *sc, int i, char *method)
  172 {
  173         struct aml_value        res0, res1, res2, *ref;
  174         char                    name[8];
  175         int                     rv = 1, x, y;
  176 
  177         dnprintf(20, "%s: acpitz_setfan(%d, %s)\n", DEVNAME(sc), i, method);
  178 
  179         snprintf(name, sizeof name, "_AL%d", i);
  180         if (aml_evalname(sc->sc_acpi, sc->sc_devnode, name, 0, NULL, &res0)) {
  181                 dnprintf(20, "%s: %s failed\n", DEVNAME(sc), name);
  182                 goto out;
  183         }
  184 
  185         if (res0.type != AML_OBJTYPE_PACKAGE) {
  186                 printf("%s: %s not a package\n", DEVNAME(sc), name);
  187                 goto out;
  188         }
  189 
  190         for (x = 0; x < res0.length; x++) {
  191                 if (res0.v_package[x]->type != AML_OBJTYPE_OBJREF) {
  192                         printf("%s: %s[%d] not a object ref\n", DEVNAME(sc),
  193                             name, x);
  194                         continue;
  195                 }
  196                 ref = res0.v_package[x]->v_objref.ref;
  197                 if (aml_evalname(sc->sc_acpi, ref->node, "_PR0",0 , NULL,
  198                     &res1)) {
  199                         printf("%s: %s[%d] _PR0 failed\n", DEVNAME(sc),
  200                             name, x);
  201                         aml_freevalue(&res1);
  202                         continue;
  203                 }
  204                 if (res1.type != AML_OBJTYPE_PACKAGE) {
  205                         printf("%s: %s[%d] _PR0 not a package\n", DEVNAME(sc),
  206                             name, x);
  207                         aml_freevalue(&res1);
  208                         continue;
  209                 }
  210                 for (y = 0; y < res1.length; y++) {
  211                         if (res1.v_package[y]->type != AML_OBJTYPE_OBJREF) {
  212                                 printf("%s: %s[%d.%d] _PR0 not a package\n",
  213                                     DEVNAME(sc), name, x, y);
  214                                 continue;
  215                         }
  216                         ref = res1.v_package[y]->v_objref.ref;
  217                         if (aml_evalname(sc->sc_acpi, ref->node, method, 0,
  218                             NULL, NULL))
  219                                 printf("%s: %s[%d.%d] %s fails\n",
  220                                     DEVNAME(sc), name, x, y, method);
  221 
  222                         /* save off status of fan */
  223                         if (aml_evalname(sc->sc_acpi, ref->node, "_STA", 0,
  224                             NULL, &res2))
  225                                 printf("%s: %s[%d.%d] _STA fails\n",
  226                                     DEVNAME(sc), name, x, y);
  227                         else {
  228                                 sc->sc_ac_stat[i] = aml_val2int(&res2);
  229                                 aml_freevalue(&res2);
  230                         }
  231                 }
  232                 aml_freevalue(&res1);
  233         }
  234         rv = 0;
  235 out:
  236         aml_freevalue(&res0);
  237         return (rv);
  238 }
  239 
  240 void
  241 acpitz_refresh(void *arg)
  242 {
  243         struct acpitz_softc     *sc = arg;
  244         int                     i, trend;
  245         extern int              acpi_s5;
  246 
  247         dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc),
  248             sc->sc_devnode->parent->name);
  249 
  250         if (-1 == (sc->sc_tmp = acpitz_getreading(sc, "_TMP"))) {
  251                 dnprintf(30, "%s: %s: failed to read temp!\n", DEVNAME(sc),
  252                     sc->sc_devnode->parent->name);
  253                 sc->sc_tmp = 0; /* XXX */
  254         }
  255 
  256         if (sc->sc_crt != -1 && sc->sc_crt <= sc->sc_tmp) {
  257                 /* Do critical shutdown */
  258                 printf("%s: Critical temperature, shutting down!\n",
  259                     DEVNAME(sc));
  260                 acpi_s5 = 1;
  261                 psignal(initproc, SIGUSR1);
  262         }
  263         if (sc->sc_hot != -1 && sc->sc_hot <= sc->sc_tmp)
  264                 printf("%s: _HOT temperature\n", DEVNAME(sc));
  265 
  266         if (sc->sc_lasttmp != -1 && sc->sc_tc1 != -1 && sc->sc_tc2 != -1 &&
  267             sc->sc_psv != -1) {
  268                 if (sc->sc_psv <= sc->sc_tmp) {
  269                         sc->sc_pse = 1;
  270                         trend = sc->sc_tc1 * (sc->sc_tmp - sc->sc_lasttmp) +
  271                             sc->sc_tc2 * (sc->sc_tmp - sc->sc_psv);
  272                         /* printf("_TZ trend = %d\n", trend); */
  273                 } else if (sc->sc_pse)
  274                         sc->sc_pse = 0;
  275         }
  276         sc->sc_lasttmp = sc->sc_tmp;
  277 
  278         for (i = 0; i < ACPITZ_MAX_AC; i++) {
  279                 if (sc->sc_ac[i] != -1 && sc->sc_ac[i] <= sc->sc_tmp) {
  280                         /* turn on fan i */
  281                         if (sc->sc_ac_stat[i] <= 0)
  282                                 acpitz_setfan(sc, i, "_ON_");
  283                 } else if (sc->sc_ac[i] != -1) {
  284                         /* turn off fan i */
  285                         if (sc->sc_ac_stat[i] > 0)
  286                                 acpitz_setfan(sc, i, "_OFF");
  287                 }
  288         }
  289         sc->sc_sens.value = sc->sc_tmp * 100000;
  290 }
  291 
  292 int
  293 acpitz_getreading(struct acpitz_softc *sc, char *name)
  294 {
  295         struct aml_value        res;
  296         int                     rv = -1;
  297 
  298         if (aml_evalname(sc->sc_acpi, sc->sc_devnode, name, 0, NULL, &res)) {
  299                 dnprintf(10, "%s: no %s\n", DEVNAME(sc), name);
  300                 goto out;
  301         }
  302         rv = aml_val2int(&res);
  303  out:
  304         aml_freevalue(&res);
  305         return (rv);
  306 }
  307 
  308 int
  309 acpitz_notify(struct aml_node *node, int notify_type, void *arg)
  310 {
  311         struct acpitz_softc     *sc = arg;
  312         u_int64_t crt;
  313 
  314         dnprintf(10, "%s notify: %.2x %s\n", DEVNAME(sc), notify_type,
  315             sc->sc_devnode->parent->name);
  316 
  317         switch (notify_type) {
  318         case 0x81:      /* Operating Points changed */
  319                 sc->sc_psv = acpitz_getreading(sc, "_PSV");
  320                 crt = sc->sc_crt;
  321                 sc->sc_crt = acpitz_getreading(sc, "_CRT");
  322                 if (crt != sc->sc_crt)
  323                         printf("%s: critical temperature: %u degC",
  324                             DEVNAME(sc), (sc->sc_crt - 2732) / 10);
  325                 break;
  326         default:
  327                 break;
  328         }
  329         acpitz_refresh(sc);
  330         return (0);
  331 }

/* [<][>][^][v][top][bottom][index][help] */