No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / acpi / aiboost.c
blob7c27a0729ba8e40e66732a6882b405beb7482d55
1 /* $NetBSD: aiboost.c,v 1.26 2009/05/12 09:29:46 cegger Exp $ */
3 /*-
4 * Copyright (c) 2007 Juan Romero Pardines
5 * Copyright (c) 2006 Takanori Watanabe
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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
27 * SUCH DAMAGE.
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>
37 #include <sys/kmem.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>
48 #ifdef AIBOOST_DEBUG
49 #define DPRINTF(x) do { printf x; } while (/* CONSTCOND */ 0)
50 #else
51 #define DPRINTF(x)
52 #endif
54 struct aiboost_elem {
55 ACPI_HANDLE h;
56 UINT32 id;
57 char desc[256];
60 struct aiboost_comp {
61 unsigned int num;
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;
70 kmutex_t sc_mtx;
73 static ACPI_STATUS aiboost_getcomp(ACPI_HANDLE *,
74 const char *,
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 *,
81 envsys_data_t *);
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[] = {
95 "ATK0110",
96 NULL
99 static int
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)
105 return 0;
107 return acpi_match_hid(aa->aa_node->ad_devinfo, aiboost_acpi_ids);
110 static void
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;
115 ACPI_HANDLE *handl;
116 int i, maxsens, error = 0;
117 size_t len;
119 sc->sc_node = aa->aa_node;
120 handl = sc->sc_node->ad_handle;
122 aprint_naive("\n");
123 aprint_normal("\n");
125 aprint_normal_dev(self, "ASUS AI Boost Hardware monitor\n");
127 if (ACPI_FAILURE(aiboost_getcomp(handl, "TSIF", &sc->sc_aitemp)))
128 return;
130 if (ACPI_FAILURE(aiboost_getcomp(handl, "VSIF", &sc->sc_aivolt)))
131 return;
133 if (ACPI_FAILURE(aiboost_getcomp(handl, "FSIF", &sc->sc_aifan)))
134 return;
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);
144 if (!sc->sc_sensor)
145 goto bad2;
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,
157 &sc->sc_sensor[i]))
158 goto bad;
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);
171 goto bad;
174 if (!pmf_device_register(self, NULL, NULL))
175 aprint_error_dev(self, "couldn't establish power handler\n");
177 return;
179 bad:
180 kmem_free(sc->sc_sensor, len);
181 bad2:
182 sysmon_envsys_destroy(sc->sc_sme);
183 mutex_destroy(&sc->sc_mtx);
186 #define COPYDESCR(x, y) \
187 do { \
188 strlcpy((x), (y), sizeof(x)); \
189 } while (/* CONSTCOND */ 0)
191 static void
192 aiboost_setup_sensors(struct aiboost_softc *sc)
194 int i, j;
196 /* Temperatures */
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;
207 /* Voltages */
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));
215 /* skip voltages */
216 j = sc->sc_aitemp->num + sc->sc_aivolt->num;
218 /* Fans */
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));
228 static void
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;
233 int i, j, val;
235 mutex_enter(&sc->sc_mtx);
236 j = 0;
237 i = edata->sensor; /* sensor number */
239 #define AIBOOST_INVALIDATE_SENSOR() \
240 do { \
241 if (val == -1 || val == 0) { \
242 edata->state = ENVSYS_SINVALID; \
243 goto out; \
245 } while (/* CONSTCOND */ 0)
247 switch (edata->units) {
248 case ENVSYS_STEMP:
249 /* Temperatures */
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));
256 break;
257 case ENVSYS_SVOLTS_DC:
258 /* Voltages */
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));
267 break;
268 case ENVSYS_SFANRPM:
269 /* Fans */
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));
275 break;
278 edata->state = ENVSYS_SVALID;
279 out:
280 mutex_exit(&sc->sc_mtx);
283 static int
284 aiboost_get_value(ACPI_HANDLE handle, const char *path, UINT32 number)
286 ACPI_OBJECT arg1, *ret;
287 ACPI_OBJECT_LIST args;
288 ACPI_BUFFER buf;
289 int val;
290 buf.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
291 buf.Pointer = 0;
293 arg1.Type = ACPI_TYPE_INTEGER;
294 arg1.Integer.Value = number;
295 args.Count = 1;
296 args.Pointer = &arg1;
298 if (ACPI_FAILURE(AcpiEvaluateObject(handle, path, &args, &buf)))
299 return -1;
301 ret = buf.Pointer;
302 val = (ret->Type == ACPI_TYPE_INTEGER) ? ret->Integer.Value : -1;
304 ACPI_FREE(buf.Pointer);
305 return val;
309 static ACPI_STATUS
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;
314 ACPI_STATUS status;
315 ACPI_HANDLE h1;
316 struct aiboost_comp *c = NULL;
317 int i, num;
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__));
324 return status;
327 status = acpi_eval_struct(h1, NULL, &buf);
328 if (ACPI_FAILURE(status)) {
329 DPRINTF(("%s: acpi_eval_struct\n", __func__));
330 return status;
333 o = buf.Pointer;
334 if (o->Type != ACPI_TYPE_PACKAGE) {
335 DPRINTF(("%s: o->Type != ACPI_TYPE_PACKAGE\n", __func__));
336 goto error;
339 elem = o->Package.Elements;
340 if (elem->Type != ACPI_TYPE_INTEGER) {
341 DPRINTF(("%s: elem->Type != ACPI_TYPE_INTEGER\n", __func__));
342 goto error;
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);
351 if (!c)
352 goto error;
354 *comp = c;
355 c->num = num;
357 DPRINTF(("%s, %d subitems\n", acpi_name(h1), num));
358 #ifdef AIBOOST_DEBUG
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));
369 #endif
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 */
374 subobj = elem;
375 buf2.Pointer = NULL;
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",
382 __func__));
383 goto error;
385 subobj = buf2.Pointer;
386 if (subobj->Type != ACPI_TYPE_PACKAGE) {
387 DPRINTF(("%s: fetched type cannot processed\n",
388 __func__));
389 goto error;
391 } else {
392 DPRINTF(("%s: elem->Type cannot be processed\n",
393 __func__));
394 goto error;
397 myobj = &subobj->Package.Elements[0];
399 /* Get UID */
400 if (myobj == NULL || myobj->Type != ACPI_TYPE_INTEGER) {
401 DPRINTF(("%s: wrong type for element %d\n", __func__,
402 i + 1));
403 goto error;
406 c->elem[i].id = myobj->Integer.Value;
408 /* Get string */
409 myobj = &subobj->Package.Elements[1];
410 if (myobj == NULL) {
411 DPRINTF(("%s: myobj is NULL\n", __func__));
412 goto error;
415 switch (myobj->Type) {
416 case ACPI_TYPE_STRING:
417 str = myobj->String.Pointer;
418 length = myobj->String.Length;
419 break;
420 case ACPI_TYPE_BUFFER:
421 str = myobj->Buffer.Pointer;
422 length = myobj->Buffer.Length;
423 break;
424 default:
425 goto error;
428 DPRINTF(("%s: id=%d str=%s\n", __func__,
429 c->elem[i].id, str));
431 (void)memcpy(c->elem[i].desc, str, length);
433 if (buf2.Pointer)
434 ACPI_FREE(buf2.Pointer);
437 if (buf.Pointer)
438 ACPI_FREE(buf.Pointer);
440 return 0;
442 error:
443 if (buf.Pointer)
444 ACPI_FREE(buf.Pointer);
445 if (buf2.Pointer)
446 ACPI_FREE(buf2.Pointer);
447 if (c)
448 kmem_free(c, clen);
450 return AE_BAD_DATA;