diff options
author | Can Erkin Acar <canacar@cvs.openbsd.org> | 2006-05-19 09:24:33 +0000 |
---|---|---|
committer | Can Erkin Acar <canacar@cvs.openbsd.org> | 2006-05-19 09:24:33 +0000 |
commit | d86af03711cbeb38b139bb2bd6d3711563d08684 (patch) | |
tree | 965314180bdbf9606428f51978f50c167afd1e04 /sys/dev/acpi | |
parent | 29ec8c91f131fd1610e4bf00eee2e50b4fbd0a8b (diff) |
Minimal thermal zone driver. Monitors thermal zone temperature,
shuts down the system if the 'critical temperature' is reached.
ok marco@
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r-- | sys/dev/acpi/acpi.c | 26 | ||||
-rw-r--r-- | sys/dev/acpi/acpitz.c | 235 | ||||
-rw-r--r-- | sys/dev/acpi/files.acpi | 7 |
3 files changed, 266 insertions, 2 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 9c4743b6383..d7242d908fc 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.48 2006/04/11 02:36:49 marco Exp $ */ +/* $OpenBSD: acpi.c,v 1.49 2006/05/19 09:24:32 canacar Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -59,6 +59,7 @@ void acpi_write_pmreg(struct acpi_softc *, int, int); void acpi_foundpss(struct aml_node *, void *); void acpi_foundhid(struct aml_node *, void *); +void acpi_foundtmp(struct aml_node *, void *); void acpi_inidev(struct aml_node *, void *); int acpi_loadtables(struct acpi_softc *, struct acpi_rsdp *); @@ -472,6 +473,26 @@ acpi_inidev(struct aml_node *node, void *arg) } void +acpi_foundtmp(struct aml_node *node, void *arg) +{ + struct acpi_softc *sc = (struct acpi_softc *)arg; + struct device *self = (struct device *)arg; + const char *dev; + struct acpi_attach_args aaa; + + dnprintf(10, "found thermal zone entry: %s\n", node->parent->name); + + memset(&aaa, 0, sizeof(aaa)); + aaa.aaa_iot = sc->sc_iot; + aaa.aaa_memt = sc->sc_memt; + aaa.aaa_node = node->parent; + aaa.aaa_dev = dev; + aaa.aaa_name = "acpitz"; + + config_found(self, &aaa, acpi_print); +} + +void acpi_foundpss(struct aml_node *node, void *arg) { struct acpi_softc *sc = (struct acpi_softc *)arg; @@ -750,6 +771,9 @@ acpi_attach(struct device *parent, struct device *self, void *aux) /* attach devices found in dsdt */ aml_find_node(aml_root.child, "_PSS", acpi_foundpss, sc); + /* attach devices found in dsdt */ + aml_find_node(aml_root.child, "_TMP", acpi_foundtmp, sc); + /* Setup threads */ sc->sc_thread = malloc(sizeof(struct acpi_thread), M_DEVBUF, M_WAITOK); sc->sc_thread->sc = sc; diff --git a/sys/dev/acpi/acpitz.c b/sys/dev/acpi/acpitz.c new file mode 100644 index 00000000000..9cdf7ce1b3a --- /dev/null +++ b/sys/dev/acpi/acpitz.c @@ -0,0 +1,235 @@ +/* $OpenBSD: acpitz.c,v 1.1 2006/05/19 09:24:32 canacar Exp $ */ +/* + * Copyright (c) 2006 Can Erkin Acar <canacar@openbsd.org> + * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/signalvar.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/rwlock.h> +#include <sys/malloc.h> + +#include <machine/bus.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#include <dev/acpi/acpidev.h> +#include <dev/acpi/amltypes.h> +#include <dev/acpi/dsdt.h> + +#include <sys/sensors.h> + +struct acpitz_softc { + struct device sc_dev; + + struct acpi_softc *sc_acpi; + struct aml_node *sc_devnode; + + struct rwlock sc_lock; + u_int64_t sc_tmp; + u_int64_t sc_crt; + struct sensor sc_sens; +}; + +int acpitz_match(struct device *, void *, void *); +void acpitz_attach(struct device *, struct device *, void *); +void acpitz_refresh(void *); +int acpitz_gettmp(struct acpitz_softc *); +int acpitz_notify(struct aml_node *, int, void *); + +struct cfattach acpitz_ca = { + sizeof(struct acpitz_softc), acpitz_match, acpitz_attach +}; + +struct cfdriver acpitz_cd = { + NULL, "acpitz", DV_DULL +}; + +void acpitz_monitor(struct acpitz_softc *); +void acpitz_refresh(void *); +int acpitz_getbif(struct acpitz_softc *); +int acpitz_getbst(struct acpitz_softc *); +int acpitz_notify(struct aml_node *, int, void *); +int acpitz_getcrt(struct acpitz_softc *); + +int +acpitz_match(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aa = aux; + struct cfdata *cf = match; + + /* sanity */ + if (aa->aaa_name == NULL || + strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || + aa->aaa_table != NULL) + return (0); + + if (aa->aaa_node->opcode != AMLOP_THERMALZONE) + return (0); + + return (1); +} + +void +acpitz_attach(struct device *parent, struct device *self, void *aux) +{ + struct acpitz_softc *sc = (struct acpitz_softc *)self; + struct acpi_attach_args *aa = aux; + struct aml_value res, env; + + sc->sc_acpi = (struct acpi_softc *)parent; + sc->sc_devnode = aa->aaa_node->child; + + rw_init(&sc->sc_lock, "acpitz"); + + memset(&res, 0, sizeof(res)); + memset(&env, 0, sizeof(env)); + + if (acpitz_gettmp(sc)) { + printf(", failed to read _TMP"); + return; + } + + if (acpitz_getcrt(sc)) { + printf(", no critical temperature defined!"); + sc->sc_crt = 0; + } else + printf(", critical temperature: %u degC", + (unsigned)(sc->sc_crt - 2732) / 10); + + aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev, + acpitz_notify, sc); + + memset(&sc->sc_sens, 0, sizeof(sc->sc_sens)); + strlcpy(sc->sc_sens.device, DEVNAME(sc), sizeof(sc->sc_sens.device)); + strlcpy(sc->sc_sens.desc, "zone temperature", + sizeof(sc->sc_sens.desc)); + sc->sc_sens.type = SENSOR_TEMP; + sensor_add(&sc->sc_sens); + sc->sc_sens.value = 0; + + if (sensor_task_register(sc, acpitz_refresh, 10)) + printf(", unable to register update task"); + + printf("\n"); +} + +void +acpitz_refresh(void *arg) +{ + struct acpitz_softc *sc = arg; + extern int acpi_s5; + + dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc), + sc->sc_devnode->parent->name); + + if (acpitz_gettmp(sc)) { + dnprintf(30, "%s: %s: failed to read temp!\n", DEVNAME(sc), + sc->sc_devnode->parent->name); + sc->sc_tmp = 0; /* XXX */ + } + + if (sc->sc_crt && sc->sc_crt <= sc->sc_tmp) { + /* Do critical shutdown */ + printf("%s: Critical temperature, shutting down!\n", + DEVNAME(sc)); + acpi_s5 = 1; + psignal(initproc, SIGUSR1); + /* NOTREACHED */ + } + + rw_enter_write(&sc->sc_lock); + + sc->sc_sens.value = sc->sc_tmp * 100000; + + rw_exit_write(&sc->sc_lock); +} + +int +acpitz_gettmp(struct acpitz_softc *sc) +{ + struct aml_value res, env; + int rv = 1; + + rw_enter_write(&sc->sc_lock); + + memset(&res, 0, sizeof(res)); + memset(&env, 0, sizeof(env)); + + if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_TMP", &res, &env)) { + dnprintf(10, "%s: no _TMP\n", DEVNAME(sc)); + goto out; + } + + sc->sc_tmp = aml_val2int(NULL, &res); + rv = 0; + out: + rw_exit_write(&sc->sc_lock); + return (rv); +} + +int +acpitz_getcrt(struct acpitz_softc *sc) +{ + struct aml_value res, env; + int rv = 1; + + rw_enter_write(&sc->sc_lock); + + memset(&res, 0, sizeof(res)); + memset(&env, 0, sizeof(env)); + + if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_CRT", &res, &env)) { + dnprintf(10, "%s: no _CRT\n", DEVNAME(sc)); + goto out; + } + + sc->sc_crt = aml_val2int(NULL, &res); + rv = 0; + out: + rw_exit_write(&sc->sc_lock); + return (rv); +} + + +int +acpitz_notify(struct aml_node *node, int notify_type, void *arg) +{ + struct acpitz_softc *sc = arg; + u_int64_t crt; + + dnprintf(10, "%s notify: %.2x %s\n", DEVNAME(sc), notify_type, + sc->sc_devnode->parent->name); + + switch (notify_type) { + case 0x81: /* Operating Points changed */ + crt = sc->sc_crt; + acpitz_getcrt(sc); + if (crt != sc->sc_crt) + printf("%s: critical temperature: %u degC", + DEVNAME(sc), + (unsigned)(sc->sc_crt - 2732) / 10); + break; + default: + break; + } + + acpitz_refresh(sc); + + return (0); +} diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi index 56e4d00cb4e..70c35c2ec5b 100644 --- a/sys/dev/acpi/files.acpi +++ b/sys/dev/acpi/files.acpi @@ -1,4 +1,4 @@ -# $OpenBSD: files.acpi,v 1.10 2006/03/06 03:13:42 marco Exp $ +# $OpenBSD: files.acpi,v 1.11 2006/05/19 09:24:32 canacar Exp $ # # Config file and device description for machine-independent ACPI code. # Included by ports that need it. @@ -40,3 +40,8 @@ file dev/acpi/acpicpu.c acpicpu device acpihpet attach acpihpet at acpi file dev/acpi/acpihpet.c acpihpet + +# Thermal Zone +device acpitz +attach acpitz at acpi +file dev/acpi/acpitz.c acpitz |