1 /* $NetBSD: aiboost.c,v 1.26 2009/05/12 09:29:46 cegger Exp $ */
4 * Copyright (c) 2007 Juan Romero Pardines
5 * Copyright (c) 2006 Takanori Watanabe
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: aiboost.c,v 1.26 2009/05/12 09:29:46 cegger Exp $");
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/device.h>
36 #include <sys/mutex.h>
39 #include <dev/acpi/acpica.h>
40 #include <dev/acpi/acpireg.h>
41 #include <dev/acpi/acpivar.h>
43 #define _COMPONENT ACPI_RESOURCE_COMPONENT
44 ACPI_MODULE_NAME ("aiboost")
46 #include <dev/sysmon/sysmonvar.h>
49 #define DPRINTF(x) do { printf x; } while (/* CONSTCOND */ 0)
62 struct aiboost_elem elem
[1];
65 struct aiboost_softc
{
66 struct acpi_devnode
*sc_node
; /* ACPI devnode */
67 struct aiboost_comp
*sc_aitemp
, *sc_aivolt
, *sc_aifan
;
68 struct sysmon_envsys
*sc_sme
;
69 envsys_data_t
*sc_sensor
;
73 static ACPI_STATUS
aiboost_getcomp(ACPI_HANDLE
*,
75 struct aiboost_comp
**);
76 static int aiboost_get_value(ACPI_HANDLE
, const char *, UINT32
);
78 /* sysmon_envsys(9) glue */
79 static void aiboost_setup_sensors(struct aiboost_softc
*);
80 static void aiboost_refresh_sensors(struct sysmon_envsys
*,
83 /* autoconf(9) glue */
84 static int aiboost_acpi_match(device_t
, cfdata_t
, void *);
85 static void aiboost_acpi_attach(device_t
, device_t
, void *);
87 CFATTACH_DECL_NEW(aiboost
, sizeof(struct aiboost_softc
), aiboost_acpi_match
,
88 aiboost_acpi_attach
, NULL
, NULL
);
91 * Supported device IDs
94 static const char * const aiboost_acpi_ids
[] = {
100 aiboost_acpi_match(device_t parent
, cfdata_t match
, void *aux
)
102 struct acpi_attach_args
*aa
= aux
;
104 if (aa
->aa_node
->ad_type
!= ACPI_TYPE_DEVICE
)
107 return acpi_match_hid(aa
->aa_node
->ad_devinfo
, aiboost_acpi_ids
);
111 aiboost_acpi_attach(device_t parent
, device_t self
, void *aux
)
113 struct aiboost_softc
*sc
= device_private(self
);
114 struct acpi_attach_args
*aa
= aux
;
116 int i
, maxsens
, error
= 0;
119 sc
->sc_node
= aa
->aa_node
;
120 handl
= sc
->sc_node
->ad_handle
;
125 aprint_normal_dev(self
, "ASUS AI Boost Hardware monitor\n");
127 if (ACPI_FAILURE(aiboost_getcomp(handl
, "TSIF", &sc
->sc_aitemp
)))
130 if (ACPI_FAILURE(aiboost_getcomp(handl
, "VSIF", &sc
->sc_aivolt
)))
133 if (ACPI_FAILURE(aiboost_getcomp(handl
, "FSIF", &sc
->sc_aifan
)))
136 mutex_init(&sc
->sc_mtx
, MUTEX_DEFAULT
, IPL_NONE
);
137 /* Initialize sensors */
138 maxsens
= sc
->sc_aivolt
->num
+ sc
->sc_aitemp
->num
+ sc
->sc_aifan
->num
;
139 DPRINTF(("%s: maxsens=%d\n", __func__
, maxsens
));
141 sc
->sc_sme
= sysmon_envsys_create();
142 len
= sizeof(envsys_data_t
) * maxsens
;
143 sc
->sc_sensor
= kmem_zalloc(len
, KM_NOSLEEP
);
148 * Set properties in sensors.
150 aiboost_setup_sensors(sc
);
153 * Add the sensors into the sysmon_envsys device.
155 for (i
= 0; i
< maxsens
; i
++) {
156 if (sysmon_envsys_sensor_attach(sc
->sc_sme
,
162 * Register the sysmon_envsys device.
164 sc
->sc_sme
->sme_name
= device_xname(self
);
165 sc
->sc_sme
->sme_cookie
= sc
;
166 sc
->sc_sme
->sme_refresh
= aiboost_refresh_sensors
;
168 if ((error
= sysmon_envsys_register(sc
->sc_sme
))) {
169 aprint_error_dev(self
, "unable to register with sysmon "
170 "(error=%d)\n", error
);
174 if (!pmf_device_register(self
, NULL
, NULL
))
175 aprint_error_dev(self
, "couldn't establish power handler\n");
180 kmem_free(sc
->sc_sensor
, len
);
182 sysmon_envsys_destroy(sc
->sc_sme
);
183 mutex_destroy(&sc
->sc_mtx
);
186 #define COPYDESCR(x, y) \
188 strlcpy((x), (y), sizeof(x)); \
189 } while (/* CONSTCOND */ 0)
192 aiboost_setup_sensors(struct aiboost_softc
*sc
)
197 for (i
= 0; i
< sc
->sc_aitemp
->num
; i
++) {
198 sc
->sc_sensor
[i
].units
= ENVSYS_STEMP
;
199 COPYDESCR(sc
->sc_sensor
[i
].desc
, sc
->sc_aitemp
->elem
[i
].desc
);
200 DPRINTF(("%s: data[%d].desc=%s elem[%d].desc=%s\n", __func__
,
201 i
, sc
->sc_sensor
[i
].desc
, i
, sc
->sc_aitemp
->elem
[i
].desc
));
204 /* skip temperatures */
205 j
= sc
->sc_aitemp
->num
;
208 for (i
= 0; i
< sc
->sc_aivolt
->num
; i
++, j
++) {
209 sc
->sc_sensor
[j
].units
= ENVSYS_SVOLTS_DC
;
210 COPYDESCR(sc
->sc_sensor
[j
].desc
, sc
->sc_aivolt
->elem
[i
].desc
);
211 DPRINTF(("%s: data[%d].desc=%s elem[%d].desc=%s\n", __func__
,
212 j
, sc
->sc_sensor
[j
].desc
, i
, sc
->sc_aivolt
->elem
[i
].desc
));
216 j
= sc
->sc_aitemp
->num
+ sc
->sc_aivolt
->num
;
219 for (i
= 0; i
< sc
->sc_aifan
->num
; i
++, j
++) {
220 sc
->sc_sensor
[j
].units
= ENVSYS_SFANRPM
;
221 COPYDESCR(sc
->sc_sensor
[j
].desc
, sc
->sc_aifan
->elem
[i
].desc
);
222 DPRINTF(("%s: data[%d].desc=%s elem[%d].desc=%s\n", __func__
,
223 j
, sc
->sc_sensor
[j
].desc
, i
, sc
->sc_aifan
->elem
[i
].desc
));
229 aiboost_refresh_sensors(struct sysmon_envsys
*sme
, envsys_data_t
*edata
)
231 struct aiboost_softc
*sc
= sme
->sme_cookie
;
232 ACPI_HANDLE
*h
= sc
->sc_node
->ad_handle
;
235 mutex_enter(&sc
->sc_mtx
);
237 i
= edata
->sensor
; /* sensor number */
239 #define AIBOOST_INVALIDATE_SENSOR() \
241 if (val == -1 || val == 0) { \
242 edata->state = ENVSYS_SINVALID; \
245 } while (/* CONSTCOND */ 0)
247 switch (edata
->units
) {
250 val
= aiboost_get_value(h
, "RTMP", sc
->sc_aitemp
->elem
[i
].id
);
251 AIBOOST_INVALIDATE_SENSOR();
252 /* envsys(4) wants uK... convert from Celsius. */
253 edata
->value_cur
= val
* 100000 + 273150000;
254 DPRINTF(("%s: temp[%d] value_cur=%d val=%d j=%d\n", __func__
,
255 i
, edata
->value_cur
, val
, j
));
257 case ENVSYS_SVOLTS_DC
:
259 j
= i
- sc
->sc_aitemp
->num
;
260 val
= aiboost_get_value(h
, "RVLT", sc
->sc_aivolt
->elem
[j
].id
);
261 AIBOOST_INVALIDATE_SENSOR();
262 /* envsys(4) wants mV... */
263 edata
->value_cur
= val
* 10000;
264 edata
->value_cur
/= 10;
265 DPRINTF(("%s: volt[%d] value_cur=%d val=%d j=%d\n", __func__
,
266 i
, edata
->value_cur
, val
, j
));
270 j
= i
- (sc
->sc_aitemp
->num
+ sc
->sc_aivolt
->num
);
271 val
= aiboost_get_value(h
, "RFAN", sc
->sc_aifan
->elem
[j
].id
);
272 AIBOOST_INVALIDATE_SENSOR();
273 edata
->value_cur
= val
;
274 DPRINTF(("%s: fan[%d] val=%d j=%d\n", __func__
, i
, val
, j
));
278 edata
->state
= ENVSYS_SVALID
;
280 mutex_exit(&sc
->sc_mtx
);
284 aiboost_get_value(ACPI_HANDLE handle
, const char *path
, UINT32 number
)
286 ACPI_OBJECT arg1
, *ret
;
287 ACPI_OBJECT_LIST args
;
290 buf
.Length
= ACPI_ALLOCATE_LOCAL_BUFFER
;
293 arg1
.Type
= ACPI_TYPE_INTEGER
;
294 arg1
.Integer
.Value
= number
;
296 args
.Pointer
= &arg1
;
298 if (ACPI_FAILURE(AcpiEvaluateObject(handle
, path
, &args
, &buf
)))
302 val
= (ret
->Type
== ACPI_TYPE_INTEGER
) ? ret
->Integer
.Value
: -1;
304 ACPI_FREE(buf
.Pointer
);
310 aiboost_getcomp(ACPI_HANDLE
*h
, const char *name
, struct aiboost_comp
**comp
)
312 ACPI_BUFFER buf
, buf2
;
313 ACPI_OBJECT
*o
, *elem
, *subobj
, *myobj
;
316 struct aiboost_comp
*c
= NULL
;
318 const char *str
= NULL
;
319 size_t length
, clen
= 0;
321 status
= AcpiGetHandle(h
, name
, &h1
);
322 if (ACPI_FAILURE(status
)) {
323 DPRINTF(("%s: AcpiGetHandle\n", __func__
));
327 status
= acpi_eval_struct(h1
, NULL
, &buf
);
328 if (ACPI_FAILURE(status
)) {
329 DPRINTF(("%s: acpi_eval_struct\n", __func__
));
334 if (o
->Type
!= ACPI_TYPE_PACKAGE
) {
335 DPRINTF(("%s: o->Type != ACPI_TYPE_PACKAGE\n", __func__
));
339 elem
= o
->Package
.Elements
;
340 if (elem
->Type
!= ACPI_TYPE_INTEGER
) {
341 DPRINTF(("%s: elem->Type != ACPI_TYPE_INTEGER\n", __func__
));
344 num
= (int)elem
[0].Integer
.Value
;
345 if (num
!= o
->Package
.Count
- 1) {
346 DPRINTF(("%s: bad Package.Count/element[0].value\n", __func__
));
349 clen
= sizeof(struct aiboost_comp
) + sizeof(struct aiboost_elem
) * num
;
350 c
= kmem_zalloc(clen
, KM_NOSLEEP
);
357 DPRINTF(("%s, %d subitems\n", acpi_name(h1
), num
));
359 for (i
= 0; i
< num
; i
++) {
360 elem
= &o
->Package
.Elements
[i
+1];
361 DPRINTF(("elem[%d]->Type = %x\n", i
+1, elem
->Type
));
362 if (elem
->Type
== ACPI_TYPE_PACKAGE
&&
363 elem
->Package
.Elements
[0].Type
== ACPI_TYPE_INTEGER
) {
364 DPRINTF((" subelem->Type = %x, %d\n",
365 elem
->Package
.Elements
[0].Type
,
366 (int)elem
->Package
.Elements
[0].Integer
.Value
));
370 for (i
= 0; i
< num
; i
++) {
371 elem
= &o
->Package
.Elements
[i
+1];
372 if (elem
->Type
== ACPI_TYPE_PACKAGE
) {
373 /* information provided directly in package */
376 } else if (elem
->Type
== ACPI_TYPE_LOCAL_REFERENCE
) {
377 /* information provided indirectly. request package */
378 c
->elem
[i
].h
= elem
->Reference
.Handle
;
379 status
= acpi_eval_struct(c
->elem
[i
].h
, NULL
, &buf2
);
380 if (ACPI_FAILURE(status
)) {
381 DPRINTF(("%s: fetching object in buf2\n",
385 subobj
= buf2
.Pointer
;
386 if (subobj
->Type
!= ACPI_TYPE_PACKAGE
) {
387 DPRINTF(("%s: fetched type cannot processed\n",
392 DPRINTF(("%s: elem->Type cannot be processed\n",
397 myobj
= &subobj
->Package
.Elements
[0];
400 if (myobj
== NULL
|| myobj
->Type
!= ACPI_TYPE_INTEGER
) {
401 DPRINTF(("%s: wrong type for element %d\n", __func__
,
406 c
->elem
[i
].id
= myobj
->Integer
.Value
;
409 myobj
= &subobj
->Package
.Elements
[1];
411 DPRINTF(("%s: myobj is NULL\n", __func__
));
415 switch (myobj
->Type
) {
416 case ACPI_TYPE_STRING
:
417 str
= myobj
->String
.Pointer
;
418 length
= myobj
->String
.Length
;
420 case ACPI_TYPE_BUFFER
:
421 str
= myobj
->Buffer
.Pointer
;
422 length
= myobj
->Buffer
.Length
;
428 DPRINTF(("%s: id=%d str=%s\n", __func__
,
429 c
->elem
[i
].id
, str
));
431 (void)memcpy(c
->elem
[i
].desc
, str
, length
);
434 ACPI_FREE(buf2
.Pointer
);
438 ACPI_FREE(buf
.Pointer
);
444 ACPI_FREE(buf
.Pointer
);
446 ACPI_FREE(buf2
.Pointer
);