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/aibs/atk0110.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 /*      $OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $        */
    2 
    3 /*
    4  * Copyright (c) 2009 Constantine A. Murenin <cnst+dfly@bugmail.mojo.ru>
    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 <machine/inttypes.h>
   20 
   21 #include <sys/param.h>
   22 #include <sys/systm.h>
   23 #include <sys/kernel.h>
   24 #include <sys/bus.h>
   25 #include <sys/module.h>
   26 #include <sys/malloc.h>
   27 
   28 #include <sys/sensors.h>
   29 
   30 #include "acpi.h"
   31 #include "acpivar.h"
   32 
   33 /*
   34  * ASUSTeK AI Booster (ACPI ATK0110).
   35  *
   36  * This code was originally written for OpenBSD after the techniques
   37  * described in the Linux's asus_atk0110.c and FreeBSD's acpi_aiboost.c
   38  * were verified to be accurate on the actual hardware kindly provided by
   39  * Sam Fourman Jr.  It was subsequently ported from OpenBSD to DragonFly BSD.
   40  *
   41  *                                -- Constantine A. Murenin <http://cnst.su/>
   42  */
   43 
   44 #define AIBS_MORE_SENSORS
   45 #define AIBS_VERBOSE
   46 
   47 struct aibs_sensor {
   48         struct ksensor  s;
   49         ACPI_INTEGER    i;
   50         ACPI_INTEGER    l;
   51         ACPI_INTEGER    h;
   52 };
   53 
   54 struct aibs_softc {
   55         struct device           *sc_dev;
   56         ACPI_HANDLE             sc_ah;
   57 
   58         struct aibs_sensor      *sc_asens_volt;
   59         struct aibs_sensor      *sc_asens_temp;
   60         struct aibs_sensor      *sc_asens_fan;
   61 
   62         struct ksensordev       sc_sensordev;
   63 };
   64 
   65 
   66 static int aibs_probe(struct device *);
   67 static int aibs_attach(struct device *);
   68 static int aibs_detach(struct device *);
   69 static void aibs_refresh(void *);
   70 
   71 static void aibs_attach_sif(struct aibs_softc *, enum sensor_type);
   72 static void aibs_refresh_r(struct aibs_softc *, enum sensor_type);
   73 
   74 
   75 static device_method_t aibs_methods[] = {
   76         DEVMETHOD(device_probe,         aibs_probe),
   77         DEVMETHOD(device_attach,        aibs_attach),
   78         DEVMETHOD(device_detach,        aibs_detach),
   79         { NULL, NULL }
   80 };
   81 
   82 static driver_t aibs_driver = {
   83         "aibs",
   84         aibs_methods,
   85         sizeof(struct aibs_softc)
   86 };
   87 
   88 static devclass_t aibs_devclass;
   89 
   90 DRIVER_MODULE(aibs, acpi, aibs_driver, aibs_devclass, NULL, NULL);
   91 MODULE_DEPEND(aibs, acpi, 1, 1, 1);
   92 
   93 static char* aibs_hids[] = {
   94         "ATK0110",
   95         NULL
   96 };
   97 
   98 static int
   99 aibs_probe(struct device *dev)
  100 {
  101 
  102         if (acpi_disabled("aibs") ||
  103             ACPI_ID_PROBE(device_get_parent(dev), dev, aibs_hids) == NULL)
  104                 return ENXIO;
  105 
  106         device_set_desc(dev, "ASUSTeK AI Booster (ACPI ASOC ATK0110)");
  107         return 0;
  108 }
  109 
  110 static int
  111 aibs_attach(struct device *dev)
  112 {
  113         struct aibs_softc       *sc;
  114 
  115         sc = device_get_softc(dev);
  116         sc->sc_dev = dev;
  117         sc->sc_ah = acpi_get_handle(dev);
  118 
  119         strlcpy(sc->sc_sensordev.xname, device_get_nameunit(dev),
  120             sizeof(sc->sc_sensordev.xname));
  121 
  122         aibs_attach_sif(sc, SENSOR_VOLTS_DC);
  123         aibs_attach_sif(sc, SENSOR_TEMP);
  124         aibs_attach_sif(sc, SENSOR_FANRPM);
  125 
  126         if (sc->sc_sensordev.sensors_count == 0) {
  127                 device_printf(dev, "no sensors found\n");
  128                 return ENXIO;
  129         }
  130 
  131         if (sensor_task_register(sc, aibs_refresh, 5)) {
  132                 device_printf(dev, "unable to register update task\n");
  133                 return ENXIO;
  134         }
  135 
  136         sensordev_install(&sc->sc_sensordev);
  137         return 0;
  138 }
  139 
  140 static void
  141 aibs_attach_sif(struct aibs_softc *sc, enum sensor_type st)
  142 {
  143         ACPI_STATUS             s;
  144         ACPI_BUFFER             b;
  145         ACPI_OBJECT             *bp, *o;
  146         int                     i, n;
  147         char                    name[] = "?SIF";
  148         struct aibs_sensor      *as;
  149 
  150         switch (st) {
  151         case SENSOR_TEMP:
  152                 name[0] = 'T';
  153                 break;
  154         case SENSOR_FANRPM:
  155                 name[0] = 'F';
  156                 break;
  157         case SENSOR_VOLTS_DC:
  158                 name[0] = 'V';
  159                 break;
  160         default:
  161                 return;
  162         }
  163 
  164         b.Length = ACPI_ALLOCATE_BUFFER;
  165         s = AcpiEvaluateObjectTyped(sc->sc_ah, name, NULL, &b,
  166             ACPI_TYPE_PACKAGE);
  167         if (ACPI_FAILURE(s)) {
  168                 device_printf(sc->sc_dev, "%s not found\n", name);
  169                 return;
  170         }
  171 
  172         bp = b.Pointer;
  173         o = bp->Package.Elements;
  174         if (o[0].Type != ACPI_TYPE_INTEGER) {
  175                 device_printf(sc->sc_dev, "%s[0]: invalid type\n", name);
  176                 AcpiOsFree(b.Pointer);
  177                 return;
  178         }
  179 
  180         n = o[0].Integer.Value;
  181         if (bp->Package.Count - 1 < n) {
  182                 device_printf(sc->sc_dev, "%s: invalid package\n", name);
  183                 AcpiOsFree(b.Pointer);
  184                 return;
  185         } else if (bp->Package.Count - 1 > n) {
  186                 int on = n;
  187 
  188 #ifdef AIBS_MORE_SENSORS
  189                 n = bp->Package.Count - 1;
  190 #endif
  191                 device_printf(sc->sc_dev, "%s: malformed package: %i/%i"
  192                     ", assume %i\n", name, on, bp->Package.Count - 1, n);
  193         }
  194         if (n < 1) {
  195                 device_printf(sc->sc_dev, "%s: no members in the package\n",
  196                     name);
  197                 AcpiOsFree(b.Pointer);
  198                 return;
  199         }
  200 
  201         as = kmalloc(sizeof(*as) * n, M_DEVBUF, M_NOWAIT | M_ZERO);
  202         if (as == NULL) {
  203                 device_printf(sc->sc_dev, "%s: malloc fail\n", name);
  204                 AcpiOsFree(b.Pointer);
  205                 return;
  206         }
  207 
  208         switch (st) {
  209         case SENSOR_TEMP:
  210                 sc->sc_asens_temp = as;
  211                 break;
  212         case SENSOR_FANRPM:
  213                 sc->sc_asens_fan = as;
  214                 break;
  215         case SENSOR_VOLTS_DC:
  216                 sc->sc_asens_volt = as;
  217                 break;
  218         default:
  219                 /* NOTREACHED */
  220                 return;
  221         }
  222 
  223         for (i = 0, o++; i < n; i++, o++) {
  224                 ACPI_OBJECT     *oi;
  225 
  226                 /* acpica automatically evaluates the referenced package */
  227                 if (o[0].Type != ACPI_TYPE_PACKAGE) {
  228                         device_printf(sc->sc_dev,
  229                             "%s: %i: not a package: %i type\n",
  230                             name, i, o[0].Type);
  231                         continue;
  232                 }
  233                 oi = o[0].Package.Elements;
  234                 if (o[0].Package.Count != 5 ||
  235                     oi[0].Type != ACPI_TYPE_INTEGER ||
  236                     oi[1].Type != ACPI_TYPE_STRING ||
  237                     oi[2].Type != ACPI_TYPE_INTEGER ||
  238                     oi[3].Type != ACPI_TYPE_INTEGER ||
  239                     oi[4].Type != ACPI_TYPE_INTEGER) {
  240                         device_printf(sc->sc_dev,
  241                             "%s: %i: invalid package\n",
  242                             name, i);
  243                         continue;
  244                 }
  245                 as[i].i = oi[0].Integer.Value;
  246                 strlcpy(as[i].s.desc, oi[1].String.Pointer,
  247                     sizeof(as[i].s.desc));
  248                 as[i].l = oi[2].Integer.Value;
  249                 as[i].h = oi[3].Integer.Value;
  250                 as[i].s.type = st;
  251 #ifdef AIBS_VERBOSE
  252                 device_printf(sc->sc_dev, "%c%i: "
  253                     "0x%08"PRIx64" %20s %5"PRIi64" / %5"PRIi64"  "
  254                     "0x%"PRIx64"\n",
  255                     name[0], i,
  256                     as[i].i, as[i].s.desc, (int64_t)as[i].l, (int64_t)as[i].h,
  257                     oi[4].Integer.Value);
  258 #endif
  259                 sensor_attach(&sc->sc_sensordev, &as[i].s);
  260         }
  261 
  262         AcpiOsFree(b.Pointer);
  263         return;
  264 }
  265 
  266 static int
  267 aibs_detach(struct device *dev)
  268 {
  269         struct aibs_softc       *sc = device_get_softc(dev);
  270 
  271         sensordev_deinstall(&sc->sc_sensordev);
  272         sensor_task_unregister(sc);
  273         if (sc->sc_asens_volt != NULL)
  274                 kfree(sc->sc_asens_volt, M_DEVBUF);
  275         if (sc->sc_asens_temp != NULL)
  276                 kfree(sc->sc_asens_temp, M_DEVBUF);
  277         if (sc->sc_asens_fan != NULL)
  278                 kfree(sc->sc_asens_fan, M_DEVBUF);
  279         return 0;
  280 }
  281 
  282 #ifdef AIBS_VERBOSE
  283 #define ddevice_printf(x...) device_printf(x)
  284 #else
  285 #define ddevice_printf(x...)
  286 #endif
  287 
  288 static void
  289 aibs_refresh(void *arg)
  290 {
  291         struct aibs_softc *sc = arg;
  292 
  293         aibs_refresh_r(sc, SENSOR_VOLTS_DC);
  294         aibs_refresh_r(sc, SENSOR_TEMP);
  295         aibs_refresh_r(sc, SENSOR_FANRPM);
  296 }
  297 
  298 static void
  299 aibs_refresh_r(struct aibs_softc *sc, enum sensor_type st)
  300 {
  301         ACPI_STATUS             rs;
  302         ACPI_HANDLE             rh;
  303         int                     i, n = sc->sc_sensordev.maxnumt[st];
  304         char                    *name;
  305         struct aibs_sensor      *as;
  306 
  307         switch (st) {
  308         case SENSOR_TEMP:
  309                 name = "RTMP";
  310                 as = sc->sc_asens_temp;
  311                 break;
  312         case SENSOR_FANRPM:
  313                 name = "RFAN";
  314                 as = sc->sc_asens_fan;
  315                 break;
  316         case SENSOR_VOLTS_DC:
  317                 name = "RVLT";
  318                 as = sc->sc_asens_volt;
  319                 break;
  320         default:
  321                 return;
  322         }
  323 
  324         if (as == NULL)
  325                 return;
  326 
  327         rs = AcpiGetHandle(sc->sc_ah, name, &rh);
  328         if (ACPI_FAILURE(rs)) {
  329                 ddevice_printf(sc->sc_dev, "%s: method handle not found\n",
  330                     name);
  331                 for (i = 0; i < n; i++)
  332                         as[i].s.flags |= SENSOR_FINVALID;
  333                 return;
  334         }
  335 
  336         for (i = 0; i < n; i++) {
  337                 ACPI_OBJECT             p, *bp;
  338                 ACPI_OBJECT_LIST        mp;
  339                 ACPI_BUFFER             b;
  340                 ACPI_INTEGER            v;
  341                 struct ksensor          *s = &as[i].s;
  342                 const ACPI_INTEGER      l = as[i].l, h = as[i].h;
  343 
  344                 p.Type = ACPI_TYPE_INTEGER;
  345                 p.Integer.Value = as[i].i;
  346                 mp.Count = 1;
  347                 mp.Pointer = &p;
  348                 b.Length = ACPI_ALLOCATE_BUFFER;
  349                 rs = AcpiEvaluateObjectTyped(rh, NULL, &mp, &b,
  350                     ACPI_TYPE_INTEGER);
  351                 if (ACPI_FAILURE(rs)) {
  352                         ddevice_printf(sc->sc_dev,
  353                             "%s: %i: evaluation failed\n",
  354                             name, i);
  355                         s->flags |= SENSOR_FINVALID;
  356                         continue;
  357                 }
  358                 bp = b.Pointer;
  359                 v = bp->Integer.Value;
  360                 AcpiOsFree(b.Pointer);
  361 
  362                 switch (st) {
  363                 case SENSOR_TEMP:
  364                         s->value = v * 100 * 1000 + 273150000;
  365                         if (v == 0) {
  366                                 s->status = SENSOR_S_UNKNOWN;
  367                                 s->flags |= SENSOR_FINVALID;
  368                         } else {
  369                                 if (v > h)
  370                                         s->status = SENSOR_S_CRIT;
  371                                 else if (v > l)
  372                                         s->status = SENSOR_S_WARN;
  373                                 else
  374                                         s->status = SENSOR_S_OK;
  375                                 s->flags &= ~SENSOR_FINVALID;
  376                         }
  377                         break;
  378                 case SENSOR_FANRPM:
  379                         s->value = v;
  380                         /* some boards have strange limits for fans */
  381                         if ((l != 0 && l < v && v < h) ||
  382                             (l == 0 && v > h))
  383                                 s->status = SENSOR_S_OK;
  384                         else
  385                                 s->status = SENSOR_S_WARN;
  386                         s->flags &= ~SENSOR_FINVALID;
  387                         break;
  388                 case SENSOR_VOLTS_DC:
  389                         s->value = v * 1000;
  390                         if (l < v && v < h)
  391                                 s->status = SENSOR_S_OK;
  392                         else
  393                                 s->status = SENSOR_S_WARN;
  394                         s->flags &= ~SENSOR_FINVALID;
  395                         break;
  396                 default:
  397                         /* NOTREACHED */
  398                         break;
  399                 }
  400         }
  401 
  402         return;
  403 }

Cache object: 760a663a40691fc153233473a2788d3a


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