acpi_tz.c revision 1.65 1 /* $NetBSD: acpi_tz.c,v 1.65 2010/04/15 07:02:24 jruoho Exp $ */
2
3 /*
4 * Copyright (c) 2003 Jared D. McNeill <jmcneill (at) invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /*
29 * ACPI Thermal Zone driver
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: acpi_tz.c,v 1.65 2010/04/15 07:02:24 jruoho Exp $");
34
35 #include <sys/param.h>
36 #include <sys/device.h>
37 #include <sys/callout.h>
38 #include <sys/kernel.h>
39 #include <sys/systm.h>
40
41 #include <dev/acpi/acpireg.h>
42 #include <dev/acpi/acpivar.h>
43
44 #define _COMPONENT ACPI_TZ_COMPONENT
45 ACPI_MODULE_NAME ("acpi_tz")
46
47 /* flags */
48 #define ATZ_F_VERBOSE 0x01 /* show events to console */
49 #define ATZ_F_CRITICAL 0x02 /* zone critical */
50 #define ATZ_F_HOT 0x04 /* zone hot */
51 #define ATZ_F_PASSIVE 0x08 /* zone passive cooling */
52 #define ATZ_F_PASSIVEONLY 0x10 /* zone is passive cooling only */
53
54 /* no active cooling level */
55 #define ATZ_ACTIVE_NONE -1
56
57 /* constants */
58 #define ATZ_TZP_RATE 300 /* default if no _TZP CM present (30 secs) */
59 #define ATZ_NLEVELS 10 /* number of cooling levels, from ACPI spec */
60 #define ATZ_ZEROC 2732 /* 0C, measured in 0.1 Kelvin */
61 #define ATZ_TMP_INVALID 0xffffffff /* invalid temperature */
62 #define ATZ_ZONE_EXPIRE 9000 /* zone info refetch interval (15min) */
63
64 /* sensor indexes */
65 #define ATZ_SENSOR_TEMP 0 /* thermal zone temperature */
66
67 static int acpitz_match(device_t, cfdata_t, void *);
68 static void acpitz_attach(device_t, device_t, void *);
69
70 /*
71 * ACPI Temperature Zone information. Note all temperatures are reported
72 * in 0.1 Kelvin, and that the ACPI specification assumes that
73 * K = C + 273.2 rather than the nominal 273.15 used by envsys(4).
74 * So define an appropriate conversion.
75 */
76
77 #define ATZ2UKELVIN(t) ((t) * 100000 - 50000)
78
79 struct acpitz_zone {
80 /* Active cooling temperature threshold */
81 uint32_t ac[ATZ_NLEVELS];
82 /* Package of references to all active cooling devices for a level */
83 ACPI_BUFFER al[ATZ_NLEVELS];
84 /* Critical temperature threshold for system shutdown */
85 uint32_t crt;
86 /* Critical temperature threshold for S4 sleep */
87 uint32_t hot;
88 /* Package of references to processor objects for passive cooling */
89 ACPI_BUFFER psl;
90 /* Conveys if temperatures are absolute or relative values. */
91 uint32_t rtv;
92 /* Passive cooling temperature threshold */
93 uint32_t psv;
94 /* Thermal constants for use in passive cooling formulas */
95 uint32_t tc1, tc2;
96 /* Current temperature of the thermal zone */
97 uint32_t prevtmp, tmp;
98 /* Thermal sampling period for passive cooling, in tenths of seconds */
99 uint32_t tsp;
100 /* Package of references to devices in this TZ (optional) */
101 ACPI_BUFFER tzd;
102 /* Recommended TZ polling frequency, in tenths of seconds */
103 uint32_t tzp;
104 /* Thermal zone name */
105 char *name;
106 /* FAN min, max, current rpms */
107 uint32_t fanmin, fanmax, fancurrent;
108 };
109
110 struct acpitz_softc {
111 struct acpi_devnode *sc_devnode;
112 struct acpitz_zone sc_zone;
113 struct callout sc_callout;
114 struct sysmon_envsys *sc_sme;
115 envsys_data_t sc_temp_sensor;
116 envsys_data_t sc_fan_sensor;
117 int sc_active; /* active cooling level */
118 int sc_flags;
119 int sc_rate; /* tz poll rate */
120 int sc_zone_expire;
121
122 int sc_first;
123 int sc_have_fan; /* FAN sensor is optional */
124 };
125
126 static void acpitz_get_status(void *);
127 static void acpitz_get_zone(void *, int);
128 static void acpitz_get_zone_quiet(void *);
129 static char *acpitz_celcius_string(int);
130 static void acpitz_print_status(device_t);
131 static void acpitz_power_off(struct acpitz_softc *);
132 static void acpitz_power_zone(struct acpitz_softc *, int, int);
133 static void acpitz_sane_temp(uint32_t *tmp);
134 static ACPI_STATUS
135 acpitz_switch_cooler(ACPI_OBJECT *, void *);
136 static void acpitz_notify_handler(ACPI_HANDLE, uint32_t, void *);
137 static int acpitz_get_integer(device_t, const char *, uint32_t *);
138 static void acpitz_tick(void *);
139 static void acpitz_init_envsys(device_t);
140 static void acpitz_get_limits(struct sysmon_envsys *, envsys_data_t *,
141 sysmon_envsys_lim_t *, uint32_t *);
142 static int acpitz_get_fanspeed(device_t, uint32_t *,
143 uint32_t *, uint32_t *);
144 #ifdef notyet
145 static ACPI_STATUS
146 acpitz_set_fanspeed(device_t, uint32_t);
147 #endif
148
149 CFATTACH_DECL_NEW(acpitz, sizeof(struct acpitz_softc), acpitz_match,
150 acpitz_attach, NULL, NULL);
151
152 /*
153 * acpitz_match: autoconf(9) match routine
154 */
155 static int
156 acpitz_match(device_t parent, cfdata_t match, void *aux)
157 {
158 struct acpi_attach_args *aa = aux;
159
160 if (aa->aa_node->ad_type != ACPI_TYPE_THERMAL)
161 return 0;
162
163 return 1;
164 }
165
166 /*
167 * acpitz_attach: autoconf(9) attach routine
168 */
169 static void
170 acpitz_attach(device_t parent, device_t self, void *aux)
171 {
172 struct acpitz_softc *sc = device_private(self);
173 struct acpi_attach_args *aa = aux;
174 ACPI_STATUS rv;
175 ACPI_INTEGER v;
176
177 #if 0
178 sc->sc_flags = ATZ_F_VERBOSE;
179 #endif
180 sc->sc_devnode = aa->aa_node;
181
182 aprint_naive("\n");
183 aprint_normal(": ACPI Thermal Zone\n");
184
185 rv = acpi_eval_integer(sc->sc_devnode->ad_handle, "_TZP", &v);
186 if (ACPI_FAILURE(rv))
187 sc->sc_zone.tzp = ATZ_TZP_RATE;
188 else
189 sc->sc_zone.tzp = v;
190
191 aprint_debug_dev(self, "sample rate %d.%ds\n",
192 sc->sc_zone.tzp / 10, sc->sc_zone.tzp % 10);
193
194 /* XXX a value of 0 means "polling is not necessary" */
195 if (sc->sc_zone.tzp == 0)
196 sc->sc_zone.tzp = ATZ_TZP_RATE;
197
198 sc->sc_zone_expire = ATZ_ZONE_EXPIRE / sc->sc_zone.tzp;
199 sc->sc_first = 1;
200 sc->sc_have_fan = 0;
201 if (acpitz_get_fanspeed(self,
202 &sc->sc_zone.fanmin, &sc->sc_zone.fanmax, &sc->sc_zone.fancurrent)
203 == 0)
204 sc->sc_have_fan = 1;
205
206 rv = acpi_eval_string(sc->sc_devnode->ad_handle,
207 "REGN", &sc->sc_zone.name);
208 if (ACPI_FAILURE(rv))
209 sc->sc_zone.name = __UNCONST("temperature");
210
211 acpitz_get_zone(self, 1);
212 acpitz_get_status(self);
213
214 (void)acpi_register_notify(sc->sc_devnode, acpitz_notify_handler);
215
216 callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
217 callout_setfunc(&sc->sc_callout, acpitz_tick, self);
218
219 acpitz_init_envsys(self);
220
221 if (!pmf_device_register(self, NULL, NULL))
222 aprint_error(": couldn't establish power handler\n");
223
224 callout_schedule(&sc->sc_callout, sc->sc_zone.tzp * hz / 10);
225 }
226
227 static void
228 acpitz_get_zone_quiet(void *opaque)
229 {
230 acpitz_get_zone(opaque, 0);
231 }
232
233 static void
234 acpitz_get_status(void *opaque)
235 {
236 device_t dv = opaque;
237 struct acpitz_softc *sc = device_private(dv);
238 uint32_t tmp, active, fmin, fmax, fcurrent;
239 int i, flags;
240
241 sc->sc_zone_expire--;
242 if (sc->sc_zone_expire <= 0) {
243 sc->sc_zone_expire = ATZ_ZONE_EXPIRE / sc->sc_zone.tzp;
244 if (sc->sc_flags & ATZ_F_VERBOSE)
245 printf("%s: force refetch zone\n", device_xname(dv));
246 acpitz_get_zone(dv, 0);
247 }
248
249 if (acpitz_get_integer(dv, "_TMP", &tmp) != 0)
250 return;
251
252 sc->sc_zone.prevtmp = sc->sc_zone.tmp;
253 sc->sc_zone.tmp = tmp;
254 if (sc->sc_first)
255 sc->sc_zone.prevtmp = tmp;
256 /* XXX sanity check for tmp here? */
257
258 if (acpitz_get_fanspeed(dv, &fmin, &fmax, &fcurrent) == 0) {
259 if (fcurrent != ATZ_TMP_INVALID)
260 sc->sc_zone.fancurrent = fcurrent;
261 }
262
263 /*
264 * The temperature unit for envsys(4) is microKelvin, so convert to
265 * that from ACPI's microKelvin. Also, the ACPI specification assumes
266 * that K = C + 273.2 rather than the nominal 273.15 used by envsys(4),
267 * so we correct for that too.
268 */
269 sc->sc_temp_sensor.value_cur = ATZ2UKELVIN(sc->sc_zone.tmp);
270 sc->sc_temp_sensor.state = ENVSYS_SVALID;
271
272 sc->sc_fan_sensor.value_cur = sc->sc_zone.fancurrent;
273 sc->sc_fan_sensor.state = ENVSYS_SVALID;
274
275 if (sc->sc_flags & ATZ_F_VERBOSE)
276 acpitz_print_status(dv);
277
278 if (sc->sc_flags & ATZ_F_PASSIVEONLY) {
279 /* Passive Cooling: XXX not yet */
280
281 } else {
282 /* Active Cooling */
283
284 /* temperature threshold: _AC0 > ... > _AC9 */
285 active = ATZ_ACTIVE_NONE;
286 for (i = ATZ_NLEVELS - 1; i >= 0; i--) {
287 if (sc->sc_zone.ac[i] == ATZ_TMP_INVALID)
288 continue;
289
290 /* we want to keep highest cooling mode in 'active' */
291 if (sc->sc_zone.ac[i] <= tmp)
292 active = i;
293 }
294
295 flags = sc->sc_flags &
296 ~(ATZ_F_CRITICAL|ATZ_F_HOT|ATZ_F_PASSIVE);
297 if (sc->sc_zone.psv != ATZ_TMP_INVALID &&
298 tmp >= sc->sc_zone.psv)
299 flags |= ATZ_F_PASSIVE;
300 if (sc->sc_zone.hot != ATZ_TMP_INVALID &&
301 tmp >= sc->sc_zone.hot)
302 flags |= ATZ_F_HOT;
303 if (sc->sc_zone.crt != ATZ_TMP_INVALID &&
304 tmp >= sc->sc_zone.crt)
305 flags |= ATZ_F_CRITICAL;
306
307 if (flags != sc->sc_flags) {
308 int changed = (sc->sc_flags ^ flags) & flags;
309 sc->sc_flags = flags;
310 if (changed & ATZ_F_CRITICAL) {
311 sc->sc_temp_sensor.state = ENVSYS_SCRITOVER;
312 aprint_debug_dev(dv,
313 "zone went critical at temp %sC\n",
314 acpitz_celcius_string(tmp));
315 } else if (changed & ATZ_F_HOT) {
316 sc->sc_temp_sensor.state = ENVSYS_SCRITOVER;
317 aprint_debug_dev(dv,
318 "zone went hot at temp %sC\n",
319 acpitz_celcius_string(tmp));
320 }
321 }
322
323 /* power on fans */
324 if (sc->sc_active != active) {
325 if (sc->sc_active != ATZ_ACTIVE_NONE)
326 acpitz_power_zone(sc, sc->sc_active, 0);
327
328 if (active != ATZ_ACTIVE_NONE) {
329 if (sc->sc_flags & ATZ_F_VERBOSE)
330 printf("%s: active cooling level %u\n",
331 device_xname(dv), active);
332 acpitz_power_zone(sc, active, 1);
333 } else if (sc->sc_flags & ATZ_F_VERBOSE)
334 printf("%s: no active cooling level\n",
335 device_xname(dv));
336
337 sc->sc_active = active;
338 }
339 }
340
341 return;
342 }
343
344 static char *
345 acpitz_celcius_string(int dk)
346 {
347 static char buf[10];
348 int dc;
349
350 dc = abs(dk - ATZ_ZEROC);
351 snprintf(buf, sizeof(buf), "%s%d.%d", (dk >= ATZ_ZEROC)?"":"-",
352 dc / 10, dc % 10);
353
354 return buf;
355 }
356
357 static void
358 acpitz_print_status(device_t dv)
359 {
360 struct acpitz_softc *sc = device_private(dv);
361
362 printf("%s: zone temperature is now %sC\n", device_xname(dv),
363 acpitz_celcius_string(sc->sc_zone.tmp));
364 if (sc->sc_have_fan) {
365 printf("%s: fan rpm %u\n", device_xname(dv),
366 sc->sc_zone.fancurrent);
367 }
368
369 return;
370 }
371
372 static ACPI_STATUS
373 acpitz_switch_cooler(ACPI_OBJECT *obj, void *arg)
374 {
375 ACPI_HANDLE cooler;
376 ACPI_STATUS rv;
377 int pwr_state, flag;
378
379 flag = *(int *)arg;
380
381 if (flag)
382 pwr_state = ACPI_STATE_D0;
383 else
384 pwr_state = ACPI_STATE_D3;
385
386 rv = acpi_eval_reference_handle(obj, &cooler);
387 if (ACPI_FAILURE(rv)) {
388 aprint_error("%s: failed to get handle\n", __func__);
389 return rv;
390 }
391
392 rv = acpi_pwr_switch_consumer(cooler, pwr_state);
393 if (rv != AE_BAD_PARAMETER && ACPI_FAILURE(rv))
394 aprint_error("%s: failed to change state for %s: %s\n",
395 __func__, acpi_name(cooler), AcpiFormatException(rv));
396
397 return AE_OK;
398 }
399
400 /*
401 * acpitz_power_zone:
402 * power on or off the i:th part of the zone zone
403 */
404 static void
405 acpitz_power_zone(struct acpitz_softc *sc, int i, int on)
406 {
407 KASSERT(i >= 0 && i < ATZ_NLEVELS);
408
409 acpi_foreach_package_object(sc->sc_zone.al[i].Pointer,
410 acpitz_switch_cooler, &on);
411 }
412
413
414 /*
415 * acpitz_power_off:
416 * power off parts of the zone
417 */
418 static void
419 acpitz_power_off(struct acpitz_softc *sc)
420 {
421 int i;
422
423 for (i = 0 ; i < ATZ_NLEVELS; i++) {
424 if (sc->sc_zone.al[i].Pointer == NULL)
425 continue;
426 acpitz_power_zone(sc, i, 0);
427 }
428 sc->sc_active = ATZ_ACTIVE_NONE;
429 sc->sc_flags &= ~(ATZ_F_CRITICAL|ATZ_F_HOT|ATZ_F_PASSIVE);
430 }
431
432 static void
433 acpitz_get_zone(void *opaque, int verbose)
434 {
435 device_t dv = opaque;
436 struct acpitz_softc *sc = device_private(dv);
437 ACPI_STATUS rv;
438 char buf[8];
439 int i, valid_levels;
440
441 if (!sc->sc_first) {
442 acpitz_power_off(sc);
443
444 for (i = 0; i < ATZ_NLEVELS; i++) {
445 if (sc->sc_zone.al[i].Pointer != NULL)
446 ACPI_FREE(sc->sc_zone.al[i].Pointer);
447 sc->sc_zone.al[i].Pointer = NULL;
448 }
449 }
450
451 valid_levels = 0;
452
453 for (i = 0; i < ATZ_NLEVELS; i++) {
454 ACPI_OBJECT *obj;
455
456 snprintf(buf, sizeof(buf), "_AC%d", i);
457 if (acpitz_get_integer(dv, buf, &sc->sc_zone.ac[i]))
458 continue;
459
460 snprintf(buf, sizeof(buf), "_AL%d", i);
461 rv = acpi_eval_struct(sc->sc_devnode->ad_handle, buf,
462 &sc->sc_zone.al[i]);
463 if (ACPI_FAILURE(rv)) {
464 sc->sc_zone.al[i].Pointer = NULL;
465 continue;
466 }
467
468 obj = sc->sc_zone.al[i].Pointer;
469 if (obj != NULL) {
470 if (obj->Type != ACPI_TYPE_PACKAGE) {
471 aprint_error("%d not package\n", i);
472 ACPI_FREE(obj);
473 sc->sc_zone.al[i].Pointer = NULL;
474 continue;
475 }
476 }
477
478 if (sc->sc_first)
479 aprint_normal(" active cooling level %d: %sC", i,
480 acpitz_celcius_string(sc->sc_zone.ac[i]));
481
482 valid_levels++;
483 }
484
485 acpitz_get_integer(dv, "_TMP", &sc->sc_zone.tmp);
486 acpitz_get_integer(dv, "_CRT", &sc->sc_zone.crt);
487 acpitz_get_integer(dv, "_HOT", &sc->sc_zone.hot);
488 acpitz_get_integer(dv, "_PSV", &sc->sc_zone.psv);
489 acpitz_get_integer(dv, "_TC1", &sc->sc_zone.tc1);
490 acpitz_get_integer(dv, "_TC2", &sc->sc_zone.tc2);
491
492 #if 0
493 sc->sc_zone.psl.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
494 sc->sc_zone.psl.Pointer = NULL;
495 AcpiEvaluateObject(sc->sc_devnode->ad_handle,
496 "_PSL", NULL, &sc->sc_zone.psl);
497 #endif
498
499 /* ACPI spec: If _RTV is not present or present and zero,
500 * values are absolute. */
501 acpitz_get_integer(dv, "_RTV", &sc->sc_zone.rtv);
502 if (sc->sc_zone.rtv == ATZ_TMP_INVALID)
503 sc->sc_zone.rtv = 0;
504
505
506 acpitz_sane_temp(&sc->sc_zone.tmp);
507 acpitz_sane_temp(&sc->sc_zone.crt);
508 acpitz_sane_temp(&sc->sc_zone.hot);
509 acpitz_sane_temp(&sc->sc_zone.psv);
510
511 if (verbose != 0) {
512 aprint_verbose_dev(dv, "");
513
514 if (sc->sc_zone.crt != ATZ_TMP_INVALID)
515 aprint_verbose("critical %s C",
516 acpitz_celcius_string(sc->sc_zone.crt));
517
518 if (sc->sc_zone.hot != ATZ_TMP_INVALID)
519 aprint_verbose(" hot %s C",
520 acpitz_celcius_string(sc->sc_zone.hot));
521
522 if (sc->sc_zone.psv != ATZ_TMP_INVALID)
523 aprint_normal(" passive %s C",
524 acpitz_celcius_string(sc->sc_zone.psv));
525 }
526
527 if (valid_levels == 0) {
528 sc->sc_flags |= ATZ_F_PASSIVEONLY;
529
530 if (sc->sc_first)
531 aprint_verbose(", passive cooling");
532 }
533
534 if (verbose != 0)
535 aprint_verbose("\n");
536
537 for (i = 0; i < ATZ_NLEVELS; i++)
538 acpitz_sane_temp(&sc->sc_zone.ac[i]);
539
540 acpitz_power_off(sc);
541 sc->sc_first = 0;
542 }
543
544 static void
545 acpitz_notify_handler(ACPI_HANDLE hdl, uint32_t notify, void *opaque)
546 {
547 device_t dv = opaque;
548 ACPI_OSD_EXEC_CALLBACK func = NULL;
549 const char *name;
550 ACPI_STATUS rv;
551
552 switch (notify) {
553 case ACPI_NOTIFY_ThermalZoneStatusChanged:
554 func = acpitz_get_status;
555 name = "status check";
556 break;
557 case ACPI_NOTIFY_ThermalZoneTripPointsChanged:
558 case ACPI_NOTIFY_DeviceListsChanged:
559 func = acpitz_get_zone_quiet;
560 name = "get zone";
561 break;
562 default:
563 aprint_debug_dev(dv,
564 "received unhandled notify message 0x%x\n", notify);
565 return;
566 }
567
568 KASSERT(func != NULL);
569
570 rv = AcpiOsExecute(OSL_NOTIFY_HANDLER, func, dv);
571 if (ACPI_FAILURE(rv))
572 aprint_debug_dev(dv, "unable to queue %s\n", name);
573 }
574
575 static void
576 acpitz_sane_temp(uint32_t *tmp)
577 {
578 /* Sane temperatures are beteen 0 and 150 C */
579 if (*tmp < ATZ_ZEROC || *tmp > ATZ_ZEROC + 1500)
580 *tmp = ATZ_TMP_INVALID;
581 }
582
583 static int
584 acpitz_get_integer(device_t dv, const char *cm, uint32_t *val)
585 {
586 struct acpitz_softc *sc = device_private(dv);
587 ACPI_STATUS rv;
588 ACPI_INTEGER tmp;
589
590 rv = acpi_eval_integer(sc->sc_devnode->ad_handle, cm, &tmp);
591
592 if (ACPI_FAILURE(rv)) {
593 *val = ATZ_TMP_INVALID;
594
595 if (rv != AE_NOT_FOUND)
596 aprint_debug_dev(dv, "failed to evaluate %s: %s\n",
597 cm, AcpiFormatException(rv));
598
599 return 1;
600 }
601
602 *val = tmp;
603
604 return 0;
605 }
606
607 static int
608 acpitz_get_fanspeed(device_t dv,
609 uint32_t *fanmin, uint32_t *fanmax, uint32_t *fancurrent)
610 {
611 struct acpitz_softc *sc = device_private(dv);
612 ACPI_STATUS rv;
613 ACPI_HANDLE handle;
614 ACPI_INTEGER fmin, fmax, fcurr;
615 int rc = 0;
616
617 handle = sc->sc_devnode->ad_handle;
618 rv = acpi_eval_integer(handle, "FMIN", &fmin);
619 if (ACPI_FAILURE(rv)) {
620 fmin = ATZ_TMP_INVALID;
621 rc = 1;
622 }
623 rv = acpi_eval_integer(handle, "FMAX", &fmax);
624 if (ACPI_FAILURE(rv)) {
625 fmax = ATZ_TMP_INVALID;
626 rc = 1;
627 }
628 rv = acpi_eval_integer(handle, "FRSP", &fcurr);
629 if (ACPI_FAILURE(rv)) {
630 fcurr = ATZ_TMP_INVALID;
631 rc = 1;
632 }
633
634 if (fanmin)
635 *fanmin = fmin;
636 if (fanmax)
637 *fanmax = fmax;
638 if (fancurrent)
639 *fancurrent = fcurr;
640 return rc;
641 }
642
643 #ifdef notyet
644 static ACPI_STATUS
645 acpitz_set_fanspeed(device_t dv, uint32_t fanspeed)
646 {
647 struct acpitz_softc *sc = device_private(dv);
648 ACPI_STATUS rv;
649 ACPI_HANDLE handle;
650 handle = sc->sc_devnode->ad_handle;
651
652 rv = acpi_eval_set_integer(handle, "FSSP", fanspeed);
653 if (ACPI_FAILURE(rv))
654 aprint_debug_dev(dv, "failed to set fanspeed to %u rpm: %s\n",
655 fanspeed, AcpiFormatException(rv));
656 return rv;
657 }
658 #endif
659
660 static void
661 acpitz_tick(void *opaque)
662 {
663 device_t dv = opaque;
664 struct acpitz_softc *sc = device_private(dv);
665
666 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpitz_get_status, dv);
667
668 callout_schedule(&sc->sc_callout, sc->sc_zone.tzp * hz / 10);
669 }
670
671 static void
672 acpitz_init_envsys(device_t dv)
673 {
674 struct acpitz_softc *sc = device_private(dv);
675
676 sc->sc_sme = sysmon_envsys_create();
677 sc->sc_sme->sme_get_limits = acpitz_get_limits;
678 sc->sc_sme->sme_cookie = sc;
679 sc->sc_sme->sme_name = device_xname(dv);
680 sc->sc_sme->sme_flags = SME_DISABLE_REFRESH;
681
682 sc->sc_temp_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FMONNOTSUPP;
683 sc->sc_temp_sensor.units = ENVSYS_STEMP;
684 strlcpy(sc->sc_temp_sensor.desc,
685 sc->sc_zone.name, sizeof(sc->sc_temp_sensor.desc));
686 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_temp_sensor))
687 goto out;
688
689 if (sc->sc_have_fan) {
690 sc->sc_fan_sensor.flags =
691 ENVSYS_FMONLIMITS | ENVSYS_FMONNOTSUPP;
692 sc->sc_fan_sensor.units = ENVSYS_SFANRPM;
693 strlcpy(sc->sc_fan_sensor.desc,
694 "FAN", sizeof(sc->sc_fan_sensor.desc));
695 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_fan_sensor))
696 /* ignore error because fan sensor is optional */
697 aprint_error_dev(dv, "unable to attach fan sensor\n");
698 }
699
700 /* hook into sysmon */
701 if (sysmon_envsys_register(sc->sc_sme) == 0)
702 return;
703
704 out:
705 aprint_error_dev(dv, "unable to register with sysmon\n");
706 sysmon_envsys_destroy(sc->sc_sme);
707 }
708
709 static void
710 acpitz_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
711 sysmon_envsys_lim_t *limits, uint32_t *props)
712 {
713 struct acpitz_softc *sc = sme->sme_cookie;
714 int i;
715
716 switch (edata->units) {
717 case ENVSYS_STEMP:
718 *props = 0;
719 if (sc->sc_zone.hot != ATZ_TMP_INVALID) {
720 *props |= PROP_CRITMAX;
721 limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.hot);
722 } else if (sc->sc_zone.crt != ATZ_TMP_INVALID) {
723 *props |= PROP_CRITMAX;
724 limits->sel_critmax = ATZ2UKELVIN(sc->sc_zone.crt);
725 }
726 for (i = 0; i < ATZ_NLEVELS; i++) {
727 if (sc->sc_zone.ac[i] != ATZ_TMP_INVALID) {
728 limits->sel_warnmax =
729 ATZ2UKELVIN(sc->sc_zone.ac[i]);
730 *props |= PROP_WARNMAX;
731 break;
732 }
733 }
734 break;
735
736 case ENVSYS_SFANRPM:
737 *props = 0;
738 if (sc->sc_zone.fanmin != ATZ_TMP_INVALID) {
739 *props |= PROP_WARNMIN;
740 limits->sel_warnmin = sc->sc_zone.fanmin;
741 sc->sc_fan_sensor.flags |= ENVSYS_FVALID_MIN;
742 }
743 if (sc->sc_zone.fanmax != ATZ_TMP_INVALID) {
744 *props |= PROP_WARNMAX;
745 limits->sel_warnmax = sc->sc_zone.fanmax;
746 sc->sc_fan_sensor.flags |= ENVSYS_FVALID_MAX;
747 }
748 break;
749 }
750 }
751