1 /* $NetBSD: acpi_tz.c,v 1.53 2010/01/01 15:55:30 pgoyette Exp $ */
4 * Copyright (c) 2003 Jared D. McNeill <jmcneill@invisible.ca>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 * ACPI Thermal Zone driver
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: acpi_tz.c,v 1.53 2010/01/01 15:55:30 pgoyette Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/errno.h>
39 #include <sys/ioctl.h>
40 #include <sys/syslog.h>
41 #include <sys/device.h>
42 #include <sys/callout.h>
44 #include <dev/sysmon/sysmonvar.h>
46 #include <dev/acpi/acpica.h>
47 #include <dev/acpi/acpireg.h>
48 #include <dev/acpi/acpivar.h>
50 #define _COMPONENT ACPI_TZ_COMPONENT
51 ACPI_MODULE_NAME ("acpi_tz")
54 #define ATZ_F_VERBOSE 0x01 /* show events to console */
55 #define ATZ_F_CRITICAL 0x02 /* zone critical */
56 #define ATZ_F_HOT 0x04 /* zone hot */
57 #define ATZ_F_PASSIVE 0x08 /* zone passive cooling */
58 #define ATZ_F_PASSIVEONLY 0x10 /* zone is passive cooling only */
60 /* no active cooling level */
61 #define ATZ_ACTIVE_NONE -1
64 #define ATZ_TZP_RATE 300 /* default if no _TZP CM present (30 secs) */
65 #define ATZ_NLEVELS 10 /* number of cooling levels, from ACPI spec */
66 #define ATZ_ZEROC 2732 /* 0C in tenths degrees Kelvin */
67 #define ATZ_TMP_INVALID 0xffffffff /* invalid temperature */
68 #define ATZ_ZONE_EXPIRE 9000 /* zone info refetch interval (15min) */
71 #define ATZ_SENSOR_TEMP 0 /* thermal zone temperature */
73 static int acpitz_match(device_t
, cfdata_t
, void *);
74 static void acpitz_attach(device_t
, device_t
, void *);
77 * ACPI Temperature Zone information. Note all temperatures are reported
78 * in tenths of degrees Kelvin, and that the ACPI specification assumes
79 * that K = C + 273.2 rather than the nominal 273.15 used by envsys(4).
80 * So define an appropriate conversion.
83 #define ATZ2UKELVIN(t) ((t) * 100000 - 50000)
86 /* Active cooling temperature threshold */
87 UINT32 ac
[ATZ_NLEVELS
];
88 /* Package of references to all active cooling devices for a level */
89 ACPI_BUFFER al
[ATZ_NLEVELS
];
90 /* Critical temperature threshold for system shutdown */
92 /* Critical temperature threshold for S4 sleep */
94 /* Package of references to processor objects for passive cooling */
96 /* Conveys if temperatures are absolute or relative values. */
98 /* Passive cooling temperature threshold */
100 /* Thermal constants for use in passive cooling formulas */
102 /* Current temperature of the thermal zone */
104 /* Thermal sampling period for passive cooling, in tenths of seconds */
106 /* Package of references to devices in this TZ (optional) */
108 /* Recommended TZ polling frequency, in tenths of seconds */
110 /* Thermal zone name */
112 /* FAN min, max, current rpms */
113 UINT32 fanmin
, fanmax
, fancurrent
;
116 struct acpitz_softc
{
117 struct acpi_devnode
*sc_devnode
;
118 struct acpitz_zone sc_zone
;
119 struct callout sc_callout
;
120 struct sysmon_envsys
*sc_sme
;
121 envsys_data_t sc_temp_sensor
;
122 envsys_data_t sc_fan_sensor
;
123 int sc_active
; /* active cooling level */
125 int sc_rate
; /* tz poll rate */
129 int sc_have_fan
; /* FAN sensor is optional */
132 static void acpitz_get_status(void *);
133 static void acpitz_get_zone(void *, int);
134 static void acpitz_get_zone_quiet(void *);
135 static char *acpitz_celcius_string(int);
136 static void acpitz_print_status(device_t
);
137 static void acpitz_power_off(struct acpitz_softc
*);
138 static void acpitz_power_zone(struct acpitz_softc
*, int, int);
139 static void acpitz_sane_temp(UINT32
*tmp
);
141 acpitz_switch_cooler(ACPI_OBJECT
*, void *);
142 static void acpitz_notify_handler(ACPI_HANDLE
, UINT32
, void *);
143 static int acpitz_get_integer(device_t
, const char *, UINT32
*);
144 static void acpitz_tick(void *);
145 static void acpitz_init_envsys(device_t
);
146 static void acpitz_get_limits(struct sysmon_envsys
*, envsys_data_t
*,
147 sysmon_envsys_lim_t
*);
148 static int acpitz_get_fanspeed(device_t
, UINT32
*, UINT32
*, UINT32
*);
151 acpitz_set_fanspeed(device_t
, UINT32
);
154 CFATTACH_DECL_NEW(acpitz
, sizeof(struct acpitz_softc
), acpitz_match
,
155 acpitz_attach
, NULL
, NULL
);
158 * acpitz_match: autoconf(9) match routine
161 acpitz_match(device_t parent
, cfdata_t match
, void *aux
)
163 struct acpi_attach_args
*aa
= aux
;
165 if (aa
->aa_node
->ad_type
!= ACPI_TYPE_THERMAL
)
172 * acpitz_attach: autoconf(9) attach routine
175 acpitz_attach(device_t parent
, device_t self
, void *aux
)
177 struct acpitz_softc
*sc
= device_private(self
);
178 struct acpi_attach_args
*aa
= aux
;
183 sc
->sc_flags
= ATZ_F_VERBOSE
;
185 sc
->sc_devnode
= aa
->aa_node
;
189 rv
= acpi_eval_integer(sc
->sc_devnode
->ad_handle
, "_TZP", &v
);
190 if (ACPI_FAILURE(rv
))
191 sc
->sc_zone
.tzp
= ATZ_TZP_RATE
;
195 aprint_debug(" sample rate %d.%ds\n",
196 sc
->sc_zone
.tzp
/ 10, sc
->sc_zone
.tzp
% 10);
198 /* XXX a value of 0 means "polling is not necessary" */
199 if (sc
->sc_zone
.tzp
== 0)
200 sc
->sc_zone
.tzp
= ATZ_TZP_RATE
;
202 sc
->sc_zone_expire
= ATZ_ZONE_EXPIRE
/ sc
->sc_zone
.tzp
;
205 if (acpitz_get_fanspeed(self
,
206 &sc
->sc_zone
.fanmin
, &sc
->sc_zone
.fanmax
, &sc
->sc_zone
.fancurrent
)
210 rv
= acpi_eval_string(sc
->sc_devnode
->ad_handle
,
211 "REGN", &sc
->sc_zone
.name
);
212 if (ACPI_FAILURE(rv
))
213 sc
->sc_zone
.name
= __UNCONST("temperature");
214 acpitz_get_zone(self
, 1);
215 acpitz_get_status(self
);
217 rv
= AcpiInstallNotifyHandler(sc
->sc_devnode
->ad_handle
,
218 ACPI_SYSTEM_NOTIFY
, acpitz_notify_handler
, self
);
219 if (ACPI_FAILURE(rv
)) {
220 aprint_error(": unable to install SYSTEM NOTIFY handler: %s\n",
221 AcpiFormatException(rv
));
225 callout_init(&sc
->sc_callout
, CALLOUT_MPSAFE
);
226 callout_setfunc(&sc
->sc_callout
, acpitz_tick
, self
);
228 acpitz_init_envsys(self
);
230 if (!pmf_device_register(self
, NULL
, NULL
))
231 aprint_error(": couldn't establish power handler\n");
233 callout_schedule(&sc
->sc_callout
, sc
->sc_zone
.tzp
* hz
/ 10);
237 acpitz_get_zone_quiet(void *opaque
)
239 acpitz_get_zone(opaque
, 0);
243 acpitz_get_status(void *opaque
)
245 device_t dv
= opaque
;
246 struct acpitz_softc
*sc
= device_private(dv
);
249 UINT32 fmin
, fmax
, fcurrent
;
251 sc
->sc_zone_expire
--;
252 if (sc
->sc_zone_expire
<= 0) {
253 sc
->sc_zone_expire
= ATZ_ZONE_EXPIRE
/ sc
->sc_zone
.tzp
;
254 if (sc
->sc_flags
& ATZ_F_VERBOSE
)
255 printf("%s: force refetch zone\n", device_xname(dv
));
256 acpitz_get_zone(dv
, 0);
259 if (acpitz_get_integer(dv
, "_TMP", &tmp
)) {
260 aprint_error_dev(dv
, "failed to evaluate _TMP\n");
264 sc
->sc_zone
.prevtmp
= sc
->sc_zone
.tmp
;
265 sc
->sc_zone
.tmp
= tmp
;
267 sc
->sc_zone
.prevtmp
= tmp
;
268 /* XXX sanity check for tmp here? */
270 if (acpitz_get_fanspeed(dv
, &fmin
, &fmax
, &fcurrent
) == 0) {
271 if (fcurrent
!= ATZ_TMP_INVALID
)
272 sc
->sc_zone
.fancurrent
= fcurrent
;
276 * The temperature unit for envsys(4) is microKelvin, so convert to
277 * that from ACPI's microKelvin. Also, the ACPI specification assumes
278 * that K = C + 273.2 rather than the nominal 273.15 used by envsys(4),
279 * so we correct for that too.
281 sc
->sc_temp_sensor
.value_cur
= ATZ2UKELVIN(sc
->sc_zone
.tmp
);
282 sc
->sc_temp_sensor
.state
= ENVSYS_SVALID
;
284 sc
->sc_fan_sensor
.value_cur
= sc
->sc_zone
.fancurrent
;
285 sc
->sc_fan_sensor
.state
= ENVSYS_SVALID
;
287 if (sc
->sc_flags
& ATZ_F_VERBOSE
)
288 acpitz_print_status(dv
);
290 if (sc
->sc_flags
& ATZ_F_PASSIVEONLY
) {
291 /* Passive Cooling: XXX not yet */
296 /* temperature threshold: _AC0 > ... > _AC9 */
297 active
= ATZ_ACTIVE_NONE
;
298 for (i
= ATZ_NLEVELS
- 1; i
>= 0; i
--) {
299 if (sc
->sc_zone
.ac
[i
] == ATZ_TMP_INVALID
)
302 /* we want to keep highest cooling mode in 'active' */
303 if (sc
->sc_zone
.ac
[i
] <= tmp
)
307 flags
= sc
->sc_flags
&
308 ~(ATZ_F_CRITICAL
|ATZ_F_HOT
|ATZ_F_PASSIVE
);
309 if (sc
->sc_zone
.psv
!= ATZ_TMP_INVALID
&&
310 tmp
>= sc
->sc_zone
.psv
)
311 flags
|= ATZ_F_PASSIVE
;
312 if (sc
->sc_zone
.hot
!= ATZ_TMP_INVALID
&&
313 tmp
>= sc
->sc_zone
.hot
)
315 if (sc
->sc_zone
.crt
!= ATZ_TMP_INVALID
&&
316 tmp
>= sc
->sc_zone
.crt
)
317 flags
|= ATZ_F_CRITICAL
;
319 if (flags
!= sc
->sc_flags
) {
320 int changed
= (sc
->sc_flags
^ flags
) & flags
;
321 sc
->sc_flags
= flags
;
322 if (changed
& ATZ_F_CRITICAL
) {
323 sc
->sc_temp_sensor
.state
= ENVSYS_SCRITOVER
;
325 "zone went critical at temp %sC\n",
326 acpitz_celcius_string(tmp
));
327 } else if (changed
& ATZ_F_HOT
) {
328 sc
->sc_temp_sensor
.state
= ENVSYS_SCRITOVER
;
330 "zone went hot at temp %sC\n",
331 acpitz_celcius_string(tmp
));
336 if (sc
->sc_active
!= active
) {
337 if (sc
->sc_active
!= ATZ_ACTIVE_NONE
)
338 acpitz_power_zone(sc
, sc
->sc_active
, 0);
340 if (active
!= ATZ_ACTIVE_NONE
) {
341 if (sc
->sc_flags
& ATZ_F_VERBOSE
)
342 printf("%s: active cooling level %u\n",
343 device_xname(dv
), active
);
344 acpitz_power_zone(sc
, active
, 1);
345 } else if (sc
->sc_flags
& ATZ_F_VERBOSE
)
346 printf("%s: no active cooling level\n",
349 sc
->sc_active
= active
;
357 acpitz_celcius_string(int dk
)
361 snprintf(buf
, sizeof(buf
), "%d.%d", (dk
- ATZ_ZEROC
) / 10,
362 (dk
- ATZ_ZEROC
) % 10);
368 acpitz_print_status(device_t dv
)
370 struct acpitz_softc
*sc
= device_private(dv
);
372 printf("%s: zone temperature is now %sC\n", device_xname(dv
),
373 acpitz_celcius_string(sc
->sc_zone
.tmp
));
374 if (sc
->sc_have_fan
) {
375 printf("%s: fan rpm %u\n", device_xname(dv
),
376 sc
->sc_zone
.fancurrent
);
383 acpitz_switch_cooler(ACPI_OBJECT
*obj
, void *arg
)
392 pwr_state
= ACPI_STATE_D0
;
394 pwr_state
= ACPI_STATE_D3
;
397 case ACPI_TYPE_LOCAL_REFERENCE
:
399 cooler
= obj
->Reference
.Handle
;
401 case ACPI_TYPE_STRING
:
402 rv
= AcpiGetHandle(NULL
, obj
->String
.Pointer
, &cooler
);
403 if (ACPI_FAILURE(rv
)) {
404 printf("acpitz_switch_cooler: "
405 "failed to get handler from %s\n",
406 obj
->String
.Pointer
);
411 printf("acpitz_switch_cooler: "
412 "unknown power type: %d\n", obj
->Type
);
416 rv
= acpi_pwr_switch_consumer(cooler
, pwr_state
);
417 if (rv
!= AE_BAD_PARAMETER
&& ACPI_FAILURE(rv
)) {
418 printf("acpitz_switch_cooler: "
419 "failed to change state for %s: %s\n",
420 acpi_name(obj
->Reference
.Handle
),
421 AcpiFormatException(rv
));
429 * power on or off the i:th part of the zone zone
432 acpitz_power_zone(struct acpitz_softc
*sc
, int i
, int on
)
434 KASSERT(i
>= 0 && i
< ATZ_NLEVELS
);
436 acpi_foreach_package_object(sc
->sc_zone
.al
[i
].Pointer
,
437 acpitz_switch_cooler
, &on
);
443 * power off parts of the zone
446 acpitz_power_off(struct acpitz_softc
*sc
)
450 for (i
= 0 ; i
< ATZ_NLEVELS
; i
++) {
451 if (sc
->sc_zone
.al
[i
].Pointer
== NULL
)
453 acpitz_power_zone(sc
, i
, 0);
455 sc
->sc_active
= ATZ_ACTIVE_NONE
;
456 sc
->sc_flags
&= ~(ATZ_F_CRITICAL
|ATZ_F_HOT
|ATZ_F_PASSIVE
);
460 acpitz_get_zone(void *opaque
, int verbose
)
462 device_t dv
= opaque
;
463 struct acpitz_softc
*sc
= device_private(dv
);
469 acpitz_power_off(sc
);
471 for (i
= 0; i
< ATZ_NLEVELS
; i
++) {
472 if (sc
->sc_zone
.al
[i
].Pointer
!= NULL
)
473 ACPI_FREE(sc
->sc_zone
.al
[i
].Pointer
);
474 sc
->sc_zone
.al
[i
].Pointer
= NULL
;
481 for (i
= 0; i
< ATZ_NLEVELS
; i
++) {
484 snprintf(buf
, sizeof(buf
), "_AC%d", i
);
485 if (acpitz_get_integer(dv
, buf
, &sc
->sc_zone
.ac
[i
]))
488 snprintf(buf
, sizeof(buf
), "_AL%d", i
);
489 rv
= acpi_eval_struct(sc
->sc_devnode
->ad_handle
, buf
,
491 if (ACPI_FAILURE(rv
)) {
492 sc
->sc_zone
.al
[i
].Pointer
= NULL
;
496 obj
= sc
->sc_zone
.al
[i
].Pointer
;
498 if (obj
->Type
!= ACPI_TYPE_PACKAGE
) {
499 aprint_error("%d not package\n", i
);
501 sc
->sc_zone
.al
[i
].Pointer
= NULL
;
507 aprint_normal(" active cooling level %d: %sC", i
,
508 acpitz_celcius_string(sc
->sc_zone
.ac
[i
]));
513 acpitz_get_integer(dv
, "_TMP", &sc
->sc_zone
.tmp
);
514 acpitz_get_integer(dv
, "_CRT", &sc
->sc_zone
.crt
);
515 acpitz_get_integer(dv
, "_HOT", &sc
->sc_zone
.hot
);
516 acpitz_get_integer(dv
, "_PSV", &sc
->sc_zone
.psv
);
517 acpitz_get_integer(dv
, "_TC1", &sc
->sc_zone
.tc1
);
518 acpitz_get_integer(dv
, "_TC2", &sc
->sc_zone
.tc2
);
521 sc
->sc_zone
.psl
.Length
= ACPI_ALLOCATE_LOCAL_BUFFER
;
522 sc
->sc_zone
.psl
.Pointer
= NULL
;
523 AcpiEvaluateObject(sc
->sc_devnode
->ad_handle
,
524 "_PSL", NULL
, &sc
->sc_zone
.psl
);
527 /* ACPI spec: If _RTV is not present or present and zero,
528 * values are absolute. */
529 acpitz_get_integer(dv
, "_RTV", &sc
->sc_zone
.rtv
);
530 if (sc
->sc_zone
.rtv
== ATZ_TMP_INVALID
)
534 acpitz_sane_temp(&sc
->sc_zone
.tmp
);
535 acpitz_sane_temp(&sc
->sc_zone
.crt
);
536 acpitz_sane_temp(&sc
->sc_zone
.hot
);
537 acpitz_sane_temp(&sc
->sc_zone
.psv
);
540 if (sc
->sc_zone
.crt
!= ATZ_TMP_INVALID
)
541 aprint_normal(" critical %sC",
542 acpitz_celcius_string(sc
->sc_zone
.crt
));
543 if (sc
->sc_zone
.hot
!= ATZ_TMP_INVALID
)
544 aprint_normal(" hot %sC",
545 acpitz_celcius_string(sc
->sc_zone
.hot
));
546 if (sc
->sc_zone
.psv
!= ATZ_TMP_INVALID
)
547 aprint_normal(" passive %sC",
548 acpitz_celcius_string(sc
->sc_zone
.tmp
));
551 if (valid_levels
== 0) {
552 sc
->sc_flags
|= ATZ_F_PASSIVEONLY
;
554 aprint_normal(", passive cooling");
559 for (i
= 0; i
< ATZ_NLEVELS
; i
++)
560 acpitz_sane_temp(&sc
->sc_zone
.ac
[i
]);
562 acpitz_power_off(sc
);
568 acpitz_notify_handler(ACPI_HANDLE hdl
, UINT32 notify
, void *opaque
)
570 device_t dv
= opaque
;
571 ACPI_OSD_EXEC_CALLBACK func
= NULL
;
576 case ACPI_NOTIFY_ThermalZoneStatusChanged
:
577 func
= acpitz_get_status
;
578 name
= "status check";
580 case ACPI_NOTIFY_ThermalZoneTripPointsChanged
:
581 case ACPI_NOTIFY_DeviceListsChanged
:
582 func
= acpitz_get_zone_quiet
;
587 "received unhandled notify message 0x%x\n", notify
);
591 KASSERT(func
!= NULL
);
593 rv
= AcpiOsExecute(OSL_NOTIFY_HANDLER
, func
, dv
);
594 if (ACPI_FAILURE(rv
))
595 aprint_debug_dev(dv
, "unable to queue %s\n", name
);
599 acpitz_sane_temp(UINT32
*tmp
)
601 /* Sane temperatures are beteen 0 and 150 C */
602 if (*tmp
< ATZ_ZEROC
|| *tmp
> ATZ_ZEROC
+ 1500)
603 *tmp
= ATZ_TMP_INVALID
;
607 acpitz_get_integer(device_t dv
, const char *cm
, UINT32
*val
)
609 struct acpitz_softc
*sc
= device_private(dv
);
613 rv
= acpi_eval_integer(sc
->sc_devnode
->ad_handle
, cm
, &tmp
);
614 if (ACPI_FAILURE(rv
)) {
616 aprint_debug_dev(dv
, "failed to evaluate %s: %s\n",
617 cm
, AcpiFormatException(rv
));
619 *val
= ATZ_TMP_INVALID
;
629 acpitz_get_fanspeed(device_t dv
,
630 UINT32
*fanmin
, UINT32
*fanmax
, UINT32
*fancurrent
)
632 struct acpitz_softc
*sc
= device_private(dv
);
635 ACPI_INTEGER fmin
, fmax
, fcurr
;
638 handle
= sc
->sc_devnode
->ad_handle
;
639 rv
= acpi_eval_integer(handle
, "FMIN", &fmin
);
640 if (ACPI_FAILURE(rv
)) {
641 fmin
= ATZ_TMP_INVALID
;
644 rv
= acpi_eval_integer(handle
, "FMAX", &fmax
);
645 if (ACPI_FAILURE(rv
)) {
646 fmax
= ATZ_TMP_INVALID
;
649 rv
= acpi_eval_integer(handle
, "FRSP", &fcurr
);
650 if (ACPI_FAILURE(rv
)) {
651 fcurr
= ATZ_TMP_INVALID
;
666 acpitz_set_fanspeed(device_t dv
, UINT32 fanspeed
)
668 struct acpitz_softc
*sc
= device_private(dv
);
671 handle
= sc
->sc_devnode
->ad_handle
;
673 rv
= acpi_eval_set_integer(handle
, "FSSP", fanspeed
);
674 if (ACPI_FAILURE(rv
))
675 aprint_debug_dev(dv
, "failed to set fanspeed to %u rpm: %s\n",
676 fanspeed
, AcpiFormatException(rv
));
682 acpitz_tick(void *opaque
)
684 device_t dv
= opaque
;
685 struct acpitz_softc
*sc
= device_private(dv
);
687 AcpiOsExecute(OSL_NOTIFY_HANDLER
, acpitz_get_status
, dv
);
689 callout_schedule(&sc
->sc_callout
, sc
->sc_zone
.tzp
* hz
/ 10);
693 acpitz_init_envsys(device_t dv
)
695 struct acpitz_softc
*sc
= device_private(dv
);
697 sc
->sc_sme
= sysmon_envsys_create();
698 sc
->sc_sme
->sme_get_limits
= acpitz_get_limits
;
699 sc
->sc_sme
->sme_cookie
= sc
;
700 sc
->sc_sme
->sme_name
= device_xname(dv
);
701 sc
->sc_sme
->sme_flags
= SME_DISABLE_REFRESH
;
703 sc
->sc_temp_sensor
.monitor
= true;
704 sc
->sc_temp_sensor
.flags
= ENVSYS_FMONLIMITS
| ENVSYS_FMONNOTSUPP
;
705 sc
->sc_temp_sensor
.units
= ENVSYS_STEMP
;
706 strlcpy(sc
->sc_temp_sensor
.desc
,
707 sc
->sc_zone
.name
, sizeof(sc
->sc_temp_sensor
.desc
));
708 if (sysmon_envsys_sensor_attach(sc
->sc_sme
, &sc
->sc_temp_sensor
))
711 if (sc
->sc_have_fan
) {
712 sc
->sc_fan_sensor
.monitor
= true;
713 sc
->sc_fan_sensor
.flags
=
714 ENVSYS_FMONLIMITS
| ENVSYS_FMONNOTSUPP
;
715 sc
->sc_fan_sensor
.units
= ENVSYS_SFANRPM
;
716 strlcpy(sc
->sc_fan_sensor
.desc
,
717 "FAN", sizeof(sc
->sc_fan_sensor
.desc
));
718 if (sysmon_envsys_sensor_attach(sc
->sc_sme
, &sc
->sc_fan_sensor
))
719 /* ignore error because fan sensor is optional */
720 aprint_error_dev(dv
, "unable to attach fan sensor\n");
723 /* hook into sysmon */
724 if (sysmon_envsys_register(sc
->sc_sme
) == 0)
728 aprint_error_dev(dv
, "unable to register with sysmon\n");
729 sysmon_envsys_destroy(sc
->sc_sme
);
733 acpitz_get_limits(struct sysmon_envsys
*sme
, envsys_data_t
*edata
,
734 sysmon_envsys_lim_t
*limits
)
736 struct acpitz_softc
*sc
= sme
->sme_cookie
;
739 switch (edata
->units
) {
741 limits
->sel_flags
= 0;
742 if (sc
->sc_zone
.hot
!= ATZ_TMP_INVALID
) {
743 limits
->sel_flags
|= PROP_CRITMAX
;
744 limits
->sel_critmax
= ATZ2UKELVIN(sc
->sc_zone
.hot
);
745 } else if (sc
->sc_zone
.crt
!= ATZ_TMP_INVALID
) {
746 limits
->sel_flags
|= PROP_CRITMAX
;
747 limits
->sel_critmax
= ATZ2UKELVIN(sc
->sc_zone
.crt
);
749 for (i
= 0; i
< ATZ_NLEVELS
; i
++) {
750 if (sc
->sc_zone
.ac
[i
] != ATZ_TMP_INVALID
) {
751 limits
->sel_warnmax
=
752 ATZ2UKELVIN(sc
->sc_zone
.ac
[i
]);
753 limits
->sel_flags
|= PROP_WARNMAX
;
760 limits
->sel_flags
= 0;
761 if (sc
->sc_zone
.fanmin
!= ATZ_TMP_INVALID
) {
762 limits
->sel_flags
|= PROP_WARNMIN
;
763 limits
->sel_warnmin
= sc
->sc_zone
.fanmin
;
764 sc
->sc_fan_sensor
.flags
|= ENVSYS_FVALID_MIN
;
766 if (sc
->sc_zone
.fanmax
!= ATZ_TMP_INVALID
) {
767 limits
->sel_flags
|= PROP_WARNMAX
;
768 limits
->sel_warnmax
= sc
->sc_zone
.fanmax
;
769 sc
->sc_fan_sensor
.flags
|= ENVSYS_FVALID_MAX
;