1 /* $OpenBSD: atk0110.c,v 1.1 2009/07/23 01:38:16 cnst Exp $ */
4 * Copyright (c) 2009 Constantine A. Murenin <cnst+dfly@bugmail.mojo.ru>
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.
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.
19 #include <machine/inttypes.h>
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/kernel.h>
25 #include <sys/module.h>
26 #include <sys/malloc.h>
28 #include <sys/sensors.h>
34 * ASUSTeK AI Booster (ACPI ATK0110).
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.
41 * -- Constantine A. Murenin <http://cnst.su/>
44 #define AIBS_MORE_SENSORS
55 struct device *sc_dev;
58 struct aibs_sensor *sc_asens_volt;
59 struct aibs_sensor *sc_asens_temp;
60 struct aibs_sensor *sc_asens_fan;
62 struct ksensordev sc_sensordev;
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 *);
71 static void aibs_attach_sif(struct aibs_softc *, enum sensor_type);
72 static void aibs_refresh_r(struct aibs_softc *, enum sensor_type);
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),
82 static driver_t aibs_driver = {
85 sizeof(struct aibs_softc)
88 static devclass_t aibs_devclass;
90 DRIVER_MODULE(aibs, acpi, aibs_driver, aibs_devclass, NULL, NULL);
91 MODULE_DEPEND(aibs, acpi, 1, 1, 1);
93 static char* aibs_hids[] = {
99 aibs_probe(struct device *dev)
102 if (acpi_disabled("aibs") ||
103 ACPI_ID_PROBE(device_get_parent(dev), dev, aibs_hids) == NULL)
106 device_set_desc(dev, "ASUSTeK AI Booster (ACPI ASOC ATK0110)");
111 aibs_attach(struct device *dev)
113 struct aibs_softc *sc;
115 sc = device_get_softc(dev);
117 sc->sc_ah = acpi_get_handle(dev);
119 strlcpy(sc->sc_sensordev.xname, device_get_nameunit(dev),
120 sizeof(sc->sc_sensordev.xname));
122 aibs_attach_sif(sc, SENSOR_VOLTS_DC);
123 aibs_attach_sif(sc, SENSOR_TEMP);
124 aibs_attach_sif(sc, SENSOR_FANRPM);
126 if (sc->sc_sensordev.sensors_count == 0) {
127 device_printf(dev, "no sensors found\n");
131 if (sensor_task_register(sc, aibs_refresh, 5)) {
132 device_printf(dev, "unable to register update task\n");
136 sensordev_install(&sc->sc_sensordev);
141 aibs_attach_sif(struct aibs_softc *sc, enum sensor_type st)
147 char name[] = "?SIF";
148 struct aibs_sensor *as;
157 case SENSOR_VOLTS_DC:
164 b.Length = ACPI_ALLOCATE_BUFFER;
165 s = AcpiEvaluateObjectTyped(sc->sc_ah, name, NULL, &b,
167 if (ACPI_FAILURE(s)) {
168 device_printf(sc->sc_dev, "%s not found\n", name);
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);
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);
185 } else if (bp->Package.Count - 1 > n) {
188 #ifdef AIBS_MORE_SENSORS
189 n = bp->Package.Count - 1;
191 device_printf(sc->sc_dev, "%s: malformed package: %i/%i"
192 ", assume %i\n", name, on, bp->Package.Count - 1, n);
195 device_printf(sc->sc_dev, "%s: no members in the package\n",
197 AcpiOsFree(b.Pointer);
201 as = kmalloc(sizeof(*as) * n, M_DEVBUF, M_NOWAIT | M_ZERO);
203 device_printf(sc->sc_dev, "%s: malloc fail\n", name);
204 AcpiOsFree(b.Pointer);
210 sc->sc_asens_temp = as;
213 sc->sc_asens_fan = as;
215 case SENSOR_VOLTS_DC:
216 sc->sc_asens_volt = as;
223 for (i = 0, o++; i < n; i++, o++) {
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",
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",
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;
252 device_printf(sc->sc_dev, "%c%i: "
253 "0x%08"PRIx64" %20s %5"PRIi64" / %5"PRIi64" "
256 as[i].i, as[i].s.desc, (int64_t)as[i].l, (int64_t)as[i].h,
257 oi[4].Integer.Value);
259 sensor_attach(&sc->sc_sensordev, &as[i].s);
262 AcpiOsFree(b.Pointer);
267 aibs_detach(struct device *dev)
269 struct aibs_softc *sc = device_get_softc(dev);
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);
283 #define ddevice_printf(x...) device_printf(x)
285 #define ddevice_printf(x...)
289 aibs_refresh(void *arg)
291 struct aibs_softc *sc = arg;
293 aibs_refresh_r(sc, SENSOR_VOLTS_DC);
294 aibs_refresh_r(sc, SENSOR_TEMP);
295 aibs_refresh_r(sc, SENSOR_FANRPM);
299 aibs_refresh_r(struct aibs_softc *sc, enum sensor_type st)
303 int i, n = sc->sc_sensordev.maxnumt[st];
305 struct aibs_sensor *as;
310 as = sc->sc_asens_temp;
314 as = sc->sc_asens_fan;
316 case SENSOR_VOLTS_DC:
318 as = sc->sc_asens_volt;
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",
331 for (i = 0; i < n; i++)
332 as[i].s.flags |= SENSOR_FINVALID;
336 for (i = 0; i < n; i++) {
341 struct ksensor *s = &as[i].s;
342 const UINT64 l = as[i].l, h = as[i].h;
344 p.Type = ACPI_TYPE_INTEGER;
345 p.Integer.Value = as[i].i;
348 b.Length = ACPI_ALLOCATE_BUFFER;
349 rs = AcpiEvaluateObjectTyped(rh, NULL, &mp, &b,
351 if (ACPI_FAILURE(rs)) {
352 ddevice_printf(sc->sc_dev,
353 "%s: %i: evaluation failed\n",
355 s->flags |= SENSOR_FINVALID;
359 v = bp->Integer.Value;
360 AcpiOsFree(b.Pointer);
364 s->value = v * 100 * 1000 + 273150000;
366 s->status = SENSOR_S_UNKNOWN;
367 s->flags |= SENSOR_FINVALID;
370 s->status = SENSOR_S_CRIT;
372 s->status = SENSOR_S_WARN;
374 s->status = SENSOR_S_OK;
375 s->flags &= ~SENSOR_FINVALID;
380 /* some boards have strange limits for fans */
381 if ((l != 0 && l < v && v < h) ||
383 s->status = SENSOR_S_OK;
385 s->status = SENSOR_S_WARN;
386 s->flags &= ~SENSOR_FINVALID;
388 case SENSOR_VOLTS_DC:
391 s->status = SENSOR_S_OK;
393 s->status = SENSOR_S_WARN;
394 s->flags &= ~SENSOR_FINVALID;