diff options
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/acpi/acpi.c | 5 | ||||
-rw-r--r-- | sys/dev/acpi/acpipwrres.c | 210 | ||||
-rw-r--r-- | sys/dev/acpi/files.acpi | 7 |
3 files changed, 220 insertions, 2 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index d67f471f3ef..86eb1722072 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.139 2009/06/03 00:36:59 pirofti Exp $ */ +/* $OpenBSD: acpi.c,v 1.140 2009/06/03 07:13:48 pirofti Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -1479,6 +1479,9 @@ acpi_add_device(struct aml_node *node, void *arg) case AML_OBJTYPE_THERMZONE: aaa.aaa_name = "acpitz"; break; + case AML_OBJTYPE_POWERRSRC: + aaa.aaa_name = "acpipwrres"; + break; default: return 0; } diff --git a/sys/dev/acpi/acpipwrres.c b/sys/dev/acpi/acpipwrres.c new file mode 100644 index 00000000000..5f71cb9f20d --- /dev/null +++ b/sys/dev/acpi/acpipwrres.c @@ -0,0 +1,210 @@ +/* $OpenBSD: acpipwrres.c,v 1.1 2009/06/03 07:13:48 pirofti Exp $ */ +/* + * Copyright (c) 2009 Paul Irofti <pirofti@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/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> + +int acpipwrres_match(struct device *, void *, void *); +void acpipwrres_attach(struct device *, struct device *, void *); +int acpipwrres_notify(struct aml_node *, int, void *); + +#define NOTIFY_PWRRES_OFF 0 +#define NOTIFY_PWRRES_ON 1 + +#ifdef ACPIPWRRES_DEBUG +#define DPRINTF(x) printf x +#else +#define DPRINTF(x) +#endif + +struct acpipwrres_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + + struct acpi_softc *sc_acpi; + struct aml_node *sc_devnode; + + TAILQ_HEAD(acpipwrres_cons_h, acpipwrres_consumer) sc_cons; + + int sc_level; + int sc_order; + int sc_ncons; + int sc_state; +#define ACPIPWRRES_OFF 0 +#define ACPIPWRRES_ON 1 +#define ACPIPWRRES_UNK -1 +}; + +struct acpipwrres_consumer { + struct aml_node *cs_node; + TAILQ_ENTRY(acpipwrres_consumer) cs_link; +}; + +struct cfattach acpipwrres_ca = { + sizeof(struct acpipwrres_softc), acpipwrres_match, acpipwrres_attach +}; + +struct cfdriver acpipwrres_cd = { + NULL, "acpipwrres", DV_DULL +}; + +int acpipwrres_foundcons(struct aml_node *, void *); + +int +acpipwrres_match(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct cfdata *cf = match; + + if (aaa->aaa_name == NULL || strcmp(aaa->aaa_name, + cf->cf_driver->cd_name) != 0 || aaa->aaa_table != NULL) + return (0); + + return (1); +} + +void +acpipwrres_attach(struct device *parent, struct device *self, void *aux) +{ + struct acpipwrres_softc *sc = (struct acpipwrres_softc *)self; + struct acpi_attach_args *aaa = aux; + struct aml_value res; + + extern struct aml_node aml_root; + + sc->sc_acpi = (struct acpi_softc *)parent; + sc->sc_devnode = aaa->aaa_node; + memset(&res, 0, sizeof res); + + printf(": %s\n", sc->sc_devnode->name); + + aml_register_notify(sc->sc_devnode, aaa->aaa_dev, + acpipwrres_notify, sc, ACPIDEV_NOPOLL); + + if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &res)) { + sc->sc_state = (int)aml_val2int(&res); + if (sc->sc_state != ACPIPWRRES_ON && + sc->sc_state != ACPIPWRRES_OFF) + sc->sc_state = ACPIPWRRES_UNK; + } else + sc->sc_state = ACPIPWRRES_UNK; + DPRINTF(("%s: state = %d\n", DEVNAME(sc), sc->sc_state)); + if (aml_evalnode(sc->sc_acpi, aaa->aaa_node, 0, NULL, &res) == 0) { + sc->sc_level = res.v_powerrsrc.pwr_level; + sc->sc_order = res.v_powerrsrc.pwr_order; + DPRINTF(("%s: level = %d, order %d\n", DEVNAME(sc), + sc->sc_level, sc->sc_order)); + aml_freevalue(&res); + } + + /* Get the list of consumers */ + TAILQ_INIT(&sc->sc_cons); + aml_find_node(aml_root.child, "_PRW", acpipwrres_foundcons, sc); + aml_find_node(aml_root.child, "_PR0", acpipwrres_foundcons, sc); + aml_find_node(aml_root.child, "_PR1", acpipwrres_foundcons, sc); + aml_find_node(aml_root.child, "_PR2", acpipwrres_foundcons, sc); +} + +int +acpipwrres_notify(struct aml_node *node, int notify, void *arg) +{ + int fmatch = 0; + struct acpipwrres_consumer *cons; + struct acpipwrres_softc *sc = arg; + struct aml_value res; + + memset(&res, 0, sizeof res); + + TAILQ_FOREACH(cons, &sc->sc_cons, cs_link) + if (cons->cs_node == node) { + fmatch = 1; + break; + } + if (!fmatch) + return (0); + + switch (notify) { + case NOTIFY_PWRRES_ON: + DPRINTF(("pwr: on devs %d\n", sc->sc_ncons)); + if (sc->sc_ncons++ == 0) + aml_evalname(sc->sc_acpi, sc->sc_devnode, "_ON", 0, NULL, + &res); + aml_freevalue(&res); + break; + case NOTIFY_PWRRES_OFF: + DPRINTF(("pwr: off devs %d\n", sc->sc_ncons)); + if (--sc->sc_ncons == 0) + aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OFF", 0, NULL, + &res); + aml_freevalue(&res); + break; + default: + printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify); + break; + } + + return (0); +} + +int +acpipwrres_foundcons(struct aml_node *node, void *arg) +{ + int i = 0; + struct acpipwrres_consumer *cons; + struct aml_node *pnode; + struct acpipwrres_softc *sc = (struct acpipwrres_softc *)arg; + struct aml_value res; + + extern struct aml_node aml_root; + + memset(&res, 0, sizeof res); + + if (aml_evalnode(sc->sc_acpi, node, 0, NULL, &res) == -1) { + DPRINTF(("pwr: consumer not found\n")); + return (-1); + } else { + DPRINTF(("%s: node name %s\n", DEVNAME(sc), aml_nodename(node))); + if (!strcmp(node->name, "_PRW")) + i = 2; /* _PRW first two values are ints */ + for (; i < res.length; i++) { + pnode = aml_searchname(&aml_root, + res.v_package[i]->v_string); + if (pnode == sc->sc_devnode) { + DPRINTF(("%s: consumer match\n", DEVNAME(sc))); + cons = malloc(sizeof *pnode, M_DEVBUF, + M_WAITOK | M_ZERO); + cons->cs_node = pnode; + TAILQ_INSERT_HEAD(&sc->sc_cons, cons, cs_link); + } + } + } + + return (0); +} diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi index f3d4daf926d..be89febd85f 100644 --- a/sys/dev/acpi/files.acpi +++ b/sys/dev/acpi/files.acpi @@ -1,4 +1,4 @@ -# $OpenBSD: files.acpi,v 1.21 2009/06/03 00:36:59 pirofti Exp $ +# $OpenBSD: files.acpi,v 1.22 2009/06/03 07:13:48 pirofti Exp $ # # Config file and device description for machine-independent ACPI code. # Included by ports that need it. @@ -86,3 +86,8 @@ file dev/acpi/acpivideo.c acpivideo device acpivout attach acpivout at acpivideo file dev/acpi/acpivout.c acpivout + +# ACPI pwrres +device acpipwrres +attach acpipwrres at acpi +file dev/acpi/acpipwrres.c acpipwrres |