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
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(device_t
);
67 static int aibs_attach(device_t
);
68 static int aibs_detach(device_t
);
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(device_t 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(device_t 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 sensor_task_register(sc
, aibs_refresh
, 5);
133 sensordev_install(&sc
->sc_sensordev
);
138 aibs_attach_sif(struct aibs_softc
*sc
, enum sensor_type st
)
144 char name
[] = "?SIF";
145 struct aibs_sensor
*as
;
154 case SENSOR_VOLTS_DC
:
161 b
.Length
= ACPI_ALLOCATE_BUFFER
;
162 s
= AcpiEvaluateObjectTyped(sc
->sc_ah
, name
, NULL
, &b
,
164 if (ACPI_FAILURE(s
)) {
165 device_printf(sc
->sc_dev
, "%s not found\n", name
);
170 o
= bp
->Package
.Elements
;
171 if (o
[0].Type
!= ACPI_TYPE_INTEGER
) {
172 device_printf(sc
->sc_dev
, "%s[0]: invalid type\n", name
);
173 AcpiOsFree(b
.Pointer
);
177 n
= o
[0].Integer
.Value
;
178 if (bp
->Package
.Count
- 1 < n
) {
179 device_printf(sc
->sc_dev
, "%s: invalid package\n", name
);
180 AcpiOsFree(b
.Pointer
);
182 } else if (bp
->Package
.Count
- 1 > n
) {
185 #ifdef AIBS_MORE_SENSORS
186 n
= bp
->Package
.Count
- 1;
188 device_printf(sc
->sc_dev
, "%s: malformed package: %i/%i"
189 ", assume %i\n", name
, on
, bp
->Package
.Count
- 1, n
);
192 device_printf(sc
->sc_dev
, "%s: no members in the package\n",
194 AcpiOsFree(b
.Pointer
);
198 as
= kmalloc(sizeof(*as
) * n
, M_DEVBUF
, M_NOWAIT
| M_ZERO
);
200 device_printf(sc
->sc_dev
, "%s: malloc fail\n", name
);
201 AcpiOsFree(b
.Pointer
);
207 sc
->sc_asens_temp
= as
;
210 sc
->sc_asens_fan
= as
;
212 case SENSOR_VOLTS_DC
:
213 sc
->sc_asens_volt
= as
;
220 for (i
= 0, o
++; i
< n
; i
++, o
++) {
223 /* acpica automatically evaluates the referenced package */
224 if (o
[0].Type
!= ACPI_TYPE_PACKAGE
) {
225 device_printf(sc
->sc_dev
,
226 "%s: %i: not a package: %i type\n",
230 oi
= o
[0].Package
.Elements
;
231 if (o
[0].Package
.Count
!= 5 ||
232 oi
[0].Type
!= ACPI_TYPE_INTEGER
||
233 oi
[1].Type
!= ACPI_TYPE_STRING
||
234 oi
[2].Type
!= ACPI_TYPE_INTEGER
||
235 oi
[3].Type
!= ACPI_TYPE_INTEGER
||
236 oi
[4].Type
!= ACPI_TYPE_INTEGER
) {
237 device_printf(sc
->sc_dev
,
238 "%s: %i: invalid package\n",
242 as
[i
].i
= oi
[0].Integer
.Value
;
243 strlcpy(as
[i
].s
.desc
, oi
[1].String
.Pointer
,
244 sizeof(as
[i
].s
.desc
));
245 as
[i
].l
= oi
[2].Integer
.Value
;
246 as
[i
].h
= oi
[3].Integer
.Value
;
249 device_printf(sc
->sc_dev
, "%c%i: "
250 "0x%08"PRIx64
" %20s %5"PRIi64
" / %5"PRIi64
" "
253 as
[i
].i
, as
[i
].s
.desc
, (int64_t)as
[i
].l
, (int64_t)as
[i
].h
,
254 oi
[4].Integer
.Value
);
256 sensor_attach(&sc
->sc_sensordev
, &as
[i
].s
);
259 AcpiOsFree(b
.Pointer
);
264 aibs_detach(device_t dev
)
266 struct aibs_softc
*sc
= device_get_softc(dev
);
268 sensordev_deinstall(&sc
->sc_sensordev
);
269 sensor_task_unregister(sc
);
270 if (sc
->sc_asens_volt
!= NULL
)
271 kfree(sc
->sc_asens_volt
, M_DEVBUF
);
272 if (sc
->sc_asens_temp
!= NULL
)
273 kfree(sc
->sc_asens_temp
, M_DEVBUF
);
274 if (sc
->sc_asens_fan
!= NULL
)
275 kfree(sc
->sc_asens_fan
, M_DEVBUF
);
280 #define ddevice_printf(x...) device_printf(x)
282 #define ddevice_printf(x...)
286 aibs_refresh(void *arg
)
288 struct aibs_softc
*sc
= arg
;
290 aibs_refresh_r(sc
, SENSOR_VOLTS_DC
);
291 aibs_refresh_r(sc
, SENSOR_TEMP
);
292 aibs_refresh_r(sc
, SENSOR_FANRPM
);
296 aibs_refresh_r(struct aibs_softc
*sc
, enum sensor_type st
)
300 int i
, n
= sc
->sc_sensordev
.maxnumt
[st
];
302 struct aibs_sensor
*as
;
307 as
= sc
->sc_asens_temp
;
311 as
= sc
->sc_asens_fan
;
313 case SENSOR_VOLTS_DC
:
315 as
= sc
->sc_asens_volt
;
324 rs
= AcpiGetHandle(sc
->sc_ah
, name
, &rh
);
325 if (ACPI_FAILURE(rs
)) {
326 ddevice_printf(sc
->sc_dev
, "%s: method handle not found\n",
328 for (i
= 0; i
< n
; i
++)
329 as
[i
].s
.flags
|= SENSOR_FINVALID
;
333 for (i
= 0; i
< n
; i
++) {
338 struct ksensor
*s
= &as
[i
].s
;
339 const UINT64 l
= as
[i
].l
, h
= as
[i
].h
;
341 p
.Type
= ACPI_TYPE_INTEGER
;
342 p
.Integer
.Value
= as
[i
].i
;
345 b
.Length
= ACPI_ALLOCATE_BUFFER
;
346 rs
= AcpiEvaluateObjectTyped(rh
, NULL
, &mp
, &b
,
348 if (ACPI_FAILURE(rs
)) {
349 ddevice_printf(sc
->sc_dev
,
350 "%s: %i: evaluation failed\n",
352 s
->flags
|= SENSOR_FINVALID
;
356 v
= bp
->Integer
.Value
;
357 AcpiOsFree(b
.Pointer
);
361 s
->value
= v
* 100 * 1000 + 273150000;
363 s
->status
= SENSOR_S_UNKNOWN
;
364 s
->flags
|= SENSOR_FINVALID
;
367 s
->status
= SENSOR_S_CRIT
;
369 s
->status
= SENSOR_S_WARN
;
371 s
->status
= SENSOR_S_OK
;
372 s
->flags
&= ~SENSOR_FINVALID
;
377 /* some boards have strange limits for fans */
378 if ((l
!= 0 && l
< v
&& v
< h
) ||
380 s
->status
= SENSOR_S_OK
;
382 s
->status
= SENSOR_S_WARN
;
383 s
->flags
&= ~SENSOR_FINVALID
;
385 case SENSOR_VOLTS_DC
:
388 s
->status
= SENSOR_S_OK
;
390 s
->status
= SENSOR_S_WARN
;
391 s
->flags
&= ~SENSOR_FINVALID
;