15db2f26eSSascha Wildner /* $OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $ */
25db2f26eSSascha Wildner
35db2f26eSSascha Wildner /*
45db2f26eSSascha Wildner * Copyright (c) 2009 Constantine A. Murenin <cnst+dfly@bugmail.mojo.ru>
55db2f26eSSascha Wildner *
65db2f26eSSascha Wildner * Permission to use, copy, modify, and distribute this software for any
75db2f26eSSascha Wildner * purpose with or without fee is hereby granted, provided that the above
85db2f26eSSascha Wildner * copyright notice and this permission notice appear in all copies.
95db2f26eSSascha Wildner *
105db2f26eSSascha Wildner * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
115db2f26eSSascha Wildner * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
125db2f26eSSascha Wildner * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
135db2f26eSSascha Wildner * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
145db2f26eSSascha Wildner * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
155db2f26eSSascha Wildner * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
165db2f26eSSascha Wildner * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
175db2f26eSSascha Wildner */
185db2f26eSSascha Wildner
195db2f26eSSascha Wildner #include <machine/inttypes.h>
205db2f26eSSascha Wildner
215db2f26eSSascha Wildner #include <sys/param.h>
225db2f26eSSascha Wildner #include <sys/systm.h>
235db2f26eSSascha Wildner #include <sys/kernel.h>
245db2f26eSSascha Wildner #include <sys/bus.h>
255db2f26eSSascha Wildner #include <sys/module.h>
265db2f26eSSascha Wildner #include <sys/malloc.h>
275db2f26eSSascha Wildner
285db2f26eSSascha Wildner #include <sys/sensors.h>
295db2f26eSSascha Wildner
305db2f26eSSascha Wildner #include "acpi.h"
315db2f26eSSascha Wildner #include "acpivar.h"
325db2f26eSSascha Wildner
335db2f26eSSascha Wildner /*
345db2f26eSSascha Wildner * ASUSTeK AI Booster (ACPI ATK0110).
355db2f26eSSascha Wildner *
365db2f26eSSascha Wildner * This code was originally written for OpenBSD after the techniques
375db2f26eSSascha Wildner * described in the Linux's asus_atk0110.c and FreeBSD's acpi_aiboost.c
385db2f26eSSascha Wildner * were verified to be accurate on the actual hardware kindly provided by
395db2f26eSSascha Wildner * Sam Fourman Jr. It was subsequently ported from OpenBSD to DragonFly BSD.
405db2f26eSSascha Wildner *
415db2f26eSSascha Wildner * -- Constantine A. Murenin <http://cnst.su/>
425db2f26eSSascha Wildner */
435db2f26eSSascha Wildner
445db2f26eSSascha Wildner #define AIBS_MORE_SENSORS
455db2f26eSSascha Wildner #define AIBS_VERBOSE
465db2f26eSSascha Wildner
475db2f26eSSascha Wildner struct aibs_sensor {
485db2f26eSSascha Wildner struct ksensor s;
49417dc5a4SSascha Wildner UINT64 i;
50417dc5a4SSascha Wildner UINT64 l;
51417dc5a4SSascha Wildner UINT64 h;
525db2f26eSSascha Wildner };
535db2f26eSSascha Wildner
545db2f26eSSascha Wildner struct aibs_softc {
55*5d302545SFrançois Tigeot device_t sc_dev;
565db2f26eSSascha Wildner ACPI_HANDLE sc_ah;
575db2f26eSSascha Wildner
585db2f26eSSascha Wildner struct aibs_sensor *sc_asens_volt;
595db2f26eSSascha Wildner struct aibs_sensor *sc_asens_temp;
605db2f26eSSascha Wildner struct aibs_sensor *sc_asens_fan;
615db2f26eSSascha Wildner
625db2f26eSSascha Wildner struct ksensordev sc_sensordev;
635db2f26eSSascha Wildner };
645db2f26eSSascha Wildner
655db2f26eSSascha Wildner
66*5d302545SFrançois Tigeot static int aibs_probe(device_t);
67*5d302545SFrançois Tigeot static int aibs_attach(device_t);
68*5d302545SFrançois Tigeot static int aibs_detach(device_t);
695db2f26eSSascha Wildner static void aibs_refresh(void *);
705db2f26eSSascha Wildner
715db2f26eSSascha Wildner static void aibs_attach_sif(struct aibs_softc *, enum sensor_type);
725db2f26eSSascha Wildner static void aibs_refresh_r(struct aibs_softc *, enum sensor_type);
735db2f26eSSascha Wildner
745db2f26eSSascha Wildner
755db2f26eSSascha Wildner static device_method_t aibs_methods[] = {
765db2f26eSSascha Wildner DEVMETHOD(device_probe, aibs_probe),
775db2f26eSSascha Wildner DEVMETHOD(device_attach, aibs_attach),
785db2f26eSSascha Wildner DEVMETHOD(device_detach, aibs_detach),
795db2f26eSSascha Wildner { NULL, NULL }
805db2f26eSSascha Wildner };
815db2f26eSSascha Wildner
825db2f26eSSascha Wildner static driver_t aibs_driver = {
835db2f26eSSascha Wildner "aibs",
845db2f26eSSascha Wildner aibs_methods,
855db2f26eSSascha Wildner sizeof(struct aibs_softc)
865db2f26eSSascha Wildner };
875db2f26eSSascha Wildner
885db2f26eSSascha Wildner static devclass_t aibs_devclass;
895db2f26eSSascha Wildner
905db2f26eSSascha Wildner DRIVER_MODULE(aibs, acpi, aibs_driver, aibs_devclass, NULL, NULL);
915db2f26eSSascha Wildner MODULE_DEPEND(aibs, acpi, 1, 1, 1);
925db2f26eSSascha Wildner
935db2f26eSSascha Wildner static char* aibs_hids[] = {
945db2f26eSSascha Wildner "ATK0110",
955db2f26eSSascha Wildner NULL
965db2f26eSSascha Wildner };
975db2f26eSSascha Wildner
985db2f26eSSascha Wildner static int
aibs_probe(device_t dev)99*5d302545SFrançois Tigeot aibs_probe(device_t dev)
1005db2f26eSSascha Wildner {
1015db2f26eSSascha Wildner
1025db2f26eSSascha Wildner if (acpi_disabled("aibs") ||
1035db2f26eSSascha Wildner ACPI_ID_PROBE(device_get_parent(dev), dev, aibs_hids) == NULL)
1045db2f26eSSascha Wildner return ENXIO;
1055db2f26eSSascha Wildner
1065db2f26eSSascha Wildner device_set_desc(dev, "ASUSTeK AI Booster (ACPI ASOC ATK0110)");
1075db2f26eSSascha Wildner return 0;
1085db2f26eSSascha Wildner }
1095db2f26eSSascha Wildner
1105db2f26eSSascha Wildner static int
aibs_attach(device_t dev)111*5d302545SFrançois Tigeot aibs_attach(device_t dev)
1125db2f26eSSascha Wildner {
1135db2f26eSSascha Wildner struct aibs_softc *sc;
1145db2f26eSSascha Wildner
1155db2f26eSSascha Wildner sc = device_get_softc(dev);
1165db2f26eSSascha Wildner sc->sc_dev = dev;
1175db2f26eSSascha Wildner sc->sc_ah = acpi_get_handle(dev);
1185db2f26eSSascha Wildner
1195db2f26eSSascha Wildner strlcpy(sc->sc_sensordev.xname, device_get_nameunit(dev),
1205db2f26eSSascha Wildner sizeof(sc->sc_sensordev.xname));
1215db2f26eSSascha Wildner
1225db2f26eSSascha Wildner aibs_attach_sif(sc, SENSOR_VOLTS_DC);
1235db2f26eSSascha Wildner aibs_attach_sif(sc, SENSOR_TEMP);
1245db2f26eSSascha Wildner aibs_attach_sif(sc, SENSOR_FANRPM);
1255db2f26eSSascha Wildner
1265db2f26eSSascha Wildner if (sc->sc_sensordev.sensors_count == 0) {
1275db2f26eSSascha Wildner device_printf(dev, "no sensors found\n");
1285db2f26eSSascha Wildner return ENXIO;
1295db2f26eSSascha Wildner }
1305db2f26eSSascha Wildner
1311bedd63aSSepherosa Ziehau sensor_task_register(sc, aibs_refresh, 5);
1325db2f26eSSascha Wildner
1335db2f26eSSascha Wildner sensordev_install(&sc->sc_sensordev);
1345db2f26eSSascha Wildner return 0;
1355db2f26eSSascha Wildner }
1365db2f26eSSascha Wildner
1375db2f26eSSascha Wildner static void
aibs_attach_sif(struct aibs_softc * sc,enum sensor_type st)1385db2f26eSSascha Wildner aibs_attach_sif(struct aibs_softc *sc, enum sensor_type st)
1395db2f26eSSascha Wildner {
1405db2f26eSSascha Wildner ACPI_STATUS s;
1415db2f26eSSascha Wildner ACPI_BUFFER b;
1425db2f26eSSascha Wildner ACPI_OBJECT *bp, *o;
1435db2f26eSSascha Wildner int i, n;
1445db2f26eSSascha Wildner char name[] = "?SIF";
1455db2f26eSSascha Wildner struct aibs_sensor *as;
1465db2f26eSSascha Wildner
1475db2f26eSSascha Wildner switch (st) {
1485db2f26eSSascha Wildner case SENSOR_TEMP:
1495db2f26eSSascha Wildner name[0] = 'T';
1505db2f26eSSascha Wildner break;
1515db2f26eSSascha Wildner case SENSOR_FANRPM:
1525db2f26eSSascha Wildner name[0] = 'F';
1535db2f26eSSascha Wildner break;
1545db2f26eSSascha Wildner case SENSOR_VOLTS_DC:
1555db2f26eSSascha Wildner name[0] = 'V';
1565db2f26eSSascha Wildner break;
1575db2f26eSSascha Wildner default:
1585db2f26eSSascha Wildner return;
1595db2f26eSSascha Wildner }
1605db2f26eSSascha Wildner
1615db2f26eSSascha Wildner b.Length = ACPI_ALLOCATE_BUFFER;
1625db2f26eSSascha Wildner s = AcpiEvaluateObjectTyped(sc->sc_ah, name, NULL, &b,
1635db2f26eSSascha Wildner ACPI_TYPE_PACKAGE);
1645db2f26eSSascha Wildner if (ACPI_FAILURE(s)) {
1655db2f26eSSascha Wildner device_printf(sc->sc_dev, "%s not found\n", name);
1665db2f26eSSascha Wildner return;
1675db2f26eSSascha Wildner }
1685db2f26eSSascha Wildner
1695db2f26eSSascha Wildner bp = b.Pointer;
1705db2f26eSSascha Wildner o = bp->Package.Elements;
1715db2f26eSSascha Wildner if (o[0].Type != ACPI_TYPE_INTEGER) {
1725db2f26eSSascha Wildner device_printf(sc->sc_dev, "%s[0]: invalid type\n", name);
1735db2f26eSSascha Wildner AcpiOsFree(b.Pointer);
1745db2f26eSSascha Wildner return;
1755db2f26eSSascha Wildner }
1765db2f26eSSascha Wildner
1775db2f26eSSascha Wildner n = o[0].Integer.Value;
1785db2f26eSSascha Wildner if (bp->Package.Count - 1 < n) {
1795db2f26eSSascha Wildner device_printf(sc->sc_dev, "%s: invalid package\n", name);
1805db2f26eSSascha Wildner AcpiOsFree(b.Pointer);
1815db2f26eSSascha Wildner return;
1825db2f26eSSascha Wildner } else if (bp->Package.Count - 1 > n) {
1835db2f26eSSascha Wildner int on = n;
1845db2f26eSSascha Wildner
1855db2f26eSSascha Wildner #ifdef AIBS_MORE_SENSORS
1865db2f26eSSascha Wildner n = bp->Package.Count - 1;
1875db2f26eSSascha Wildner #endif
1885db2f26eSSascha Wildner device_printf(sc->sc_dev, "%s: malformed package: %i/%i"
1895db2f26eSSascha Wildner ", assume %i\n", name, on, bp->Package.Count - 1, n);
1905db2f26eSSascha Wildner }
1915db2f26eSSascha Wildner if (n < 1) {
1925db2f26eSSascha Wildner device_printf(sc->sc_dev, "%s: no members in the package\n",
1935db2f26eSSascha Wildner name);
1945db2f26eSSascha Wildner AcpiOsFree(b.Pointer);
1955db2f26eSSascha Wildner return;
1965db2f26eSSascha Wildner }
1975db2f26eSSascha Wildner
1985db2f26eSSascha Wildner as = kmalloc(sizeof(*as) * n, M_DEVBUF, M_NOWAIT | M_ZERO);
1995db2f26eSSascha Wildner if (as == NULL) {
2005db2f26eSSascha Wildner device_printf(sc->sc_dev, "%s: malloc fail\n", name);
2015db2f26eSSascha Wildner AcpiOsFree(b.Pointer);
2025db2f26eSSascha Wildner return;
2035db2f26eSSascha Wildner }
2045db2f26eSSascha Wildner
2055db2f26eSSascha Wildner switch (st) {
2065db2f26eSSascha Wildner case SENSOR_TEMP:
2075db2f26eSSascha Wildner sc->sc_asens_temp = as;
2085db2f26eSSascha Wildner break;
2095db2f26eSSascha Wildner case SENSOR_FANRPM:
2105db2f26eSSascha Wildner sc->sc_asens_fan = as;
2115db2f26eSSascha Wildner break;
2125db2f26eSSascha Wildner case SENSOR_VOLTS_DC:
2135db2f26eSSascha Wildner sc->sc_asens_volt = as;
2145db2f26eSSascha Wildner break;
2155db2f26eSSascha Wildner default:
2165db2f26eSSascha Wildner /* NOTREACHED */
2175db2f26eSSascha Wildner return;
2185db2f26eSSascha Wildner }
2195db2f26eSSascha Wildner
2205db2f26eSSascha Wildner for (i = 0, o++; i < n; i++, o++) {
2215db2f26eSSascha Wildner ACPI_OBJECT *oi;
2225db2f26eSSascha Wildner
2235db2f26eSSascha Wildner /* acpica automatically evaluates the referenced package */
2245db2f26eSSascha Wildner if (o[0].Type != ACPI_TYPE_PACKAGE) {
2255db2f26eSSascha Wildner device_printf(sc->sc_dev,
2265db2f26eSSascha Wildner "%s: %i: not a package: %i type\n",
2275db2f26eSSascha Wildner name, i, o[0].Type);
2285db2f26eSSascha Wildner continue;
2295db2f26eSSascha Wildner }
2305db2f26eSSascha Wildner oi = o[0].Package.Elements;
2315db2f26eSSascha Wildner if (o[0].Package.Count != 5 ||
2325db2f26eSSascha Wildner oi[0].Type != ACPI_TYPE_INTEGER ||
2335db2f26eSSascha Wildner oi[1].Type != ACPI_TYPE_STRING ||
2345db2f26eSSascha Wildner oi[2].Type != ACPI_TYPE_INTEGER ||
2355db2f26eSSascha Wildner oi[3].Type != ACPI_TYPE_INTEGER ||
2365db2f26eSSascha Wildner oi[4].Type != ACPI_TYPE_INTEGER) {
2375db2f26eSSascha Wildner device_printf(sc->sc_dev,
2385db2f26eSSascha Wildner "%s: %i: invalid package\n",
2395db2f26eSSascha Wildner name, i);
2405db2f26eSSascha Wildner continue;
2415db2f26eSSascha Wildner }
2425db2f26eSSascha Wildner as[i].i = oi[0].Integer.Value;
2435db2f26eSSascha Wildner strlcpy(as[i].s.desc, oi[1].String.Pointer,
2445db2f26eSSascha Wildner sizeof(as[i].s.desc));
2455db2f26eSSascha Wildner as[i].l = oi[2].Integer.Value;
2465db2f26eSSascha Wildner as[i].h = oi[3].Integer.Value;
2475db2f26eSSascha Wildner as[i].s.type = st;
2485db2f26eSSascha Wildner #ifdef AIBS_VERBOSE
2495db2f26eSSascha Wildner device_printf(sc->sc_dev, "%c%i: "
2505db2f26eSSascha Wildner "0x%08"PRIx64" %20s %5"PRIi64" / %5"PRIi64" "
2515db2f26eSSascha Wildner "0x%"PRIx64"\n",
2525db2f26eSSascha Wildner name[0], i,
2535db2f26eSSascha Wildner as[i].i, as[i].s.desc, (int64_t)as[i].l, (int64_t)as[i].h,
2545db2f26eSSascha Wildner oi[4].Integer.Value);
2555db2f26eSSascha Wildner #endif
2565db2f26eSSascha Wildner sensor_attach(&sc->sc_sensordev, &as[i].s);
2575db2f26eSSascha Wildner }
2585db2f26eSSascha Wildner
2595db2f26eSSascha Wildner AcpiOsFree(b.Pointer);
2605db2f26eSSascha Wildner return;
2615db2f26eSSascha Wildner }
2625db2f26eSSascha Wildner
2635db2f26eSSascha Wildner static int
aibs_detach(device_t dev)264*5d302545SFrançois Tigeot aibs_detach(device_t dev)
2655db2f26eSSascha Wildner {
2665db2f26eSSascha Wildner struct aibs_softc *sc = device_get_softc(dev);
2675db2f26eSSascha Wildner
2685db2f26eSSascha Wildner sensordev_deinstall(&sc->sc_sensordev);
2695db2f26eSSascha Wildner sensor_task_unregister(sc);
2705db2f26eSSascha Wildner if (sc->sc_asens_volt != NULL)
2715db2f26eSSascha Wildner kfree(sc->sc_asens_volt, M_DEVBUF);
2725db2f26eSSascha Wildner if (sc->sc_asens_temp != NULL)
2735db2f26eSSascha Wildner kfree(sc->sc_asens_temp, M_DEVBUF);
2745db2f26eSSascha Wildner if (sc->sc_asens_fan != NULL)
2755db2f26eSSascha Wildner kfree(sc->sc_asens_fan, M_DEVBUF);
2765db2f26eSSascha Wildner return 0;
2775db2f26eSSascha Wildner }
2785db2f26eSSascha Wildner
2795db2f26eSSascha Wildner #ifdef AIBS_VERBOSE
2805db2f26eSSascha Wildner #define ddevice_printf(x...) device_printf(x)
2815db2f26eSSascha Wildner #else
2825db2f26eSSascha Wildner #define ddevice_printf(x...)
2835db2f26eSSascha Wildner #endif
2845db2f26eSSascha Wildner
2855db2f26eSSascha Wildner static void
aibs_refresh(void * arg)2865db2f26eSSascha Wildner aibs_refresh(void *arg)
2875db2f26eSSascha Wildner {
2885db2f26eSSascha Wildner struct aibs_softc *sc = arg;
2895db2f26eSSascha Wildner
2905db2f26eSSascha Wildner aibs_refresh_r(sc, SENSOR_VOLTS_DC);
2915db2f26eSSascha Wildner aibs_refresh_r(sc, SENSOR_TEMP);
2925db2f26eSSascha Wildner aibs_refresh_r(sc, SENSOR_FANRPM);
2935db2f26eSSascha Wildner }
2945db2f26eSSascha Wildner
2955db2f26eSSascha Wildner static void
aibs_refresh_r(struct aibs_softc * sc,enum sensor_type st)2965db2f26eSSascha Wildner aibs_refresh_r(struct aibs_softc *sc, enum sensor_type st)
2975db2f26eSSascha Wildner {
2985db2f26eSSascha Wildner ACPI_STATUS rs;
2995db2f26eSSascha Wildner ACPI_HANDLE rh;
3005db2f26eSSascha Wildner int i, n = sc->sc_sensordev.maxnumt[st];
3015db2f26eSSascha Wildner char *name;
3025db2f26eSSascha Wildner struct aibs_sensor *as;
3035db2f26eSSascha Wildner
3045db2f26eSSascha Wildner switch (st) {
3055db2f26eSSascha Wildner case SENSOR_TEMP:
3065db2f26eSSascha Wildner name = "RTMP";
3075db2f26eSSascha Wildner as = sc->sc_asens_temp;
3085db2f26eSSascha Wildner break;
3095db2f26eSSascha Wildner case SENSOR_FANRPM:
3105db2f26eSSascha Wildner name = "RFAN";
3115db2f26eSSascha Wildner as = sc->sc_asens_fan;
3125db2f26eSSascha Wildner break;
3135db2f26eSSascha Wildner case SENSOR_VOLTS_DC:
3145db2f26eSSascha Wildner name = "RVLT";
3155db2f26eSSascha Wildner as = sc->sc_asens_volt;
3165db2f26eSSascha Wildner break;
3175db2f26eSSascha Wildner default:
3185db2f26eSSascha Wildner return;
3195db2f26eSSascha Wildner }
3205db2f26eSSascha Wildner
3215db2f26eSSascha Wildner if (as == NULL)
3225db2f26eSSascha Wildner return;
3235db2f26eSSascha Wildner
3245db2f26eSSascha Wildner rs = AcpiGetHandle(sc->sc_ah, name, &rh);
3255db2f26eSSascha Wildner if (ACPI_FAILURE(rs)) {
3265db2f26eSSascha Wildner ddevice_printf(sc->sc_dev, "%s: method handle not found\n",
3275db2f26eSSascha Wildner name);
3285db2f26eSSascha Wildner for (i = 0; i < n; i++)
3295db2f26eSSascha Wildner as[i].s.flags |= SENSOR_FINVALID;
3305db2f26eSSascha Wildner return;
3315db2f26eSSascha Wildner }
3325db2f26eSSascha Wildner
3335db2f26eSSascha Wildner for (i = 0; i < n; i++) {
3345db2f26eSSascha Wildner ACPI_OBJECT p, *bp;
3355db2f26eSSascha Wildner ACPI_OBJECT_LIST mp;
3365db2f26eSSascha Wildner ACPI_BUFFER b;
337417dc5a4SSascha Wildner UINT64 v;
3385db2f26eSSascha Wildner struct ksensor *s = &as[i].s;
339417dc5a4SSascha Wildner const UINT64 l = as[i].l, h = as[i].h;
3405db2f26eSSascha Wildner
3415db2f26eSSascha Wildner p.Type = ACPI_TYPE_INTEGER;
3425db2f26eSSascha Wildner p.Integer.Value = as[i].i;
3435db2f26eSSascha Wildner mp.Count = 1;
3445db2f26eSSascha Wildner mp.Pointer = &p;
3455db2f26eSSascha Wildner b.Length = ACPI_ALLOCATE_BUFFER;
3465db2f26eSSascha Wildner rs = AcpiEvaluateObjectTyped(rh, NULL, &mp, &b,
3475db2f26eSSascha Wildner ACPI_TYPE_INTEGER);
3485db2f26eSSascha Wildner if (ACPI_FAILURE(rs)) {
3495db2f26eSSascha Wildner ddevice_printf(sc->sc_dev,
3505db2f26eSSascha Wildner "%s: %i: evaluation failed\n",
3515db2f26eSSascha Wildner name, i);
3525db2f26eSSascha Wildner s->flags |= SENSOR_FINVALID;
3535db2f26eSSascha Wildner continue;
3545db2f26eSSascha Wildner }
3555db2f26eSSascha Wildner bp = b.Pointer;
3565db2f26eSSascha Wildner v = bp->Integer.Value;
3575db2f26eSSascha Wildner AcpiOsFree(b.Pointer);
3585db2f26eSSascha Wildner
3595db2f26eSSascha Wildner switch (st) {
3605db2f26eSSascha Wildner case SENSOR_TEMP:
3615db2f26eSSascha Wildner s->value = v * 100 * 1000 + 273150000;
3625db2f26eSSascha Wildner if (v == 0) {
3635db2f26eSSascha Wildner s->status = SENSOR_S_UNKNOWN;
3645db2f26eSSascha Wildner s->flags |= SENSOR_FINVALID;
3655db2f26eSSascha Wildner } else {
3665db2f26eSSascha Wildner if (v > h)
3675db2f26eSSascha Wildner s->status = SENSOR_S_CRIT;
3685db2f26eSSascha Wildner else if (v > l)
3695db2f26eSSascha Wildner s->status = SENSOR_S_WARN;
3705db2f26eSSascha Wildner else
3715db2f26eSSascha Wildner s->status = SENSOR_S_OK;
3725db2f26eSSascha Wildner s->flags &= ~SENSOR_FINVALID;
3735db2f26eSSascha Wildner }
3745db2f26eSSascha Wildner break;
3755db2f26eSSascha Wildner case SENSOR_FANRPM:
3765db2f26eSSascha Wildner s->value = v;
3775db2f26eSSascha Wildner /* some boards have strange limits for fans */
3785db2f26eSSascha Wildner if ((l != 0 && l < v && v < h) ||
3795db2f26eSSascha Wildner (l == 0 && v > h))
3805db2f26eSSascha Wildner s->status = SENSOR_S_OK;
3815db2f26eSSascha Wildner else
3825db2f26eSSascha Wildner s->status = SENSOR_S_WARN;
3835db2f26eSSascha Wildner s->flags &= ~SENSOR_FINVALID;
3845db2f26eSSascha Wildner break;
3855db2f26eSSascha Wildner case SENSOR_VOLTS_DC:
3865db2f26eSSascha Wildner s->value = v * 1000;
3875db2f26eSSascha Wildner if (l < v && v < h)
3885db2f26eSSascha Wildner s->status = SENSOR_S_OK;
3895db2f26eSSascha Wildner else
3905db2f26eSSascha Wildner s->status = SENSOR_S_WARN;
3915db2f26eSSascha Wildner s->flags &= ~SENSOR_FINVALID;
3925db2f26eSSascha Wildner break;
3935db2f26eSSascha Wildner default:
3945db2f26eSSascha Wildner /* NOTREACHED */
3955db2f26eSSascha Wildner break;
3965db2f26eSSascha Wildner }
3975db2f26eSSascha Wildner }
3985db2f26eSSascha Wildner
3995db2f26eSSascha Wildner return;
4005db2f26eSSascha Wildner }
401