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 <sys/cdefs.h>
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/kernel.h>
24 #include <sys/module.h>
25 #include <sys/malloc.h>
27 #include <sys/sensors.h>
33 * ASUSTeK AI Booster (ACPI ATK0110).
35 * This code was originally written for OpenBSD after the techniques
36 * described in the Linux's asus_atk0110.c and FreeBSD's acpi_aiboost.c
37 * were verified to be accurate on the actual hardware kindly provided by
38 * Sam Fourman Jr. It was subsequently ported from OpenBSD to DragonFly BSD.
40 * -- Constantine A. Murenin <http://cnst.su/>
43 #define AIBS_MORE_SENSORS
54 struct device
*sc_dev
;
57 struct aibs_sensor
*sc_asens_volt
;
58 struct aibs_sensor
*sc_asens_temp
;
59 struct aibs_sensor
*sc_asens_fan
;
61 struct ksensordev sc_sensordev
;
65 static int aibs_probe(struct device
*);
66 static int aibs_attach(struct device
*);
67 static int aibs_detach(struct device
*);
68 static void aibs_refresh(void *);
70 static void aibs_attach_sif(struct aibs_softc
*, enum sensor_type
);
71 static void aibs_refresh_r(struct aibs_softc
*, enum sensor_type
);
74 static device_method_t aibs_methods
[] = {
75 DEVMETHOD(device_probe
, aibs_probe
),
76 DEVMETHOD(device_attach
, aibs_attach
),
77 DEVMETHOD(device_detach
, aibs_detach
),
81 static driver_t aibs_driver
= {
84 sizeof(struct aibs_softc
)
87 static devclass_t aibs_devclass
;
89 DRIVER_MODULE(aibs
, acpi
, aibs_driver
, aibs_devclass
, NULL
, NULL
);
92 static char* aibs_hids
[] = {
98 aibs_probe(struct device
*dev
)
101 if (acpi_disabled("aibs") ||
102 ACPI_ID_PROBE(device_get_parent(dev
), dev
, aibs_hids
) == NULL
)
105 device_set_desc(dev
, "ASUSTeK AI Booster (ACPI ASOC ATK0110)");
110 aibs_attach(struct device
*dev
)
112 struct aibs_softc
*sc
;
114 sc
= device_get_softc(dev
);
116 sc
->sc_ah
= acpi_get_handle(dev
);
118 strlcpy(sc
->sc_sensordev
.xname
, device_get_nameunit(dev
),
119 sizeof(sc
->sc_sensordev
.xname
));
121 aibs_attach_sif(sc
, SENSOR_VOLTS_DC
);
122 aibs_attach_sif(sc
, SENSOR_TEMP
);
123 aibs_attach_sif(sc
, SENSOR_FANRPM
);
125 if (sc
->sc_sensordev
.sensors_count
== 0) {
126 device_printf(dev
, "no sensors found\n");
130 if (sensor_task_register(sc
, aibs_refresh
, 5)) {
131 device_printf(dev
, "unable to register update task\n");
135 sensordev_install(&sc
->sc_sensordev
);
140 aibs_attach_sif(struct aibs_softc
*sc
, enum sensor_type st
)
146 char name
[] = "?SIF";
147 struct aibs_sensor
*as
;
156 case SENSOR_VOLTS_DC
:
163 b
.Length
= ACPI_ALLOCATE_BUFFER
;
164 s
= AcpiEvaluateObjectTyped(sc
->sc_ah
, name
, NULL
, &b
,
166 if (ACPI_FAILURE(s
)) {
167 device_printf(sc
->sc_dev
, "%s not found\n", name
);
172 o
= bp
->Package
.Elements
;
173 if (o
[0].Type
!= ACPI_TYPE_INTEGER
) {
174 device_printf(sc
->sc_dev
, "%s[0]: invalid type\n", name
);
175 AcpiOsFree(b
.Pointer
);
179 n
= o
[0].Integer
.Value
;
180 if (bp
->Package
.Count
- 1 < n
) {
181 device_printf(sc
->sc_dev
, "%s: invalid package\n", name
);
182 AcpiOsFree(b
.Pointer
);
184 } else if (bp
->Package
.Count
- 1 > n
) {
187 #ifdef AIBS_MORE_SENSORS
188 n
= bp
->Package
.Count
- 1;
190 device_printf(sc
->sc_dev
, "%s: misformed package: %i/%i"
191 ", assume %i\n", name
, on
, bp
->Package
.Count
- 1, n
);
194 device_printf(sc
->sc_dev
, "%s: no members in the package\n",
196 AcpiOsFree(b
.Pointer
);
200 as
= kmalloc(sizeof(*as
) * n
, M_DEVBUF
, M_NOWAIT
| M_ZERO
);
202 device_printf(sc
->sc_dev
, "%s: malloc fail\n", name
);
203 AcpiOsFree(b
.Pointer
);
209 sc
->sc_asens_temp
= as
;
212 sc
->sc_asens_fan
= as
;
214 case SENSOR_VOLTS_DC
:
215 sc
->sc_asens_volt
= as
;
222 for (i
= 0, o
++; i
< n
; i
++, o
++) {
225 /* acpica5 automatically evaluates the referenced package */
226 if(o
[0].Type
!= ACPI_TYPE_PACKAGE
) {
227 device_printf(sc
->sc_dev
,
228 "%s: %i: not a package: %i type\n",
232 oi
= o
[0].Package
.Elements
;
233 if (o
[0].Package
.Count
!= 5 ||
234 oi
[0].Type
!= ACPI_TYPE_INTEGER
||
235 oi
[1].Type
!= ACPI_TYPE_STRING
||
236 oi
[2].Type
!= ACPI_TYPE_INTEGER
||
237 oi
[3].Type
!= ACPI_TYPE_INTEGER
||
238 oi
[4].Type
!= ACPI_TYPE_INTEGER
) {
239 device_printf(sc
->sc_dev
,
240 "%s: %i: invalid package\n",
244 as
[i
].i
= oi
[0].Integer
.Value
;
245 strlcpy(as
[i
].s
.desc
, oi
[1].String
.Pointer
,
246 sizeof(as
[i
].s
.desc
));
247 as
[i
].l
= oi
[2].Integer
.Value
;
248 as
[i
].h
= oi
[3].Integer
.Value
;
251 device_printf(sc
->sc_dev
, "%c%i: "
252 "0x%08llx %20s %5lli / %5lli 0x%llx\n",
254 as
[i
].i
, as
[i
].s
.desc
, as
[i
].l
, as
[i
].h
,
255 oi
[4].Integer
.Value
);
257 sensor_attach(&sc
->sc_sensordev
, &as
[i
].s
);
260 AcpiOsFree(b
.Pointer
);
265 aibs_detach(struct device
*dev
)
267 struct aibs_softc
*sc
= device_get_softc(dev
);
269 sensordev_deinstall(&sc
->sc_sensordev
);
270 sensor_task_unregister(sc
);
271 if (sc
->sc_asens_volt
!= NULL
)
272 kfree(sc
->sc_asens_volt
, M_DEVBUF
);
273 if (sc
->sc_asens_temp
!= NULL
)
274 kfree(sc
->sc_asens_temp
, M_DEVBUF
);
275 if (sc
->sc_asens_fan
!= NULL
)
276 kfree(sc
->sc_asens_fan
, M_DEVBUF
);
281 #define ddevice_printf(x...) device_printf(x)
283 #define ddevice_printf(x...)
287 aibs_refresh(void *arg
)
289 struct aibs_softc
*sc
= arg
;
291 aibs_refresh_r(sc
, SENSOR_VOLTS_DC
);
292 aibs_refresh_r(sc
, SENSOR_TEMP
);
293 aibs_refresh_r(sc
, SENSOR_FANRPM
);
297 aibs_refresh_r(struct aibs_softc
*sc
, enum sensor_type st
)
301 int i
, n
= sc
->sc_sensordev
.maxnumt
[st
];
303 struct aibs_sensor
*as
;
308 as
= sc
->sc_asens_temp
;
312 as
= sc
->sc_asens_fan
;
314 case SENSOR_VOLTS_DC
:
316 as
= sc
->sc_asens_volt
;
325 rs
= AcpiGetHandle(sc
->sc_ah
, name
, &rh
);
326 if (ACPI_FAILURE(rs
)) {
327 ddevice_printf(sc
->sc_dev
, "%s: method handle not found\n",
329 for (i
= 0; i
< n
; i
++)
330 as
[i
].s
.flags
|= SENSOR_FINVALID
;
334 for (i
= 0; i
< n
; i
++) {
339 struct ksensor
*s
= &as
[i
].s
;
340 const int64_t l
= as
[i
].l
, h
= as
[i
].h
;
342 p
.Type
= ACPI_TYPE_INTEGER
;
343 p
.Integer
.Value
= as
[i
].i
;
346 b
.Length
= ACPI_ALLOCATE_BUFFER
;
347 rs
= AcpiEvaluateObjectTyped(rh
, NULL
, &mp
, &b
,
349 if (ACPI_FAILURE(rs
)) {
350 ddevice_printf(sc
->sc_dev
,
351 "%s: %i: evaluation failed\n",
353 s
->flags
|= SENSOR_FINVALID
;
357 v
= bp
->Integer
.Value
;
358 AcpiOsFree(b
.Pointer
);
362 s
->value
= v
* 100 * 1000 + 273150000;
364 s
->status
= SENSOR_S_UNKNOWN
;
365 s
->flags
|= SENSOR_FINVALID
;
368 s
->status
= SENSOR_S_CRIT
;
370 s
->status
= SENSOR_S_WARN
;
372 s
->status
= SENSOR_S_OK
;
373 s
->flags
&= ~SENSOR_FINVALID
;
378 /* some boards have strange limits for fans */
379 if ((l
!= 0 && l
< v
&& v
< h
) ||
381 s
->status
= SENSOR_S_OK
;
383 s
->status
= SENSOR_S_WARN
;
384 s
->flags
&= ~SENSOR_FINVALID
;
386 case SENSOR_VOLTS_DC
:
389 s
->status
= SENSOR_S_OK
;
391 s
->status
= SENSOR_S_WARN
;
392 s
->flags
&= ~SENSOR_FINVALID
;