code:
/* $OpenBSD: acpimcfg.c,v 1.2 2011/01/05 22:29:31 kettenis Exp $ */
/*
 * Copyright (c) 2010 Mark Kettenis <kettenis@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/systm.h>
#include <sys/device.h>

#include <machine/apicvar.h>

#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
#include <dev/pci/pcivar.h>

int acpimcfg_match(struct device *, void *, void *);
void acpimcfg_attach(struct device *, struct device *, void *);

struct cfattach acpimcfg_ca = {
	sizeof(struct device), acpimcfg_match, acpimcfg_attach
};

struct cfdriver acpimcfg_cd = {
	NULL, "acpimcfg", DV_DULL
};

int
acpimcfg_match(struct device *parent, void *match, void *aux)
{
	struct acpi_attach_args *aaa = aux;
	struct acpi_table_header *hdr;

	/*
	 * If we do not have a table, it is not us
	 */
	if (aaa->aaa_table == NULL)
		return (0);

	/*
	 * If it is an MCFG table, we can attach
	 */
	hdr = (struct acpi_table_header *)aaa->aaa_table;
	if (memcmp(hdr->signature, MCFG_SIG, sizeof(MCFG_SIG) - 1) != 0)
		return (0);

	return (1);
}

void
acpimcfg_attach(struct device *parent, struct device *self, void *aux)
{
	struct acpi_attach_args *aaa = aux;
	struct acpi_mcfg *mcfg = (struct acpi_mcfg *)aaa->aaa_table;

	printf(" addr 0x%llx, bus %d-%d\n", mcfg->base_address,
	    mcfg->min_bus_number, mcfg->max_bus_number);

	/*
	 * Some (broken?) BIOSen have an MCFG table for an empty bus
	 * range.  Ignore those tables.
	 */
	if (mcfg->min_bus_number == mcfg->max_bus_number)
		return;

	pci_mcfg_addr = mcfg->base_address;
	pci_mcfg_min_bus = mcfg->min_bus_number;
	pci_mcfg_max_bus = mcfg->max_bus_number;
}


code:
/* $OpenBSD: acpiprt.c,v 1.47 2015/03/14 03:38:46 jsg Exp $ */
/*
 * Copyright (c) 2006 Mark Kettenis <kettenis@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/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>

#include <dev/pci/pcivar.h>
#include <dev/pci/ppbreg.h>

#include <machine/i82093reg.h>
#include <machine/i82093var.h>

#include <machine/mpbiosvar.h>

#include "ioapic.h"

struct acpiprt_irq {
	int _int;
	int _shr;
	int _ll;
	int _he;
};

struct acpiprt_map {
	int bus, dev;
	int pin;
	int irq;
	struct acpiprt_softc *sc;
	struct aml_node *node;
	SIMPLEQ_ENTRY(acpiprt_map) list;
};

SIMPLEQ_HEAD(, acpiprt_map) acpiprt_map_list =
    SIMPLEQ_HEAD_INITIALIZER(acpiprt_map_list);

int	acpiprt_match(struct device *, void *, void *);
void	acpiprt_attach(struct device *, struct device *, void *);
int	acpiprt_getirq(union acpi_resource *crs, void *arg);
int	acpiprt_chooseirq(union acpi_resource *, void *);

struct acpiprt_softc {
	struct device		sc_dev;

	struct acpi_softc	*sc_acpi;
	struct aml_node		*sc_devnode;

	int			sc_bus;
};

struct cfattach acpiprt_ca = {
	sizeof(struct acpiprt_softc), acpiprt_match, acpiprt_attach
};

struct cfdriver acpiprt_cd = {
	NULL, "acpiprt", DV_DULL
};

void	acpiprt_prt_add(struct acpiprt_softc *, struct aml_value *);
int	acpiprt_getpcibus(struct acpiprt_softc *, struct aml_node *);
void	acpiprt_route_interrupt(int bus, int dev, int pin);

int
acpiprt_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);

	return (1);
}

void
acpiprt_attach(struct device *parent, struct device *self, void *aux)
{
	struct acpiprt_softc *sc = (struct acpiprt_softc *)self;
	struct acpi_attach_args *aa = aux;
	struct aml_value res;
	int i;

	sc->sc_acpi = (struct acpi_softc *)parent;
	sc->sc_devnode = aa->aaa_node;
	sc->sc_bus = acpiprt_getpcibus(sc, sc->sc_devnode);
	printf(": bus %d (%s)", sc->sc_bus, sc->sc_devnode->parent->name);

	if (sc->sc_bus == -1) {
		printf("\n");
		return;
	}

	if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL, &res)) {
		printf(": no PCI interrupt routing table\n");
		return;
	}

	if (res.type != AML_OBJTYPE_PACKAGE) {
		printf(": _PRT is not a package\n");
		aml_freevalue(&res);
		return;
	}

	printf("\n");

	for (i = 0; i < res.length; i++)
		acpiprt_prt_add(sc, res.v_package[i]);

	aml_freevalue(&res);
}

int
acpiprt_getirq(union acpi_resource *crs, void *arg)
{
	struct acpiprt_irq *irq = arg;
	int typ, len;

	irq->_shr = 0;
	irq->_ll = 0;
	irq->_he = 1;

	typ = AML_CRSTYPE(crs);
	len = AML_CRSLEN(crs);
	switch (typ) {
	case SR_IRQ:
		irq->_int= ffs(letoh16(crs->sr_irq.irq_mask)) - 1;
		if (len > 2) {
			irq->_shr = (crs->sr_irq.irq_flags & SR_IRQ_SHR);
			irq->_ll = (crs->sr_irq.irq_flags & SR_IRQ_POLARITY);
			irq->_he = (crs->sr_irq.irq_flags & SR_IRQ_MODE);
		}
		break;
	case LR_EXTIRQ:
		irq->_int = letoh32(crs->lr_extirq.irq[0]);
		irq->_shr = (crs->lr_extirq.flags & LR_EXTIRQ_SHR);
		irq->_ll = (crs->lr_extirq.flags & LR_EXTIRQ_POLARITY);
		irq->_he = (crs->lr_extirq.flags & LR_EXTIRQ_MODE);
		break;
	default:
		printf("unknown interrupt: %x\n", typ);
	}
	return (0);
}

int
acpiprt_pri[16] = {
	0,			/* 8254 Counter 0 */
	1,			/* Keyboard */
	0,			/* 8259 Slave */
	2,			/* Serial Port A */
	2,			/* Serial Port B */
	5,			/* Parallel Port / Generic */
	2,			/* Floppy Disk */
	4,			/* Parallel Port / Generic */
	1,			/* RTC */
	6,			/* Generic */
	7,			/* Generic */
	7,			/* Generic */
	1,			/* Mouse */
	0,			/* FPU */
	2,			/* Primary IDE */
	3			/* Secondary IDE */
};

int
acpiprt_chooseirq(union acpi_resource *crs, void *arg)
{
	struct acpiprt_irq *irq = arg;
	int typ, len, i, pri = -1;

	irq->_shr = 0;
	irq->_ll = 0;
	irq->_he = 1;

	typ = AML_CRSTYPE(crs);
	len = AML_CRSLEN(crs);
	switch (typ) {
	case SR_IRQ:
		for (i = 0; i < sizeof(crs->sr_irq.irq_mask) * 8; i++) {
			if (crs->sr_irq.irq_mask & (1 << i) &&
			    acpiprt_pri[i] > pri) {
				irq->_int = i;
				pri = acpiprt_pri[irq->_int];
			}
		}
		if (len > 2) {
			irq->_shr = (crs->sr_irq.irq_flags & SR_IRQ_SHR);
			irq->_ll = (crs->sr_irq.irq_flags & SR_IRQ_POLARITY);
			irq->_he = (crs->sr_irq.irq_flags & SR_IRQ_MODE);
		}
		break;
	case LR_EXTIRQ:
		/* First try non-8259 interrupts. */
		for (i = 0; i < crs->lr_extirq.irq_count; i++) {
			if (crs->lr_extirq.irq[i] > 15) {
				irq->_int = crs->lr_extirq.irq[i];
				return (0);
			}
		}

		for (i = 0; i < crs->lr_extirq.irq_count; i++) {
			if (acpiprt_pri[crs->lr_extirq.irq[i]] > pri) {
				irq->_int = crs->lr_extirq.irq[i];
				pri = acpiprt_pri[irq->_int];
			}
		}
		irq->_shr = (crs->lr_extirq.flags & LR_EXTIRQ_SHR);
		irq->_ll = (crs->lr_extirq.flags & LR_EXTIRQ_POLARITY);
		irq->_he = (crs->lr_extirq.flags & LR_EXTIRQ_MODE);
		break;
	default:
		printf("unknown interrupt: %x\n", typ);
	}
	return (0);
}

void
acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v)
{
	struct aml_node	*node;
	struct aml_value res, *pp;
	struct acpiprt_irq irq;
	u_int64_t addr;
	int pin;
	int64_t sta;
#if NIOAPIC > 0
	struct mp_intr_map *map;
	struct ioapic_softc *apic;
#endif
	pci_chipset_tag_t pc = NULL;
	pcitag_t tag;
	pcireg_t reg;
	int bus, dev, func, nfuncs;
	struct acpiprt_map *p;

	if (v->type != AML_OBJTYPE_PACKAGE || v->length != 4) {
		printf("invalid mapping object\n");
		return;
	}

	addr = aml_val2int(v->v_package[0]);
	pin = aml_val2int(v->v_package[1]);
	if (pin > 3) {
		return;
	}

	pp = v->v_package[2];
	if (pp->type == AML_OBJTYPE_STRING) {
		node = aml_searchrel(sc->sc_devnode, pp->v_string);
		if (node == NULL) {
			printf("Invalid device\n");
			return;
		}
		pp = node->value;
	}
	if (pp->type == AML_OBJTYPE_NAMEREF) {
		node = aml_searchrel(sc->sc_devnode, pp->v_nameref);
		if (node == NULL) {
			printf("Invalid device\n");
			return;
		}
		pp = node->value;
	}
	if (pp->type == AML_OBJTYPE_OBJREF) {
		pp = pp->v_objref.ref;
	}
	if (pp->type == AML_OBJTYPE_DEVICE) {
		node = pp->node;
		if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta)) {
			printf("no _STA method\n");
			return;
		}

		if ((sta & STA_PRESENT) == 0)
			return;

		if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) {
			printf("no _CRS method\n");
			return;
		}

		if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
			printf("invalid _CRS object\n");
			aml_freevalue(&res);
			return;
		}
		aml_parse_resource(&res, acpiprt_getirq, &irq);
		aml_freevalue(&res);

		/* Pick a new IRQ if necessary. */
		if ((irq._int == 0 || irq._int == 2 || irq._int == 13) &&
		    !aml_evalname(sc->sc_acpi, node, "_PRS", 0, NULL, &res)){
			aml_parse_resource(&res, acpiprt_chooseirq, &irq);
			aml_freevalue(&res);
		}

		if ((p = malloc(sizeof(*p), M_ACPI, M_NOWAIT)) == NULL)
			return;
		p->bus = sc->sc_bus;
		p->dev = ACPI_PCI_DEV(addr << 16);
		p->pin = pin;
		p->irq = irq._int;
		p->sc = sc;
		p->node = node;
		SIMPLEQ_INSERT_TAIL(&acpiprt_map_list, p, list);
	} else {
		irq._int = aml_val2int(v->v_package[3]);
		irq._shr = 1;
		irq._ll = 1;
		irq._he = 0;
	}

#ifdef ACPI_DEBUG
	printf("%s: %s addr 0x%llx pin %d irq %d\n",
	    DEVNAME(sc), aml_nodename(pp->node), addr, pin, irq._int);
#endif

#if NIOAPIC > 0
	if (nioapics > 0) {
		apic = ioapic_find_bybase(irq._int);
		if (apic == NULL) {
			printf("%s: no apic found for irq %d\n",
			    DEVNAME(sc), irq._int);
			return;
		}

		map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO);
		if (map == NULL)
			return;

		map->ioapic = apic;
		map->ioapic_pin = irq._int - apic->sc_apic_vecbase;
		map->bus_pin = ((addr >> 14) & 0x7c) | (pin & 0x3);
		if (irq._ll)
			map->flags |= (MPS_INTPO_ACTLO << MPS_INTPO_SHIFT);
		else
			map->flags |= (MPS_INTPO_ACTHI << MPS_INTPO_SHIFT);
		if (irq._he)
			map->flags |= (MPS_INTTR_EDGE << MPS_INTTR_SHIFT);
		else
			map->flags |= (MPS_INTTR_LEVEL << MPS_INTTR_SHIFT);

		map->redir = (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
		switch ((map->flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK) {
		case MPS_INTPO_DEF:
		case MPS_INTPO_ACTLO:
			map->redir |= IOAPIC_REDLO_ACTLO;
			break;
		}
		switch ((map->flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK) {
		case MPS_INTTR_DEF:
		case MPS_INTTR_LEVEL:
			map->redir |= IOAPIC_REDLO_LEVEL;
			break;
		}

		map->ioapic_ih = APIC_INT_VIA_APIC |
		    ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
		    (map->ioapic_pin << APIC_INT_PIN_SHIFT));

		apic->sc_pins[map->ioapic_pin].ip_map = map;

		map->next = mp_busses[sc->sc_bus].mb_intrs;
		mp_busses[sc->sc_bus].mb_intrs = map;

		return;
	}
#endif

	bus = sc->sc_bus;
	dev = ACPI_PCI_DEV(addr << 16);
	tag = pci_make_tag(pc, bus, dev, 0);

	reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
	if (PCI_HDRTYPE_MULTIFN(reg))
		nfuncs = 8;
	else
		nfuncs = 1;

	for (func = 0; func < nfuncs; func++) {
		tag = pci_make_tag(pc, bus, dev, func);
		reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
		if (PCI_INTERRUPT_PIN(reg) == pin + 1) {
			reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
			reg |= irq._int << PCI_INTERRUPT_LINE_SHIFT;
			pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);
		}
	}
}

int
acpiprt_getpcibus(struct acpiprt_softc *sc, struct aml_node *node)
{
	/* Check if parent device has PCI mapping */
	return (node->parent && node->parent->pci) ?
		node->parent->pci->sub : -1;
}

void
acpiprt_route_interrupt(int bus, int dev, int pin)
{
	struct acpiprt_softc *sc;
	struct acpiprt_map *p;
	struct acpiprt_irq irq;
	struct aml_node *node = NULL;
	struct aml_value res, res2;
	union acpi_resource *crs;
	int newirq;
	int64_t sta;

	SIMPLEQ_FOREACH(p, &acpiprt_map_list, list) {
		if (p->bus == bus && p->dev == dev && p->pin == (pin - 1)) {
			newirq = p->irq;
			sc = p->sc;
			node = p->node;
			break;
		}
	}
	if (node == NULL)
		return;

	if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta)) {
		printf("no _STA method\n");
		return;
	}

	KASSERT(sta & STA_PRESENT);

	if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) {
		printf("no _CRS method\n");
		return;
	}
	if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
		printf("invalid _CRS object\n");
		aml_freevalue(&res);
		return;
	}
	aml_parse_resource(&res, acpiprt_getirq, &irq);

	/* Only re-route interrupts when necessary. */
	if ((sta & STA_ENABLED) && irq._int == newirq) {
		aml_freevalue(&res);
		return;
	}

	crs = (union acpi_resource *)res.v_buffer;
	switch (AML_CRSTYPE(crs)) {
	case SR_IRQ:
		crs->sr_irq.irq_mask = htole16(1 << newirq);
		break;
	case LR_EXTIRQ:
		crs->lr_extirq.irq[0] = htole32(newirq);
		break;
	}

	if (aml_evalname(sc->sc_acpi, node, "_SRS", 1, &res, &res2)) {
		printf("no _SRS method\n");
		aml_freevalue(&res);
		return;
	}
	aml_freevalue(&res);
	aml_freevalue(&res2);
}

license: unknown


code:
/* $OpenBSD: acpipwrres.c,v 1.7 2014/09/14 14:17:24 jsg Exp $ */

/*
 * Copyright (c) 2013 Martin Pieuchot <mpi@openbsd.org>
 * 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/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 *);

#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;

	SIMPLEQ_HEAD(, acpipwrres_consumer)	sc_cons;
	int					sc_cons_ref;

	int	sc_level;
	int	sc_order;
	int	sc_state;
#define ACPIPWRRES_OFF		0
#define ACPIPWRRES_ON		1
#define ACPIPWRRES_UNK		-1
};

struct acpipwrres_consumer {
	struct aml_node				*cs_node;
	SIMPLEQ_ENTRY(acpipwrres_consumer)	cs_next;
};

struct cfattach acpipwrres_ca = {
	sizeof(struct acpipwrres_softc), acpipwrres_match, acpipwrres_attach
};

struct cfdriver acpipwrres_cd = {
	NULL, "acpipwrres", DV_DULL
};

int	acpipwrres_hascons(struct acpipwrres_softc *, struct aml_node *);
int	acpipwrres_addcons(struct acpipwrres_softc *, struct aml_node *);
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;
	struct acpipwrres_consumer	*cons;

	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", sc->sc_devnode->name);

	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(("\n%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 */
	SIMPLEQ_INIT(&sc->sc_cons);
#if notyet
	aml_find_node(&aml_root, "_PRW", acpipwrres_foundcons, sc);
#endif
	aml_find_node(&aml_root, "_PR0", acpipwrres_foundcons, sc);
	aml_find_node(&aml_root, "_PR1", acpipwrres_foundcons, sc);
	aml_find_node(&aml_root, "_PR2", acpipwrres_foundcons, sc);
	aml_find_node(&aml_root, "_PR3", acpipwrres_foundcons, sc);

	DPRINTF(("%s", DEVNAME(sc)));
	if (!SIMPLEQ_EMPTY(&sc->sc_cons)) {
		printf(", resource for");
		SIMPLEQ_FOREACH(cons, &sc->sc_cons, cs_next)
			printf(" %s%s", cons->cs_node->name,
			   (SIMPLEQ_NEXT(cons, cs_next) == NULL) ? "" : ",");
	}
	printf("\n");
}

int
acpipwrres_ref_incr(struct acpipwrres_softc *sc, struct aml_node *node)
{
	struct aml_value		res;

	if (!acpipwrres_hascons(sc, node))
		return (1);

	DPRINTF(("%s: dev %s ON %d\n", DEVNAME(sc), node->name,
	    sc->sc_cons_ref));

	if (sc->sc_cons_ref++ == 0) {
		memset(&res, 0, sizeof(res));
		aml_evalname(sc->sc_acpi, sc->sc_devnode, "_ON", 0,
		    NULL, &res);
		aml_freevalue(&res);
	}

	return (0);
}

int
acpipwrres_ref_decr(struct acpipwrres_softc *sc, struct aml_node *node)
{
	struct aml_value		res;

	if (!acpipwrres_hascons(sc, node))
		return (1);

	DPRINTF(("%s: dev %s OFF %d\n", DEVNAME(sc), node->name,
	    sc->sc_cons_ref));

	if (--sc->sc_cons_ref == 0) {
		memset(&res, 0, sizeof(res));
		aml_evalname(sc->sc_acpi, sc->sc_devnode, "_OFF", 0,
		    NULL, &res);
		aml_freevalue(&res);
	}

	return (0);
}

int
acpipwrres_hascons(struct acpipwrres_softc *sc, struct aml_node *node)
{
	struct acpipwrres_consumer	*cons;

	SIMPLEQ_FOREACH(cons, &sc->sc_cons, cs_next) {
		if (cons->cs_node == node)
			return (1);
	}

	return (0);
}

int
acpipwrres_addcons(struct acpipwrres_softc *sc, struct aml_node *node)
{
	struct acpipwrres_consumer	*cons;
	struct acpi_pwrres		*pr;
	int				state;

	/*
	 * Add handlers to put the device into Dx states.
	 *
	 * XXX What about PRW?
	 */
	if (strcmp(node->name, "_PR0") == 0) {
		state = ACPI_STATE_D0;
	} else if (strcmp(node->name, "_PR1") == 0) {
		state = ACPI_STATE_D1;
	} else if (strcmp(node->name, "_PR2") == 0) {
		state = ACPI_STATE_D2;
	} else if (strcmp(node->name, "_PR3") == 0) {
		state = ACPI_STATE_D3;
	} else {
		return (0);
	}

	if (!acpipwrres_hascons(sc, node->parent)) {
		cons = malloc(sizeof(*cons), M_DEVBUF, M_NOWAIT | M_ZERO);
		if (cons == NULL)
			return (ENOMEM);

		cons->cs_node = node->parent;
		SIMPLEQ_INSERT_TAIL(&sc->sc_cons, cons, cs_next);
	}

	DPRINTF(("%s: resource for %s (D%d) \n", DEVNAME(sc),
	    node->parent->name, state));

	/*
	 * Make sure we attach only once the same Power Resource for a
	 * given state.
	 */
	SIMPLEQ_FOREACH(pr, &sc->sc_acpi->sc_pwrresdevs, p_next) {
		if (pr->p_node == node->parent &&
		    pr->p_res_state == state &&
		    pr->p_res_sc == sc) {
			DPRINTF(("error: pr for %s already set\n",
			   aml_nodename(pr->p_node)));
			return (EINVAL);
		}
	}

	pr = malloc(sizeof(struct acpi_pwrres), M_DEVBUF, M_NOWAIT | M_ZERO);
	if (pr == NULL)
		return (ENOMEM);

	pr->p_node = node->parent;
	pr->p_state = -1;
	pr->p_res_state = state;
	pr->p_res_sc = sc;

	SIMPLEQ_INSERT_TAIL(&sc->sc_acpi->sc_pwrresdevs, pr, p_next);

	return (0);
}

int
acpipwrres_foundcons(struct aml_node *node, void *arg)
{
	struct acpipwrres_softc		*sc = (struct acpipwrres_softc *)arg;
	struct aml_value		res, *ref;
	int				i = 0;

	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);
	}

	if (res.type != AML_OBJTYPE_PACKAGE) {
		DPRINTF(("%s: %s is not a package\n", DEVNAME(sc),
		    aml_nodename(node)));
		aml_freevalue(&res);
		return (1);
	}

	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++) {
		ref = res.v_package[i];

		if (ref->type == AML_OBJTYPE_STRING) {
			struct aml_node	*pnode;

			pnode = aml_searchrel(&aml_root, ref->v_string);
			if (pnode == NULL) {
				DPRINTF(("%s: device %s not found\n",
				    DEVNAME(sc), ref->v_string));
				continue;
			}
			ref = pnode->value;
		}

		if (ref->type == AML_OBJTYPE_OBJREF)
			ref = ref->v_objref.ref;

		if (ref->type != AML_OBJTYPE_POWERRSRC) {
			DPRINTF(("%s: object reference has a wrong type (%d)\n",
			    DEVNAME(sc), ref->type));
			continue;
		}

		if (ref->node == sc->sc_devnode)
			(void)acpipwrres_addcons(sc, node);
	}
	aml_freevalue(&res);

	return (0);
}


code:
/*	$OpenBSD: acpireg.h,v 1.30 2015/01/15 01:19:28 jsg Exp $	*/
/*
 * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
 * 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.
 */

#ifndef _DEV_ACPI_ACPIREG_H_
#define _DEV_ACPI_ACPIREG_H_

/*	Root System Descriptor Pointer */
struct acpi_rsdp1 {
	u_int8_t	signature[8];
#define	RSDP_SIG	"RSD PTR "
#define	rsdp_signaturee	rsdp1.signature
	u_int8_t	checksum;	/* make sum == 0 */
#define	rsdp_checksum	rsdp1.checksum
	u_int8_t	oemid[6];
#define	rsdp_oemid	rsdp1.oemid
	u_int8_t	revision;	/* 0 for 1, 2 for 2 */
#define	rsdp_revision	rsdp1.revision
	u_int32_t	rsdt;		/* physical */
#define	rsdp_rsdt	rsdp1.rsdt
} __packed;

struct acpi_rsdp {
	struct acpi_rsdp1 rsdp1;
	/*
	 * The following values are only valid
	 * when rsdp_revision == 2
	 */
	u_int32_t	rsdp_length;		/* length of rsdp */
	u_int64_t	rsdp_xsdt;		/* physical */
	u_int8_t	rsdp_extchecksum;	/* entire table */
	u_int8_t	rsdp_reserved[3];	/* must be zero */
} __packed;

struct acpi_table_header {
	u_int8_t	signature[4];
#define	hdr_signature		hdr.signature
	u_int32_t	length;
#define	hdr_length		hdr.length
	u_int8_t	revision;
#define	hdr_revision		hdr.revision
	u_int8_t	checksum;
#define	hdr_checksum		hdr.checksum
	u_int8_t	oemid[6];
#define hdr_oemid		hdr.oemid
	u_int8_t	oemtableid[8];
#define hdr_oemtableid		hdr.oemtableid
	u_int32_t	oemrevision;
#define	hdr_oemrevision		hdr.oemrevision
	u_int8_t	aslcompilerid[4];
#define hdr_aslcompilerid	hdr.aslcompilerid
	u_int32_t	aslcompilerrevision;
#define	hdr_aslcompilerrevision	hdr.aslcompilerrevision
} __packed;

struct acpi_rsdt {
	struct acpi_table_header	hdr;
#define RSDT_SIG	"RSDT"
	u_int32_t			table_offsets[1];
} __packed;

struct acpi_xsdt {
	struct acpi_table_header	hdr;
#define XSDT_SIG	"XSDT"
	u_int64_t			table_offsets[1];
} __packed;

struct acpi_gas {
	u_int8_t	address_space_id;
#define GAS_SYSTEM_MEMORY	0
#define GAS_SYSTEM_IOSPACE	1
#define GAS_PCI_CFG_SPACE	2
#define GAS_EMBEDDED		3
#define GAS_SMBUS		4
#define GAS_FUNCTIONAL_FIXED	127
	u_int8_t	register_bit_width;
	u_int8_t	register_bit_offset;
	u_int8_t	access_size;
#define GAS_ACCESS_UNDEFINED	0
#define GAS_ACCESS_BYTE		1
#define GAS_ACCESS_WORD		2
#define GAS_ACCESS_DWORD	3
#define GAS_ACCESS_QWORD	4
	u_int64_t	address;
} __packed;

struct acpi_fadt {
	struct acpi_table_header	hdr;
#define	FADT_SIG	"FACP"
	u_int32_t	firmware_ctl;	/* phys addr FACS */
	u_int32_t	dsdt;		/* phys addr DSDT */
	u_int8_t	int_model;	/* interrupt model (hdr_revision < 3) */
#define	FADT_INT_DUAL_PIC	0
#define	FADT_INT_MULTI_APIC	1
	u_int8_t	pm_profile;	/* power mgmt profile */
#define	FADT_PM_UNSPEC		0
#define	FADT_PM_DESKTOP		1
#define	FADT_PM_MOBILE		2
#define	FADT_PM_WORKSTATION	3
#define	FADT_PM_ENT_SERVER	4
#define	FADT_PM_SOHO_SERVER	5
#define	FADT_PM_APPLIANCE	6
#define	FADT_PM_PERF_SERVER	7
	u_int16_t	sci_int;	/* SCI interrupt */
	u_int32_t	smi_cmd;	/* SMI command port */
	u_int8_t	acpi_enable;	/* value to enable */
	u_int8_t	acpi_disable;	/* value to disable */
	u_int8_t	s4bios_req;	/* value for S4 */
	u_int8_t	pstate_cnt;	/* value for performance (hdr_revision > 2) */
	u_int32_t	pm1a_evt_blk;	/* power management 1a */
	u_int32_t	pm1b_evt_blk;	/* power mangement 1b */
	u_int32_t	pm1a_cnt_blk;	/* pm control 1a */
	u_int32_t	pm1b_cnt_blk;	/* pm control 1b */
	u_int32_t	pm2_cnt_blk;	/* pm control 2 */
	u_int32_t	pm_tmr_blk;
	u_int32_t	gpe0_blk;
	u_int32_t	gpe1_blk;
	u_int8_t	pm1_evt_len;
	u_int8_t	pm1_cnt_len;
	u_int8_t	pm2_cnt_len;
	u_int8_t	pm_tmr_len;
	u_int8_t	gpe0_blk_len;
	u_int8_t	gpe1_blk_len;
	u_int8_t	gpe1_base;
	u_int8_t	cst_cnt;	/* (hdr_revision > 2) */
	u_int16_t	p_lvl2_lat;
	u_int16_t	p_lvl3_lat;
	u_int16_t	flush_size;
	u_int16_t	flush_stride;
	u_int8_t	duty_offset;
	u_int8_t	duty_width;
	u_int8_t	day_alrm;
	u_int8_t	mon_alrm;
	u_int8_t	century;
	u_int16_t	iapc_boot_arch;	/* (hdr_revision > 2) */
#define	FADT_LEGACY_DEVICES		0x0001	/* Legacy devices supported */
#define	FADT_i8042			0x0002	/* Keyboard controller present */
#define	FADT_NO_VGA			0x0004	/* Do not probe VGA */
	u_int8_t	reserved1;
	u_int32_t	flags;
#define	FADT_WBINVD			0x00000001
#define	FADT_WBINVD_FLUSH		0x00000002
#define	FADT_PROC_C1			0x00000004
#define	FADT_P_LVL2_UP			0x00000008
#define	FADT_PWR_BUTTON			0x00000010
#define	FADT_SLP_BUTTON			0x00000020
#define	FADT_FIX_RTC			0x00000040
#define	FADT_RTC_S4			0x00000080
#define	FADT_TMR_VAL_EXT		0x00000100
#define	FADT_DCK_CAP			0x00000200
#define	FADT_RESET_REG_SUP		0x00000400
#define	FADT_SEALED_CASE		0x00000800
#define	FADT_HEADLESS			0x00001000
#define	FADT_CPU_SW_SLP			0x00002000
#define	FADT_PCI_EXP_WAK		0x00004000
#define	FADT_USE_PLATFORM_CLOCK		0x00008000
#define	FADT_S4_RTC_STS_VALID		0x00010000
#define	FADT_REMOTE_POWER_ON_CAPABLE	0x00020000
#define	FADT_FORCE_APIC_CLUSTER_MODEL	0x00040000
#define	FADT_FORCE_APIC_PHYS_DEST_MODE	0x00080000
	/*
	 * Following values only exist when rev > 1
	 * If the extended addresses exists, they
	 * must be used in preferense to the non-
	 * extended values above
	 */
	struct acpi_gas	reset_reg;
	u_int8_t	reset_value;
	u_int8_t	reserved2a;
	u_int8_t	reserved2b;
	u_int8_t	reserved2c;
	u_int64_t	x_firmware_ctl;
	u_int64_t	x_dsdt;
	struct acpi_gas	x_pm1a_evt_blk;
	struct acpi_gas	x_pm1b_evt_blk;
	struct acpi_gas	x_pm1a_cnt_blk;
	struct acpi_gas	x_pm1b_cnt_blk;
	struct acpi_gas	x_pm2_cnt_blk;
	struct acpi_gas	x_pm_tmr_blk;
	struct acpi_gas	x_gpe0_blk;
	struct acpi_gas	x_gpe1_blk;
} __packed;

struct acpi_dsdt {
	struct acpi_table_header	hdr;
#define DSDT_SIG	"DSDT"
	u_int8_t	aml[1];
} __packed;

struct acpi_ssdt {
	struct acpi_table_header	hdr;
#define SSDT_SIG	"SSDT"
	u_int8_t	aml[1];
} __packed;

/*
 * Table deprecated by ACPI 2.0
 */
struct acpi_psdt {
	struct acpi_table_header	hdr;
#define PSDT_SIG	"PSDT"
} __packed;

struct acpi_madt {
	struct acpi_table_header	hdr;
#define MADT_SIG	"APIC"
	u_int32_t	local_apic_address;
	u_int32_t	flags;
#define ACPI_APIC_PCAT_COMPAT	0x00000001
} __packed;

struct acpi_madt_lapic {
	u_int8_t	apic_type;
#define	ACPI_MADT_LAPIC		0
	u_int8_t	length;
	u_int8_t	acpi_proc_id;
	u_int8_t	apic_id;
	u_int32_t	flags;
#define	ACPI_PROC_ENABLE	0x00000001
} __packed;

struct acpi_madt_ioapic {
	u_int8_t	apic_type;
#define	ACPI_MADT_IOAPIC	1
	u_int8_t	length;
	u_int8_t	acpi_ioapic_id;
	u_int8_t	reserved;
	u_int32_t	address;
	u_int32_t	global_int_base;
} __packed;

struct acpi_madt_override {
	u_int8_t	apic_type;
#define	ACPI_MADT_OVERRIDE	2
	u_int8_t	length;
	u_int8_t	bus;
#define	ACPI_OVERRIDE_BUS_ISA	0
	u_int8_t	source;
	u_int32_t	global_int;
	u_int16_t	flags;
#define	ACPI_OVERRIDE_POLARITY_BITS	0x3
#define	ACPI_OVERRIDE_POLARITY_BUS		0x0
#define	ACPI_OVERRIDE_POLARITY_HIGH		0x1
#define	ACPI_OVERRIDE_POLARITY_LOW		0x3
#define	ACPI_OVERRIDE_TRIGGER_BITS	0xc
#define	ACPI_OVERRIDE_TRIGGER_BUS		0x0
#define	ACPI_OVERRIDE_TRIGGER_EDGE		0x4
#define	ACPI_OVERRIDE_TRIGGER_LEVEL		0xc
} __packed;

struct acpi_madt_nmi {
	u_int8_t	apic_type;
#define	ACPI_MADT_NMI		3
	u_int8_t	length;
	u_int16_t	flags;		/* Same flags as acpi_madt_override */
	u_int32_t	global_int;
} __packed;

struct acpi_madt_lapic_nmi {
	u_int8_t	apic_type;
#define	ACPI_MADT_LAPIC_NMI	4
	u_int8_t	length;
	u_int8_t	acpi_proc_id;
	u_int16_t	flags;		/* Same flags as acpi_madt_override */
	u_int8_t	local_apic_lint;
} __packed;

struct acpi_madt_lapic_override {
	u_int8_t	apic_type;
#define	ACPI_MADT_LAPIC_OVERRIDE	5
	u_int8_t	length;
	u_int16_t	reserved;
	u_int64_t	lapic_address;
} __packed;

struct acpi_madt_io_sapic {
	u_int8_t	apic_type;
#define	ACPI_MADT_IO_SAPIC	6
	u_int8_t	length;
	u_int8_t	iosapic_id;
	u_int8_t	reserved;
	u_int32_t	global_int_base;
	u_int64_t	iosapic_address;
} __packed;

struct acpi_madt_local_sapic {
	u_int8_t	apic_type;
#define	ACPI_MADT_LOCAL_SAPIC	7
	u_int8_t	length;
	u_int8_t	acpi_proc_id;
	u_int8_t	local_sapic_id;
	u_int8_t	local_sapic_eid;
	u_int8_t	reserved[3];
	u_int32_t	flags;		/* Same flags as acpi_madt_lapic */
	u_int32_t	acpi_proc_uid;
	u_int8_t	acpi_proc_uid_string[1];
} __packed;

struct acpi_madt_platform_int {
	u_int8_t	apic_type;
#define	ACPI_MADT_PLATFORM_INT	8
	u_int8_t	length;
	u_int16_t	flags;		/* Same flags as acpi_madt_override */
	u_int8_t	int_type;
#define	ACPI_MADT_PLATFORM_PMI		1
#define	ACPI_MADT_PLATFORM_INIT		2
#define	ACPI_MADT_PLATFORM_CORR_ERROR	3
	u_int8_t	proc_id;
	u_int8_t	proc_eid;
	u_int8_t	io_sapic_vec;
	u_int32_t	global_int;
	u_int32_t	platform_int_flags;
#define	ACPI_MADT_PLATFORM_CPEI		0x00000001
} __packed;

struct acpi_madt_x2apic {
	u_int8_t	apic_type;
#define	ACPI_MADT_X2APIC	9
	u_int8_t	length;
	u_int8_t	reserved[2];
	u_int32_t	apic_id;
	u_int32_t	flags;		/* Same flags as acpi_madt_lapic */
	u_int32_t	apic_proc_uid;
} __packed;

struct acpi_madt_x2apic_nmi {
	u_int8_t	apic_type;
#define	ACPI_MADT_X2APIC_NMI	10
	u_int8_t	length;
	u_int16_t	flags;		/* Same flags as acpi_madt_override */
	u_int32_t	apic_proc_uid;
	u_int8_t	local_x2apic_lint;
	u_int8_t	reserved[3];
} __packed;

union acpi_madt_entry {
	struct acpi_madt_lapic		madt_lapic;
	struct acpi_madt_ioapic		madt_ioapic;
	struct acpi_madt_override	madt_override;
	struct acpi_madt_nmi		madt_nmi;
	struct acpi_madt_lapic_nmi	madt_lapic_nmi;
	struct acpi_madt_lapic_override	madt_lapic_override;
	struct acpi_madt_io_sapic	madt_io_sapic;
	struct acpi_madt_local_sapic	madt_local_sapic;
	struct acpi_madt_platform_int	madt_platform_int;
	struct acpi_madt_x2apic		madt_x2apic;
	struct acpi_madt_x2apic_nmi	madt_x2apic_nmi;
} __packed;

struct acpi_sbst {
	struct acpi_table_header	hdr;
#define SBST_SIG	"SBST"
	u_int32_t	warning_energy_level;
	u_int32_t	low_energy_level;
	u_int32_t	critical_energy_level;
} __packed;

struct acpi_ecdt {
	struct acpi_table_header	hdr;
#define ECDT_SIG	"ECDT"
	struct acpi_gas	ec_control;
	struct acpi_gas ec_data;
	u_int32_t	uid;
	u_int8_t	gpe_bit;
	u_int8_t	ec_id[1];
} __packed;

struct acpi_srat {
	struct acpi_table_header	hdr;
#define SRAT_SIG	"SRAT"
	u_int32_t	reserved1;
	u_int64_t	reserved2;
} __packed;

struct acpi_slit {
	struct acpi_table_header	hdr;
#define SLIT_SIG	"SLIT"
	u_int64_t	number_of_localities;
} __packed;

struct acpi_hpet {
	struct acpi_table_header	hdr;
#define HPET_SIG	"HPET"
	u_int32_t	event_timer_block_id;
	struct acpi_gas	base_address;
	u_int8_t	hpet_number;
	u_int16_t	main_counter_min_clock_tick;
	u_int8_t	page_protection;
} __packed;

struct acpi_mcfg {
	struct acpi_table_header	hdr;
#define MCFG_SIG	"MCFG"
	u_int8_t	reserved[8];
	u_int64_t	base_address;
	u_int16_t	segment;
	u_int8_t	min_bus_number;
	u_int8_t	max_bus_number;
	u_int32_t	reserved1;
} __packed;

struct acpi_facs {
	u_int8_t	signature[4];
#define	FACS_SIG	"FACS"
	u_int32_t	length;
	u_int32_t	hardware_signature;
	u_int32_t	wakeup_vector;
	u_int32_t	global_lock;
#define	FACS_LOCK_PENDING	0x00000001
#define	FACS_LOCK_OWNED		0x00000002
	u_int32_t	flags;
#define	FACS_S4BIOS_F		0x00000001	/* S4BIOS_REQ supported */
	uint64_t	x_wakeup_vector;
	u_int8_t	version;
	u_int8_t	reserved[31];
} __packed;

/*
 * Intel ACPI DMA Remapping Entries
 */
struct acpidmar_devpath {
	uint8_t		device;
	uint8_t		function;
} __packed;

struct acpidmar_devscope {
	uint8_t		type;
#define DMAR_ENDPOINT			0x1
#define DMAR_BRIDGE			0x2
#define DMAR_IOAPIC			0x3
#define DMAR_HPET			0x4
	uint8_t		length;
	uint16_t	reserved;
	uint8_t		enumid;
	uint8_t		bus;
} __packed;

/* DMA Remapping Hardware Unit */
struct acpidmar_drhd {
	uint16_t	type;
	uint16_t	length;

	uint8_t		flags;
	uint8_t		reserved;
	uint16_t	segment;
	uint64_t	address;
	/* struct acpidmar_devscope[]; */
} __packed;

/* Reserved Memory Region Reporting */
struct acpidmar_rmrr {
	uint16_t	type;
	uint16_t	length;

	uint16_t	reserved;
	uint16_t	segment;
	uint64_t	base;
	uint64_t	limit;
	/* struct acpidmar_devscope[]; */
} __packed;

/* Root Port ATS Capability Reporting */
struct acpidmar_atsr {
	uint16_t	type;
	uint16_t	length;

	uint8_t		flags;
	uint8_t		reserved;
	uint16_t	segment;
	/* struct acpidmar_devscope[]; */
} __packed;

union acpidmar_entry {
	struct {
		uint16_t	type;
#define DMAR_DRHD			0x0
#define DMAR_RMRR			0x1
#define DMAR_ATSR			0x2
#define DMAR_RHSA			0x3
		uint16_t	length;
	} __packed;
	struct acpidmar_drhd	drhd;
	struct acpidmar_rmrr	rmrr;
	struct acpidmar_atsr	atsr;
} __packed;

struct acpi_dmar {
	struct acpi_table_header	hdr;
#define DMAR_SIG	"DMAR"
	uint8_t		haw;
	uint8_t		flags;
	uint8_t		reserved[10];
	/* struct acpidmar_entry[]; */
} __packed;

/*
 * AMD I/O Virtualization Remapping Entries
 */
union acpi_ivhd_entry {
	uint8_t		type;
#define IVHD_ALL			1
#define IVHD_SEL			2
#define IVHD_SOR			3
#define IVHD_EOR			4
#define IVHD_ALIAS_SEL			66
#define IVHD_ALIAS_SOR			67
#define IVHD_EXT_SEL			70
#define IVHD_EXT_SOR			71
#define IVHD_SPECIAL			72
	struct {
		uint8_t		type;
		uint16_t	resvd;
		uint8_t		data;
	} __packed all;
	struct {
		uint8_t		type;
		uint16_t	devid;
		uint8_t		data;
	} __packed sel;
	struct {
		uint8_t		type;
		uint16_t	devid;
		uint8_t		data;
	} __packed sor;
	struct {
		uint8_t		type;
		uint16_t	devid;
		uint8_t		resvd;
	} __packed eor;
	struct {
		uint8_t		type;
		uint16_t	devid;
		uint8_t		data;
		uint8_t		resvd1;
		uint16_t	srcid;
		uint8_t		resvd2;
	} __packed alias;
	struct {
		uint8_t		type;
		uint16_t	devid;
		uint8_t		data;
		uint32_t	extdata;
#define IVHD_ATS_DIS			(1L << 31)
	} __packed ext;
	struct {
		uint8_t		type;
		uint16_t	resvd;
		uint8_t		data;
		uint8_t		handle;
		uint16_t	devid;
		uint8_t		variety;
#define IVHD_IOAPIC			0x01
#define IVHD_HPET			0x02
	} __packed special;
} __packed;

struct acpi_ivmd {
	uint8_t		type;
	uint8_t		flags;
#define	IVMD_EXCLRANGE			(1L << 3)
#define IVMD_IW				(1L << 2)
#define IVMD_IR				(1L << 1)
#define IVMD_UNITY			(1L << 0)
	uint16_t	length;
	uint16_t	devid;
	uint16_t	auxdata;
	uint8_t		reserved[8];
	uint64_t	base;
	uint64_t	limit;
} __packed;

struct acpi_ivhd {
	uint8_t		type;
	uint8_t		flags;
#define IVHD_IOTLB		(1L << 4)
#define IVHD_ISOC		(1L << 3)
#define IVHD_RESPASSPW		(1L << 2)
#define IVHD_PASSPW		(1L << 1)
#define IVHD_HTTUNEN		(1L << 0)
	uint16_t	length;
	uint16_t	devid;
	uint16_t	cap;
	uint64_t	address;
	uint16_t	segment;
	uint16_t	info;
#define IVHD_UNITID_SHIFT	8
#define IVHD_UNITID_MASK	0x1F
#define IVHD_MSINUM_SHIFT	0
#define IVHD_MSINUM_MASK	0x1F
	uint32_t	reserved;
} __packed;

union acpi_ivrs_entry {
	struct {
		uint8_t		type;
#define IVRS_IVHD			0x10
#define IVRS_IVMD_ALL			0x20
#define IVRS_IVMD_SPECIFIED		0x21
#define IVRS_IVMD_RANGE			0x22
		uint8_t		flags;
		uint16_t	length;
	} __packed;
	struct acpi_ivhd	ivhd;
	struct acpi_ivmd	ivmd;
} __packed;

struct acpi_ivrs {
	struct acpi_table_header	hdr;
#define IVRS_SIG	"IVRS"
	uint32_t		ivinfo;
#define IVRS_ATSRNG		(1L << 22)
#define IVRS_VASIZE_SHIFT	15
#define IVRS_VASIZE_MASK	0x7F
#define IVRS_PASIZE_SHIFT	8
#define IVRS_PASIZE_MASK	0x7F
	uint8_t			reserved[8];
} __packed;

#define ACPI_FREQUENCY	3579545		/* Per ACPI spec */

/*
 * PCI Configuration space
 */
#define ACPI_ADR_PCIDEV(addr)	(u_int16_t)(addr >> 16)
#define ACPI_ADR_PCIFUN(addr)	(u_int16_t)(addr & 0xFFFF)
#define ACPI_PCI_BUS(addr) (u_int16_t)((addr) >> 48)
#define ACPI_PCI_DEV(addr) (u_int16_t)((addr) >> 32)
#define ACPI_PCI_FN(addr)  (u_int16_t)((addr) >> 16)
#define ACPI_PCI_REG(addr) (u_int16_t)(addr)
#define ACPI_PCI_ADDR(b,d,f,r) ((u_int64_t)(b)<<48LL | (u_int64_t)(d)<<32LL | (f)<<16LL | (r))

/*
 * PM1 Status Registers Fixed Hardware Feature Status Bits
 */
#define	ACPI_PM1_STATUS			0x00
#define		ACPI_PM1_TMR_STS		0x0001
#define		ACPI_PM1_BM_STS			0x0010
#define		ACPI_PM1_GBL_STS		0x0020
#define		ACPI_PM1_PWRBTN_STS		0x0100
#define		ACPI_PM1_SLPBTN_STS		0x0200
#define		ACPI_PM1_RTC_STS		0x0400
#define		ACPI_PM1_PCIEXP_WAKE_STS	0x4000
#define		ACPI_PM1_WAK_STS		0x8000

#define	ACPI_PM1_ALL_STS (ACPI_PM1_TMR_STS | ACPI_PM1_BM_STS | \
	    ACPI_PM1_GBL_STS | ACPI_PM1_PWRBTN_STS | \
	    ACPI_PM1_SLPBTN_STS | ACPI_PM1_RTC_STS | \
	    ACPI_PM1_PCIEXP_WAKE_STS | ACPI_PM1_WAK_STS )

/*
 * PM1 Enable Registers
 */
#define	ACPI_PM1_ENABLE			0x02
#define		ACPI_PM1_TMR_EN			0x0001
#define		ACPI_PM1_GBL_EN			0x0020
#define		ACPI_PM1_PWRBTN_EN		0x0100
#define		ACPI_PM1_SLPBTN_EN		0x0200
#define		ACPI_PM1_RTC_EN			0x0400
#define		ACPI_PM1_PCIEXP_WAKE_DIS	0x4000

/*
 * PM1 Control Registers
 */
#define	ACPI_PM1_CONTROL		0x00
#define		ACPI_PM1_SCI_EN			0x0001
#define		ACPI_PM1_BM_RLD			0x0002
#define		ACPI_PM1_GBL_RLS		0x0004
#define		ACPI_PM1_SLP_TYPX(x)		((x) << 10)
#define		ACPI_PM1_SLP_TYPX_MASK		0x1c00
#define		ACPI_PM1_SLP_EN			0x2000

/*
 * PM2 Control Registers
 */
#define ACPI_PM2_CONTROL		0x06
#define	ACPI_PM2_ARB_DIS		0x0001

/*
 * Sleeping States
 */
#define ACPI_STATE_S0		0
#define ACPI_STATE_S1		1
#define ACPI_STATE_S2		2
#define ACPI_STATE_S3		3
#define ACPI_STATE_S4		4
#define ACPI_STATE_S5		5

/*
 * Device Power States
 */
#define ACPI_STATE_D0		0
#define ACPI_STATE_D1		1
#define ACPI_STATE_D2		2
#define ACPI_STATE_D3		3

/*
 * ACPI Device IDs
 */
#define ACPI_DEV_TIM	"PNP0100"	/* System timer */
#define ACPI_DEV_ACPI	"PNP0C08"	/* ACPI device */
#define ACPI_DEV_PCIB	"PNP0A03"	/* PCI bus */
#define ACPI_DEV_GISAB	"PNP0A05"	/* Generic ISA Bus */
#define ACPI_DEV_EIOB	"PNP0A06"	/* Extended I/O Bus */
#define ACPI_DEV_PCIEB	"PNP0A08"	/* PCIe bus */
#define ACPI_DEV_MR	"PNP0C02"	/* Motherboard resources */
#define ACPI_DEV_NPROC	"PNP0C04"	/* Numeric data processor */
#define ACPI_DEV_CS	"PNP0C08"	/* ACPI-Compliant System */
#define ACPI_DEV_ECD	"PNP0C09"	/* Embedded Controller Device */
#define ACPI_DEV_CMB	"PNP0C0A"	/* Control Method Battery */
#define ACPI_DEV_FAN	"PNP0C0B"	/* Fan Device */
#define ACPI_DEV_PBD	"PNP0C0C"	/* Power Button Device */
#define ACPI_DEV_LD	"PNP0C0D"	/* Lid Device */
#define ACPI_DEV_SBD	"PNP0C0E"	/* Sleep Button Device */
#define ACPI_DEV_PILD	"PNP0C0F"	/* PCI Interrupt Link Device */
#define ACPI_DEV_MEMD	"PNP0C80"	/* Memory Device */
#define ACPI_DEV_MOUSE	"PNP0F13"	/* PS/2 Mouse */
#define ACPI_DEV_SHC	"ACPI0001"	/* SMBus 1.0 Host Controller */
#define ACPI_DEV_SMS1	"ACPI0002"	/* Smart Battery Subsystem */
#define ACPI_DEV_AC	"ACPI0003"	/* AC Device */
#define ACPI_DEV_MD	"ACPI0004"	/* Module Device */
#define ACPI_DEV_SMS2	"ACPI0005"	/* SMBus 2.0 Host Controller */
#define ACPI_DEV_GBD	"ACPI0006"	/* GPE Block Device */
#define ACPI_DEV_PD	"ACPI0007"	/* Processor Device */
#define ACPI_DEV_ALSD	"ACPI0008"	/* Ambient Light Sensor Device */
#define ACPI_DEV_IOXA	"ACPI0009"	/* IO x APIC Device */
#define ACPI_DEV_IOA	"ACPI000A"	/* IO APIC Device */
#define ACPI_DEV_IOSA	"ACPI000B"	/* IO SAPIC Device */
#define ACPI_DEV_THZ	"THERMALZONE"	/* Thermal Zone */
#define ACPI_DEV_FFB	"FIXEDBUTTON"	/* Fixed Feature Button */
#define ACPI_DEV_ASUS	"ASUS010"	/* ASUS Hotkeys */
#define ACPI_DEV_ASUS1	"ATK0100"	/* ASUS Special Device */
#define ACPI_DEV_IBM	"IBM0068"	/* IBM ThinkPad support */
#define ACPI_DEV_LENOVO	"LEN0068"	/* Lenovo ThinkPad support */
#define ACPI_DEV_ASUSAIBOOSTER	"ATK0110"	/* ASUSTeK AI Booster */
#define ACPI_DEV_TOSHIBA_LIBRETTO	"TOS6200"	/* Toshiba Libretto support */
#define ACPI_DEV_TOSHIBA_DYNABOOK	"TOS6207"	/* Toshiba Dynabook support */
#define ACPI_DEV_TOSHIBA_SPA40	"TOS6208"	/* Toshiba SPA40 support */

#endif	/* !_DEV_ACPI_ACPIREG_H_ */


code:
/* $OpenBSD: acpisony.c,v 1.6 2014/09/14 14:17:24 jsg Exp $ */
/*
 * Copyright (c) 2010 Paul Irofti <pirofti@openbsd.org>
 *
 * Permission to use, copy, modify, and/or 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/systm.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 <machine/apmvar.h>

int	acpisony_match(struct device *, void *, void *);
void	acpisony_attach(struct device *, struct device *, void *);
int	acpisony_activate(struct device *, int);
int	acpisony_notify(struct aml_node *, int, void *);

#ifdef ACPISONY_DEBUG
#define DPRINTF(x)	printf x
#else
#define DPRINTF(x)
#endif

/* Notifications */
#define	SONY_NOTIFY_FN_KEY			0x90

#define	SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED	0x85
#define	SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED	0x05
#define	SONY_NOTIFY_BRIGHTNESS_UP_PRESSED	0x86
#define	SONY_NOTIFY_BRIGHTNESS_UP_RELEASED	0x06

#define	SONY_NOTIFY_DISPLAY_SWITCH_PRESSED	0x87
#define	SONY_NOTIFY_DISPLAY_SWITCH_RELEASED	0x07

#define	SONY_NOTIFY_ZOOM_OUT_PRESSED		0x89
#define	SONY_NOTIFY_ZOOM_OUT_RELEASED		0x09

#define	SONY_NOTIFY_ZOOM_IN_PRESSED		0x8a
#define	SONY_NOTIFY_ZOOM_IN_RELEASED		0x0a

#define	SONY_NOTIFY_SUSPEND_PRESSED		0x8c
#define	SONY_NOTIFY_SUSPEND_RELEASED		0x0c

struct acpisony_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;
};

struct cfattach acpisony_ca = {
	sizeof(struct acpisony_softc), acpisony_match, acpisony_attach,
	NULL, acpisony_activate
};

struct cfdriver acpisony_cd = {
	NULL, "acpisony", DV_DULL
};

void acpisony_notify_setup(struct acpisony_softc *);
int acpisony_set_hotkey(struct acpisony_softc *, int, int);
int acpisony_find_offset(struct acpisony_softc *, int);

void acpisony_brightness_down(struct acpisony_softc *);
int acpisony_get_brightness(struct acpisony_softc *);
void acpisony_set_brightness(struct acpisony_softc *, int);

int
acpisony_match(struct device *parent, void *match, void *aux)
{
	struct acpi_attach_args *aa = aux;
	struct cfdata		*cf = match;

	if (aa->aaa_name == NULL ||
	    strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
	    aa->aaa_table != NULL)
		return (0);

	return (1);
}

void
acpisony_attach(struct device *parent, struct device *self, void *aux)
{
	struct acpisony_softc	*sc = (struct acpisony_softc *)self;
	struct acpi_attach_args *aa = aux;

	sc->sc_acpi = (struct acpi_softc *)parent;
	sc->sc_devnode = aa->aaa_node;

	printf(": %s\n", sc->sc_devnode->name);

	/* Setup the notification masks */
	acpisony_notify_setup(sc);

	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
	    acpisony_notify, sc, ACPIDEV_NOPOLL);
}

int
acpisony_activate(struct device *self, int act)
{
	struct acpisony_softc *sc = (struct acpisony_softc *)self;

	switch (act) {
	case DVACT_WAKEUP:
		acpisony_notify_setup(sc);
		break;
	}
	return 0;
}

int
acpisony_notify(struct aml_node *node, int notify, void *arg)
{
	struct acpisony_softc *sc = arg;
	int val, key = 0;

	if (notify == SONY_NOTIFY_FN_KEY) {
		notify -= 0x90;
		DPRINTF(("notify = %X", notify));

		if (notify == acpisony_find_offset(sc, 0x100)) {
			DPRINTF(("key = 0x100\n"));
			key = 0x100;
		}
		if (notify == acpisony_find_offset(sc, 0x127)) {
			DPRINTF(("key = 0x127\n"));
			key = 0x127;
		}

		if (key) {
			val = acpisony_set_hotkey(sc, key, 0x200);
			if (val < 0) {
				printf("returned val = %X", val);
				return 1;
			}
			notify = val & 0xff;

			DPRINTF(("Treat %X events, notify %X\n", key, notify));
		} else
			DPRINTF(("rfkill update, notify %X\n", notify));
	}

	switch (notify) {
	case SONY_NOTIFY_BRIGHTNESS_DOWN_PRESSED:
		DPRINTF(("br-down-pressed\n"));
		acpisony_brightness_down(sc);
		break;
	case SONY_NOTIFY_BRIGHTNESS_DOWN_RELEASED:
		DPRINTF(("br-down-released\n"));
		break;
	case SONY_NOTIFY_BRIGHTNESS_UP_PRESSED:
		DPRINTF(("br-up-pressed\n"));
		break;
	case SONY_NOTIFY_BRIGHTNESS_UP_RELEASED:
		DPRINTF(("br-up-released\n"));
		break;
	case SONY_NOTIFY_DISPLAY_SWITCH_PRESSED:
		DPRINTF(("display-pressed\n"));
		break;
	case SONY_NOTIFY_DISPLAY_SWITCH_RELEASED:
		DPRINTF(("display-released\n"));
		break;
	case SONY_NOTIFY_ZOOM_IN_PRESSED:
		DPRINTF(("zoom-in-pressed\n"));
		break;
	case SONY_NOTIFY_ZOOM_IN_RELEASED:
		DPRINTF(("zoom-in-released\n"));
		break;
	case SONY_NOTIFY_ZOOM_OUT_PRESSED:
		DPRINTF(("zoom-out-pressed\n"));
		break;
	case SONY_NOTIFY_ZOOM_OUT_RELEASED:
		DPRINTF(("zoom-out-released\n"));
		break;
	case SONY_NOTIFY_SUSPEND_PRESSED:
		DPRINTF(("suspend-pressed\n"));
#ifndef SMALL_KERNEL
		if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ))
			acpi_addtask(sc->sc_acpi, acpi_sleep_task,
			    sc->sc_acpi, ACPI_STATE_S3);
#endif
		break;
	case SONY_NOTIFY_SUSPEND_RELEASED:
		DPRINTF(("suspend-released\n"));
		break;
	default:
		printf("%s: unknown event 0x%02x\n", DEVNAME(sc), notify);
		break;
	}

	return 0;
}

void
acpisony_notify_setup(struct acpisony_softc *sc)
{
	struct aml_value arg;

	bzero(&arg, sizeof(arg));
	arg.type = AML_OBJTYPE_INTEGER;

	arg.v_integer = 1;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "ECON", 1, &arg, NULL);

	/* Enable all events */
	arg.v_integer = 0xffff;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);

	/* Enable hotkeys */
	arg.v_integer = 0x04;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
	arg.v_integer = 0x02;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
	arg.v_integer = 0x10;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN02", 1, &arg, NULL);
	arg.v_integer = 0x00;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
	arg.v_integer = 0x02;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN03", 1, &arg, NULL);
	arg.v_integer = 0x101;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, NULL);
}

int
acpisony_find_offset(struct acpisony_softc *sc, int key)
{
	struct aml_value arg, res;
	int val;

	bzero(&arg, sizeof(arg));
	arg.type = AML_OBJTYPE_INTEGER;

	for (arg.v_integer = 0x20; arg.v_integer < 0x30; arg.v_integer++) {
		aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN00", 1, &arg, &res);
		val = aml_val2int(&res);
		aml_freevalue(&res);
		if (val == key) {
			DPRINTF(("Matched key %X\n", val));
			return arg.v_integer - 0x20;
		}
	}

	return -1;
}

int
acpisony_set_hotkey(struct acpisony_softc *sc, int key, int val)
{
	int off, rc = -1;
	struct aml_value res, arg;

	bzero(&arg, sizeof(arg));
	arg.type = AML_OBJTYPE_INTEGER;

	off = acpisony_find_offset(sc, key);
	DPRINTF(("off = %X\n", off));
	if (off < 0)
		return rc;

	arg.v_integer = off | val;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SN07", 1, &arg, &res);
	rc = aml_val2int(&res);
	aml_freevalue(&res);

	return rc;
}

void
acpisony_brightness_down(struct acpisony_softc *sc)
{
	int val;

	val = acpisony_get_brightness(sc);
	DPRINTF(("current value = %X", val));
	if (val > 0)
		val--;
	else
		val = 0;
	DPRINTF(("next value = %X", val));
	acpisony_set_brightness(sc, val);
}

int
acpisony_get_brightness(struct acpisony_softc *sc)
{
	struct aml_value res;
	int val;

	aml_evalname(sc->sc_acpi, sc->sc_devnode, "GBRT", 0, NULL, &res);
	val = aml_val2int(&res);
	aml_freevalue(&res);

	return val;
}

void
acpisony_set_brightness(struct acpisony_softc *sc, int level)
{
	struct aml_value arg;

	bzero(&arg, sizeof(arg));
	arg.type = AML_OBJTYPE_INTEGER;
	arg.v_integer = level;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBRT", 1, &arg, NULL);
	aml_freevalue(&arg);
}


code:
/*	$OpenBSD: acpithinkpad.c,v 1.44 2015/04/24 14:44:17 deraadt Exp $	*/
/*
 * Copyright (c) 2008 joshua stein <jcs@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/systm.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 <machine/apmvar.h>

#include "audio.h"
#include "wskbd.h"

#define	THINKPAD_HKEY_VERSION1		0x0100
#define	THINKPAD_HKEY_VERSION2		0x0200

#define	THINKPAD_CMOS_VOLUME_DOWN	0x00
#define	THINKPAD_CMOS_VOLUME_UP		0x01
#define	THINKPAD_CMOS_VOLUME_MUTE	0x02
#define	THINKPAD_CMOS_BRIGHTNESS_UP	0x04
#define	THINKPAD_CMOS_BRIGHTNESS_DOWN	0x05

#define	THINKPAD_BLUETOOTH_PRESENT	0x01
#define	THINKPAD_BLUETOOTH_ENABLED	0x02

/* wan (not wifi) card */
#define	THINKPAD_WAN_PRESENT		0x01
#define	THINKPAD_WAN_ENABLED		0x02

#define	THINKPAD_BUTTON_FN_F1		0x1001
#define	THINKPAD_BUTTON_LOCK_SCREEN	0x1002
#define	THINKPAD_BUTTON_BATTERY_INFO	0x1003
#define	THINKPAD_BUTTON_SUSPEND		0x1004
#define	THINKPAD_BUTTON_WIRELESS	0x1005
#define	THINKPAD_BUTTON_FN_F6		0x1006
#define	THINKPAD_BUTTON_EXTERNAL_SCREEN	0x1007
#define	THINKPAD_BUTTON_POINTER_SWITCH	0x1008
#define	THINKPAD_BUTTON_EJECT		0x1009
#define	THINKPAD_BUTTON_BRIGHTNESS_UP	0x1010
#define	THINKPAD_BUTTON_BRIGHTNESS_DOWN	0x1011
#define	THINKPAD_BUTTON_THINKLIGHT	0x1012
#define	THINKPAD_BUTTON_FN_SPACE	0x1014
#define	THINKPAD_BUTTON_VOLUME_UP	0x1015
#define	THINKPAD_BUTTON_VOLUME_DOWN	0x1016
#define	THINKPAD_BUTTON_VOLUME_MUTE	0x1017
#define	THINKPAD_BUTTON_THINKVANTAGE	0x1018
#define	THINKPAD_BUTTON_BLACK		0x101a
#define	THINKPAD_BUTTON_MICROPHONE_MUTE	0x101b
#define	THINKPAD_BUTTON_FN_F11		0x100b
#define	THINKPAD_BUTTON_HIBERNATE	0x100c
#define	THINKPAD_KEYLIGHT_CHANGED	0x101c
#define	THINKPAD_BUTTON_CONFIG		0x101d
#define	THINKPAD_BUTTON_FIND		0x101e
#define	THINKPAD_BUTTON_ALL_ACTIVEPROGS	0x101f
#define	THINKPAD_BUTTON_ALL_PROGS	0x1020

#define	THINKPAD_ADAPTIVE_NEXT		0x1101
#define	THINKPAD_ADAPTIVE_QUICK		0x1102
#define	THINKPAD_ADAPTIVE_SNIP		0x1105
#define	THINKPAD_ADAPTIVE_VOICE		0x1108
#define	THINKPAD_ADAPTIVE_GESTURES	0x110a
#define	THINKPAD_ADAPTIVE_SETTINGS	0x110e
#define	THINKPAD_ADAPTIVE_TAB		0x110f
#define	THINKPAD_ADAPTIVE_REFRESH	0x1110
#define	THINKPAD_ADAPTIVE_BACK		0x1111
#define THINKPAD_PORT_REPL_DOCKED	0x4010
#define THINKPAD_PORT_REPL_UNDOCKED	0x4011
#define	THINKPAD_LID_OPEN		0x5001
#define	THINKPAD_LID_CLOSED		0x5002
#define	THINKPAD_TABLET_SCREEN_NORMAL	0x500a
#define	THINKPAD_TABLET_SCREEN_ROTATED	0x5009
#define	THINKPAD_BRIGHTNESS_CHANGED	0x5010
#define	THINKPAD_TABLET_PEN_INSERTED	0x500b
#define	THINKPAD_TABLET_PEN_REMOVED	0x500c
#define	THINKPAD_SWITCH_NUMLOCK		0x6000
#define	THINKPAD_THERMAL_TABLE_CHANGED	0x6030
#define	THINKPAD_POWER_CHANGED		0x6040
#define	THINKPAD_BACKLIGHT_CHANGED	0x6050
#define	THINKPAD_BUTTON_FN_TOGGLE       0x6060
#define	THINKPAD_TABLET_SCREEN_CHANGED	0x60c0
#define	THINKPAD_SWITCH_WIRELESS	0x7000

#define THINKPAD_NSENSORS 9
#define THINKPAD_NTEMPSENSORS 8

#define THINKPAD_ECOFFSET_FANLO		0x84
#define THINKPAD_ECOFFSET_FANHI		0x85

#define	THINKPAD_ADAPTIVE_MODE_HOME	1
#define	THINKPAD_ADAPTIVE_MODE_FUNCTION	3

struct acpithinkpad_softc {
	struct device		 sc_dev;

	struct acpiec_softc     *sc_ec;
	struct acpi_softc	*sc_acpi;
	struct aml_node		*sc_devnode;

	struct ksensor		 sc_sens[THINKPAD_NSENSORS];
	struct ksensordev	 sc_sensdev;
};

extern void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);

int	thinkpad_match(struct device *, void *, void *);
void	thinkpad_attach(struct device *, struct device *, void *);
int	thinkpad_hotkey(struct aml_node *, int, void *);
int	thinkpad_enable_events(struct acpithinkpad_softc *);
int	thinkpad_toggle_bluetooth(struct acpithinkpad_softc *);
int	thinkpad_toggle_wan(struct acpithinkpad_softc *);
int	thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t);
int	thinkpad_volume_down(struct acpithinkpad_softc *);
int	thinkpad_volume_up(struct acpithinkpad_softc *);
int	thinkpad_volume_mute(struct acpithinkpad_softc *);
int	thinkpad_brightness_up(struct acpithinkpad_softc *);
int	thinkpad_brightness_down(struct acpithinkpad_softc *);
int	thinkpad_adaptive_change(struct acpithinkpad_softc *);
int	thinkpad_activate(struct device *, int);

void    thinkpad_sensor_attach(struct acpithinkpad_softc *sc);
void    thinkpad_sensor_refresh(void *);

#if NAUDIO > 0 && NWSKBD > 0
extern int wskbd_set_mixervolume(long, long);
#endif

struct cfattach acpithinkpad_ca = {
	sizeof(struct acpithinkpad_softc), thinkpad_match, thinkpad_attach,
	NULL, thinkpad_activate
};

struct cfdriver acpithinkpad_cd = {
	NULL, "acpithinkpad", DV_DULL
};

const char *acpithinkpad_hids[] = {
	ACPI_DEV_IBM, ACPI_DEV_LENOVO, 0
};

int
thinkpad_match(struct device *parent, void *match, void *aux)
{
	struct acpi_attach_args	*aa = aux;
	struct cfdata *cf = match;
	int64_t	res;

	if (!acpi_matchhids(aa, acpithinkpad_hids, cf->cf_driver->cd_name))
		return (0);

	if (aml_evalinteger((struct acpi_softc *)parent, aa->aaa_node,
	    "MHKV", 0, NULL, &res))
		return (0);

	if (!(res == THINKPAD_HKEY_VERSION1 || res == THINKPAD_HKEY_VERSION2))
		return (0);

	return (1);
}

void
thinkpad_sensor_attach(struct acpithinkpad_softc *sc)
{
	int i;

	if (sc->sc_acpi->sc_ec == NULL)
		return;
	sc->sc_ec = sc->sc_acpi->sc_ec;

	/* Add temperature probes */
	strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
	    sizeof(sc->sc_sensdev.xname));
	for (i=0; i<THINKPAD_NTEMPSENSORS; i++) {
		sc->sc_sens[i].type = SENSOR_TEMP;
		sensor_attach(&sc->sc_sensdev, &sc->sc_sens[i]);
	}

	/* Add fan probe */
	sc->sc_sens[i].type = SENSOR_FANRPM;
	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[i]);

	sensordev_install(&sc->sc_sensdev);
}

void
thinkpad_sensor_refresh(void *arg)
{
	struct acpithinkpad_softc *sc = arg;
	u_int8_t lo, hi, i;
	int64_t tmp;
	char sname[5];

	/* Refresh sensor readings */
	for (i=0; i<THINKPAD_NTEMPSENSORS; i++) {
		snprintf(sname, sizeof(sname), "TMP%d", i);
		aml_evalinteger(sc->sc_acpi, sc->sc_ec->sc_devnode,
		    sname, 0, 0, &tmp);
		sc->sc_sens[i].value = (tmp * 1000000) + 273150000;
		if (tmp > 127 || tmp < -127)
			sc->sc_sens[i].flags = SENSOR_FINVALID;
	}

	/* Read fan RPM */
	acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANLO, 1, &lo);
	acpiec_read(sc->sc_ec, THINKPAD_ECOFFSET_FANHI, 1, &hi);
	sc->sc_sens[i].value = ((hi << 8L) + lo);
}

void
thinkpad_attach(struct device *parent, struct device *self, void *aux)
{
	struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self;
	struct acpi_attach_args	*aa = aux;

	sc->sc_acpi = (struct acpi_softc *)parent;
	sc->sc_devnode = aa->aaa_node;

	printf("\n");

	/* Set event mask to receive everything */
	thinkpad_enable_events(sc);
	thinkpad_sensor_attach(sc);

	/* Run thinkpad_hotkey on button presses */
	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
	    thinkpad_hotkey, sc, ACPIDEV_POLL);
}

int
thinkpad_enable_events(struct acpithinkpad_softc *sc)
{
	struct aml_value arg, args[2];
	int64_t	mask;
	int i;

	/* Get the supported event mask */
	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKA",
	    0, NULL, &mask)) {
		printf("%s: no MHKA\n", DEVNAME(sc));
		return (1);
	}

	/* Update hotkey mask */
	bzero(args, sizeof(args));
	args[0].type = args[1].type = AML_OBJTYPE_INTEGER;
	for (i = 0; i < 32; i++) {
		args[0].v_integer = i + 1;
		args[1].v_integer = (((1 << i) & mask) != 0);

		if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKM",
		    2, args, NULL)) {
			printf("%s: couldn't toggle MHKM\n", DEVNAME(sc));
			return (1);
		}
	}

	/* Enable hotkeys */
	bzero(&arg, sizeof(arg));
	arg.type = AML_OBJTYPE_INTEGER;
	arg.v_integer = 1;
	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "MHKC",
	    1, &arg, NULL)) {
		printf("%s: couldn't enable hotkeys\n", DEVNAME(sc));
		return (1);
	}

	return (0);
}

int
thinkpad_hotkey(struct aml_node *node, int notify_type, void *arg)
{
	struct acpithinkpad_softc *sc = arg;
	int handled = 0;
	int64_t	event;

	if (notify_type == 0x00) {
		/* Poll sensors */
		thinkpad_sensor_refresh(sc);
		return (0);
	}

	if (notify_type != 0x80)
		return (1);

	for (;;) {
		if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "MHKP",
		    0, NULL, &event))
			break;
		if (event == 0)
			break;

		switch (event) {
		case THINKPAD_BUTTON_BRIGHTNESS_UP:
			thinkpad_brightness_up(sc);
			handled = 1;
			break;
		case THINKPAD_BUTTON_BRIGHTNESS_DOWN:
			thinkpad_brightness_down(sc);
			handled = 1;
			break;
		case THINKPAD_BUTTON_WIRELESS:
			thinkpad_toggle_bluetooth(sc);
			handled = 1;
			break;
		case THINKPAD_BUTTON_SUSPEND:
#ifndef SMALL_KERNEL
			if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ))
				acpi_addtask(sc->sc_acpi, acpi_sleep_task,
				    sc->sc_acpi, ACPI_STATE_S3);
#endif
			handled = 1;
			break;
		case THINKPAD_BUTTON_VOLUME_MUTE:
			thinkpad_volume_mute(sc);
			handled = 1;
			break;
		case THINKPAD_BUTTON_VOLUME_DOWN:
			thinkpad_volume_down(sc);
			handled = 1;
			break;
		case THINKPAD_BUTTON_VOLUME_UP:
			thinkpad_volume_up(sc);
			handled = 1;
			break;
		case THINKPAD_BUTTON_MICROPHONE_MUTE:
#if NAUDIO > 0 && NWSKBD > 0
			wskbd_set_mixervolume(0, 0);
#endif
			handled = 1;
			break;
		case THINKPAD_BUTTON_HIBERNATE:
#if defined(HIBERNATE) && !defined(SMALL_KERNEL)
			if (acpi_record_event(sc->sc_acpi, APM_USER_HIBERNATE_REQ))
				acpi_addtask(sc->sc_acpi, acpi_sleep_task,
				    sc->sc_acpi, ACPI_STATE_S4);
#endif
			handled = 1;
			break;
		case THINKPAD_ADAPTIVE_NEXT:
		case THINKPAD_ADAPTIVE_QUICK:
			thinkpad_adaptive_change(sc);
			handled = 1;
			break;
		case THINKPAD_ADAPTIVE_BACK:
		case THINKPAD_ADAPTIVE_GESTURES:
		case THINKPAD_ADAPTIVE_REFRESH:
		case THINKPAD_ADAPTIVE_SETTINGS:
		case THINKPAD_ADAPTIVE_SNIP:
		case THINKPAD_ADAPTIVE_TAB:
		case THINKPAD_ADAPTIVE_VOICE:
		case THINKPAD_BACKLIGHT_CHANGED:
		case THINKPAD_KEYLIGHT_CHANGED:
		case THINKPAD_BRIGHTNESS_CHANGED:
		case THINKPAD_BUTTON_BATTERY_INFO:
		case THINKPAD_BUTTON_EJECT:
		case THINKPAD_BUTTON_EXTERNAL_SCREEN:
		case THINKPAD_BUTTON_FN_F11:
		case THINKPAD_BUTTON_FN_F1:
		case THINKPAD_BUTTON_FN_F6:
		case THINKPAD_BUTTON_FN_SPACE:
		case THINKPAD_BUTTON_FN_TOGGLE:
		case THINKPAD_BUTTON_LOCK_SCREEN:
		case THINKPAD_BUTTON_POINTER_SWITCH:
		case THINKPAD_BUTTON_THINKLIGHT:
		case THINKPAD_BUTTON_THINKVANTAGE:
		case THINKPAD_BUTTON_BLACK:
		case THINKPAD_BUTTON_CONFIG:
		case THINKPAD_BUTTON_FIND:
		case THINKPAD_BUTTON_ALL_ACTIVEPROGS:
		case THINKPAD_BUTTON_ALL_PROGS:
		case THINKPAD_LID_CLOSED:
		case THINKPAD_LID_OPEN:
		case THINKPAD_PORT_REPL_DOCKED:
		case THINKPAD_PORT_REPL_UNDOCKED:
		case THINKPAD_POWER_CHANGED:
		case THINKPAD_SWITCH_WIRELESS:
		case THINKPAD_TABLET_PEN_INSERTED:
		case THINKPAD_TABLET_PEN_REMOVED:
		case THINKPAD_SWITCH_NUMLOCK:
		case THINKPAD_TABLET_SCREEN_NORMAL:
		case THINKPAD_TABLET_SCREEN_ROTATED:
		case THINKPAD_TABLET_SCREEN_CHANGED:
		case THINKPAD_THERMAL_TABLE_CHANGED:
			handled = 1;
			break;
		default:
			printf("%s: unknown event 0x%03llx\n",
			    DEVNAME(sc), event);
		}
	}

	return (handled);
}

int
thinkpad_toggle_bluetooth(struct acpithinkpad_softc *sc)
{
	struct aml_value arg;
	int64_t	bluetooth;

	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GBDC",
	    0, NULL, &bluetooth))
		return (1);

	if (!(bluetooth & THINKPAD_BLUETOOTH_PRESENT))
		return (1);

	bzero(&arg, sizeof(arg));
	arg.type = AML_OBJTYPE_INTEGER;
	arg.v_integer = bluetooth ^ THINKPAD_BLUETOOTH_ENABLED;
	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SBDC",
	    1, &arg, NULL)) {
		printf("%s: couldn't toggle bluetooth\n", DEVNAME(sc));
		return (1);
	}

	return (0);
}

int
thinkpad_toggle_wan(struct acpithinkpad_softc *sc)
{
	struct aml_value arg;
	int64_t wan;

	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GWAN",
	    0, NULL, &wan))
		return (1);

	if (!(wan & THINKPAD_WAN_PRESENT))
		return (1);

	bzero(&arg, sizeof(arg));
	arg.type = AML_OBJTYPE_INTEGER;
	arg.v_integer = wan ^ THINKPAD_WAN_ENABLED;
	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "SWAN",
	    1, &arg, NULL)) {
		printf("%s: couldn't toggle wan\n", DEVNAME(sc));
		return (1);
	}

	return (0);
}

int
thinkpad_cmos(struct acpithinkpad_softc *sc, uint8_t cmd)
{
	struct aml_value arg;

	bzero(&arg, sizeof(arg));
	arg.type = AML_OBJTYPE_INTEGER;
	arg.v_integer = cmd;
	aml_evalname(sc->sc_acpi, sc->sc_devnode, "\\UCMS", 1, &arg, NULL);
	return (0);
}

int
thinkpad_volume_down(struct acpithinkpad_softc *sc)
{
	return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_DOWN));
}

int
thinkpad_volume_up(struct acpithinkpad_softc *sc)
{
	return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_UP));
}

int
thinkpad_volume_mute(struct acpithinkpad_softc *sc)
{
	return (thinkpad_cmos(sc, THINKPAD_CMOS_VOLUME_MUTE));
}

int
thinkpad_brightness_up(struct acpithinkpad_softc *sc)
{
	return (thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_UP));
}

int
thinkpad_brightness_down(struct acpithinkpad_softc *sc)
{
	return (thinkpad_cmos(sc, THINKPAD_CMOS_BRIGHTNESS_DOWN));
}

int
thinkpad_adaptive_change(struct acpithinkpad_softc *sc)
{
	struct aml_value arg;
	int64_t	mode;

	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GTRW",
	    0, NULL, &mode)) {
		printf("%s: couldn't get adaptive keyboard mode\n", DEVNAME(sc));
		return (1);
	}

	bzero(&arg, sizeof(arg));
	arg.type = AML_OBJTYPE_INTEGER;

	if (mode == THINKPAD_ADAPTIVE_MODE_FUNCTION)
		arg.v_integer = THINKPAD_ADAPTIVE_MODE_HOME;
	else
		arg.v_integer = THINKPAD_ADAPTIVE_MODE_FUNCTION;

	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "STRW",
	    1, &arg, NULL)) {
		printf("%s: couldn't set adaptive keyboard mode\n", DEVNAME(sc));
		return (1);
	}

	return (0);
}

int
thinkpad_activate(struct device *self, int act)
{

	struct acpithinkpad_softc *sc = (struct acpithinkpad_softc *)self;
	int64_t res;

	switch(act) {
	case DVACT_WAKEUP:
		if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "GTRW",
		    0, NULL, &res) == 0)
			thinkpad_adaptive_change(sc);
		break;
	}
	return (0);
}


code:
/* $OpenBSD: acpitimer.c,v 1.11 2015/03/14 03:38:46 jsg Exp $ */
/*
 * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
 *
 * 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/systm.h>
#include <sys/device.h>
#include <sys/timetc.h>

#include <machine/bus.h>

#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>

int acpitimermatch(struct device *, void *, void *);
void acpitimerattach(struct device *, struct device *, void *);

u_int acpi_get_timecount(struct timecounter *tc);

static struct timecounter acpi_timecounter = {
	acpi_get_timecount,	/* get_timecount */
	0,			/* no poll_pps */
	0x00ffffff,		/* counter_mask (24 bits) */
	ACPI_FREQUENCY,		/* frequency */
	0,			/* name */
	1000			/* quality */
};

struct acpitimer_softc {
	struct device		sc_dev;

	bus_space_tag_t		sc_iot;
	bus_space_handle_t	sc_ioh;
};

struct cfattach acpitimer_ca = {
	sizeof(struct acpitimer_softc), acpitimermatch, acpitimerattach
};

struct cfdriver acpitimer_cd = {
	NULL, "acpitimer", DV_DULL
};

int
acpitimermatch(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);

	return (1);
}

void
acpitimerattach(struct device *parent, struct device *self, void *aux)
{
	struct acpitimer_softc *sc = (struct acpitimer_softc *) self;
	struct acpi_softc *psc = (struct acpi_softc *) parent;
	int rc;

	if (psc->sc_fadt->hdr_revision >= 3 &&
	    psc->sc_fadt->x_pm_tmr_blk.address != 0)
		rc = acpi_map_address(psc, &psc->sc_fadt->x_pm_tmr_blk, 0,
		    psc->sc_fadt->pm_tmr_len, &sc->sc_ioh, &sc->sc_iot);
	else
		rc = acpi_map_address(psc, NULL, psc->sc_fadt->pm_tmr_blk,
		    psc->sc_fadt->pm_tmr_len, &sc->sc_ioh, &sc->sc_iot);
	if (rc) {
		printf(": can't map i/o space\n");
		return;
	}

	printf(": %d Hz, %d bits\n", ACPI_FREQUENCY,
	    psc->sc_fadt->flags & FADT_TMR_VAL_EXT ? 32 : 24);

	if (psc->sc_fadt->flags & FADT_TMR_VAL_EXT)
		acpi_timecounter.tc_counter_mask = 0xffffffffU;
	acpi_timecounter.tc_priv = sc;
	acpi_timecounter.tc_name = sc->sc_dev.dv_xname;
	tc_init(&acpi_timecounter);
}

u_int
acpi_get_timecount(struct timecounter *tc)
{
	struct acpitimer_softc *sc = tc->tc_priv;
	u_int u1, u2, u3;

	u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0);
	u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0);
	do {
		u1 = u2;
		u2 = u3;
		u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0);
	} while (u1 > u2 || u2 > u3);

	return (u2);
}


code:
/* $OpenBSD: acpitoshiba.c,v 1.4 2015/03/14 03:38:46 jsg Exp $ */
/*-
 * Copyright (c) 2003 Hiroyuki Aizu <aizu@navi.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */
#include <sys/param.h>
#include <sys/systm.h>

#include <dev/acpi/acpivar.h>
#include <dev/acpi/acpidev.h>
#include <dev/acpi/amltypes.h>
#include <dev/acpi/dsdt.h>

#include <machine/apmvar.h>
#include <dev/wscons/wsconsio.h>

/*
 * Toshiba HCI interface definitions
 *
 * HCI is Toshiba's "Hardware Control Interface" which is supposed to
 * be uniform across all their models.	Ideally we would just call
 * dedicated ACPI methods instead of using this primitive interface.
 * However, the ACPI methods seem to be incomplete in some areas (for
 * example they allow setting, but not reading, the LCD brightness
 * value), so this is still useful.
 */
#define	METHOD_HCI			"GHCI"
#define	METHOD_HCI_ENABLE		"ENAB"

/* Operations */
#define	HCI_SET				0xFF00
#define	HCI_GET				0xFE00

/* Functions */
#define	HCI_REG_SYSTEM_EVENT		0x0016
#define	HCI_REG_VIDEO_OUTPUT		0x001C
#define	HCI_REG_LCD_BRIGHTNESS		0x002A

/* Field definitions */
#define	HCI_LCD_BRIGHTNESS_BITS		3
#define	HCI_LCD_BRIGHTNESS_SHIFT	(16 - HCI_LCD_BRIGHTNESS_BITS)
#define	HCI_LCD_BRIGHTNESS_MAX		((1 << HCI_LCD_BRIGHTNESS_BITS) - 1)
#define	HCI_LCD_BRIGHTNESS_MIN		0
#define	HCI_VIDEO_OUTPUT_FLAG		0x0100
#define	HCI_VIDEO_OUTPUT_CYCLE_MIN	0
#define	HCI_VIDEO_OUTPUT_CYCLE_MAX	7

/* HCI register definitions */
#define	HCI_WORDS			6 /* Number of register */
#define	HCI_REG_AX			0 /* Operation, then return value */
#define	HCI_REG_BX			1 /* Function */
#define	HCI_REG_CX			2 /* Argument (in or out) */

/* Return codes */
#define	HCI_FAILURE			-1
#define	HCI_SUCCESS			0

/* Toshiba fn_keys events */
#define	FN_KEY_VIDEO_OUTPUT		0x01BF
#define	FN_KEY_BRIGHTNESS_DOWN		0x01C0
#define	FN_KEY_BRIGHTNESS_UP		0x01C1

struct acpitoshiba_softc {
	struct device		 sc_dev;
	struct acpi_softc	*sc_acpi;
	struct aml_node		*sc_devnode;
};

int	toshiba_enable_events(struct acpitoshiba_softc *);
int	toshiba_read_events(struct acpitoshiba_softc *);
int	toshiba_match(struct device *, void *, void *);
void	toshiba_attach(struct device *, struct device *, void *);
int	toshiba_hotkey(struct aml_node *, int, void *);
int	toshiba_get_brightness(struct acpitoshiba_softc *, u_int32_t *);
int	toshiba_set_brightness(struct acpitoshiba_softc *, u_int32_t *);
int	toshiba_get_video_output(struct acpitoshiba_softc *, u_int32_t *);
int	toshiba_set_video_output(struct acpitoshiba_softc *, u_int32_t *);
int	toshiba_find_brightness(struct acpitoshiba_softc *, int *);
int	toshiba_fn_key_brightness_up(struct acpitoshiba_softc *);
int	toshiba_fn_key_brightness_down(struct acpitoshiba_softc *);
int	toshiba_fn_key_video_output(struct acpitoshiba_softc *);

/* wconsole hook functions */
int	acpitoshiba_get_param(struct wsdisplay_param *);
int	acpitoshiba_set_param(struct wsdisplay_param *);
extern int (*ws_get_param)(struct wsdisplay_param *);
extern int (*ws_set_param)(struct wsdisplay_param *);
int	get_param_brightness(struct wsdisplay_param *);
int	set_param_brightness(struct wsdisplay_param *);

struct cfattach acpitoshiba_ca = {
	sizeof(struct acpitoshiba_softc), toshiba_match, toshiba_attach
};

struct cfdriver acpitoshiba_cd = {
	NULL, "acpitoshiba", DV_DULL
};

int
get_param_brightness(struct wsdisplay_param *dp)
{
	struct acpitoshiba_softc	*sc = NULL;
	int i, ret;

	for (i = 0; i < acpitoshiba_cd.cd_ndevs; i++) {
		if (acpitoshiba_cd.cd_devs[i] == NULL)
			continue;

		sc = (struct acpitoshiba_softc *)acpitoshiba_cd.cd_devs[i];
	}

	if (sc != NULL) {
		rw_enter_write(&sc->sc_acpi->sc_lck);

		/* default settings */
		dp->min = HCI_LCD_BRIGHTNESS_MIN;
		dp->max = HCI_LCD_BRIGHTNESS_MAX;

		ret = toshiba_get_brightness(sc, &dp->curval);

		rw_exit_write(&sc->sc_acpi->sc_lck);

		if ((dp->curval != -1) && (ret != HCI_FAILURE) )
			return (0);
	}

	return (1);
}

int
acpitoshiba_get_param(struct wsdisplay_param *dp)
{
	int ret;

	switch (dp->param) {
	case WSDISPLAYIO_PARAM_BRIGHTNESS:
		ret = get_param_brightness(dp);
		return (ret);
	default:
		return (1);
	}
}

int
set_param_brightness(struct wsdisplay_param *dp)
{
	struct acpitoshiba_softc	*sc = NULL;
	int i, ret;

	for (i = 0; i < acpitoshiba_cd.cd_ndevs; i++) {
		if (acpitoshiba_cd.cd_devs[i] == NULL)
			continue;

		sc = (struct acpitoshiba_softc *)acpitoshiba_cd.cd_devs[i];
	}

	if (sc != NULL) {
		rw_enter_write(&sc->sc_acpi->sc_lck);
		ret = toshiba_find_brightness(sc, &dp->curval);
		rw_exit_write(&sc->sc_acpi->sc_lck);

		if ((dp->curval != -1) && ( ret != HCI_FAILURE))
			return (0);

	}

	return (1);
}

int
acpitoshiba_set_param(struct wsdisplay_param *dp)
{
	int ret;

	switch (dp->param) {
	case WSDISPLAYIO_PARAM_BRIGHTNESS:
		ret = set_param_brightness(dp);
		return (ret);
	default:
		return (1);
	}
}

int
toshiba_find_brightness(struct acpitoshiba_softc *sc, int *new_blevel)
{
	int ret, current_blevel;

	ret = toshiba_get_brightness(sc, &current_blevel);
	if ( ret != HCI_SUCCESS)
		return (1);

	if ( current_blevel != *new_blevel) {
		if ( *new_blevel >= HCI_LCD_BRIGHTNESS_MAX)
			*new_blevel = current_blevel = HCI_LCD_BRIGHTNESS_MAX;
		else if (*new_blevel <= HCI_LCD_BRIGHTNESS_MIN)
			*new_blevel = current_blevel = HCI_LCD_BRIGHTNESS_MIN;
		else
			current_blevel = *new_blevel;

		ret = toshiba_set_brightness(sc, &current_blevel);
		if ( ret != HCI_SUCCESS)
			return (1);
	}

	return (0);
}

int
toshiba_match(struct device *parent, void *match, void *aux)
{
      struct acpi_attach_args *aa = aux;
      struct cfdata	      *cf = match;

	if ( aa->aaa_name == NULL ||
	   strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
	   aa->aaa_table != NULL)
	      return (0);

      return (1);

}

int
toshiba_enable_events(struct acpitoshiba_softc *sc)
{
	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI_ENABLE,
		    0, NULL, NULL)) {
		printf("%s: couldn't toggle METHOD_HCI_ENABLE\n", DEVNAME(sc));
		return (HCI_FAILURE);
	}

	return (HCI_SUCCESS);
}

int
toshiba_read_events(struct acpitoshiba_softc *sc)
{
	struct aml_value args[HCI_WORDS];
	struct aml_value res;
	int i, val;

	bzero(args, sizeof(args));
	bzero(&res, sizeof(res));

	for (i = 0; i < HCI_WORDS; ++i)
		args[i].type = AML_OBJTYPE_INTEGER;

	args[HCI_REG_AX].v_integer = HCI_GET;
	args[HCI_REG_BX].v_integer = HCI_REG_SYSTEM_EVENT;

	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
		    i, args, &res)) {
		printf("%s: couldn't toggle METHOD_HCI\n", DEVNAME(sc));
		return (HCI_FAILURE);
	}

	/*
	 * We receive a package type so we need to get the event
	 * value from the HCI_REG_CX.
	 */
	val = aml_val2int(res.v_package[HCI_REG_CX]);
	aml_freevalue(&res);

	return (val);
}

void
toshiba_attach(struct device *parent, struct device *self, void *aux)
{
	struct acpitoshiba_softc *sc = (struct acpitoshiba_softc *)self;
	struct acpi_attach_args *aa = aux;
	int ret;

	sc->sc_acpi = (struct acpi_softc *)parent;
	sc->sc_devnode = aa->aaa_node;

	printf("\n");

	/* enable events and hotkeys */
	ret = toshiba_enable_events(sc);
	if ( ret != HCI_FAILURE) {
		/* Run toshiba_hotkey on button presses */
		aml_register_notify(sc->sc_devnode, aa->aaa_dev,
				toshiba_hotkey, sc, ACPIDEV_NOPOLL);

		/* wsconsctl purpose */
		ws_get_param = acpitoshiba_get_param;
		ws_set_param = acpitoshiba_set_param;
	}

}

int
toshiba_fn_key_brightness_up(struct acpitoshiba_softc *sc)
{
	u_int32_t brightness_level;
	int ret;

	ret = toshiba_get_brightness(sc, &brightness_level);
	if ( ret != HCI_FAILURE) {

		if (brightness_level++ == HCI_LCD_BRIGHTNESS_MAX)
			brightness_level = HCI_LCD_BRIGHTNESS_MAX;
		else
			ret = toshiba_set_brightness(sc, &brightness_level);
	}

	return (ret);
}

int
toshiba_fn_key_brightness_down(struct acpitoshiba_softc *sc)
{
	u_int32_t brightness_level;
	int ret;

	ret = toshiba_get_brightness(sc, &brightness_level);
	if ( ret != HCI_FAILURE) {
		if (brightness_level-- == HCI_LCD_BRIGHTNESS_MIN)
			brightness_level = HCI_LCD_BRIGHTNESS_MIN;
		else
			ret = toshiba_set_brightness(sc, &brightness_level);
	}

	return (ret);
}

int
toshiba_fn_key_video_output(struct acpitoshiba_softc *sc)
{
	u_int32_t video_output;
	int ret;

	ret = toshiba_get_video_output(sc, &video_output);
	if ( ret != HCI_FAILURE) {
		video_output = (video_output + 1) % HCI_VIDEO_OUTPUT_CYCLE_MAX;

		ret = toshiba_set_video_output(sc, &video_output);
	}

	return (ret);

}

int
toshiba_hotkey(struct aml_node *node, int notify, void *arg)
{
	struct acpitoshiba_softc *sc = arg;
	int event, ret;

	event = toshiba_read_events(sc);
	if (!event)
		return (0);

	switch (event) {
	case FN_KEY_BRIGHTNESS_UP:
		/* Increase brightness */
		ret = toshiba_fn_key_brightness_up(sc);
		break;
	case FN_KEY_BRIGHTNESS_DOWN:
		/* Decrease brightness */
		ret = toshiba_fn_key_brightness_down(sc);
		break;
	case FN_KEY_VIDEO_OUTPUT:
		/* Cycle through video outputs. */
		ret = toshiba_fn_key_video_output(sc);
		break;
	default:
		break;
	}

	if ( ret != HCI_SUCCESS)
		return (1);

	return (0);
}

int
toshiba_set_brightness(struct acpitoshiba_softc *sc, u_int32_t *brightness)
{
	struct aml_value args[HCI_WORDS];
	int i;

	bzero(args, sizeof(args));

	for (i = 0; i < HCI_WORDS; ++i)
		args[i].type = AML_OBJTYPE_INTEGER;

	if ((*brightness < HCI_LCD_BRIGHTNESS_MIN) ||
	    (*brightness > HCI_LCD_BRIGHTNESS_MAX))
		       return (HCI_FAILURE);

	*brightness <<= HCI_LCD_BRIGHTNESS_SHIFT;

	args[HCI_REG_AX].v_integer = HCI_SET;
	args[HCI_REG_BX].v_integer = HCI_REG_LCD_BRIGHTNESS;
	args[HCI_REG_CX].v_integer = *brightness;

	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
	    i, args, NULL)) {
		printf("%s: set brightness failed\n", DEVNAME(sc));
		return (HCI_FAILURE);
	}

	return (HCI_SUCCESS);
}

int
toshiba_get_brightness(struct acpitoshiba_softc *sc, u_int32_t *brightness)
{
	struct aml_value args[HCI_WORDS];
	struct aml_value res;
	int i;

	bzero(args, sizeof(args));
	bzero(&res, sizeof(res));

	for (i = 0; i < HCI_WORDS; ++i)
		args[i].type = AML_OBJTYPE_INTEGER;

	args[HCI_REG_AX].v_integer = HCI_GET;
	args[HCI_REG_BX].v_integer = HCI_REG_LCD_BRIGHTNESS;

	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
	    i, args, &res)) {
		printf("%s: get brightness failed\n", DEVNAME(sc));
		return (HCI_FAILURE);
	}

	/*
	 * We receive a package type so we need to get the event
	 * value from the HCI_REG_CX.
	 */
	*brightness = aml_val2int(res.v_package[HCI_REG_CX]);

	*brightness >>= HCI_LCD_BRIGHTNESS_SHIFT;

	aml_freevalue(&res);

	return (HCI_SUCCESS);
}

int
toshiba_get_video_output(struct acpitoshiba_softc *sc, u_int32_t *video_output)
{
	struct aml_value res, args[HCI_WORDS];
	int i;

	bzero(args, sizeof(args));
	bzero(&res, sizeof(res));

	for (i = 0; i < HCI_WORDS; ++i)
		args[i].type = AML_OBJTYPE_INTEGER;

	args[HCI_REG_AX].v_integer = HCI_GET;
	args[HCI_REG_BX].v_integer = HCI_REG_VIDEO_OUTPUT;

	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
	    i, args, &res)) {
		printf("%s: get video output failed\n", DEVNAME(sc));
		return (HCI_FAILURE);
	}

	/*
	 * We receive a package type so we need to get the event
	 * value from the HCI_REG_CX.
	 */
	*video_output = aml_val2int(res.v_package[HCI_REG_CX]);

	*video_output &= 0xff;

	aml_freevalue(&res);

	return (HCI_SUCCESS);
}

int
toshiba_set_video_output(struct acpitoshiba_softc *sc, u_int32_t *video_output)
{
	struct aml_value args[HCI_WORDS];
	int i;

	bzero(args, sizeof(args));

	if ((*video_output < HCI_VIDEO_OUTPUT_CYCLE_MIN) ||
	    (*video_output > HCI_VIDEO_OUTPUT_CYCLE_MAX))
		return (HCI_FAILURE);

	*video_output |= HCI_VIDEO_OUTPUT_FLAG;

	for (i = 0; i < HCI_WORDS; ++i)
		args[i].type = AML_OBJTYPE_INTEGER;

	args[HCI_REG_AX].v_integer = HCI_SET;
	args[HCI_REG_BX].v_integer = HCI_REG_VIDEO_OUTPUT;
	args[HCI_REG_CX].v_integer = *video_output;

	if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
	    i, args, NULL)) {
		printf("%s: set video output failed\n", DEVNAME(sc));
		return (HCI_FAILURE);
	}

	return (HCI_SUCCESS);
}


code:
/* $OpenBSD: acpitz.c,v 1.49 2015/05/06 01:41:55 jsg 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/malloc.h>
#include <sys/kernel.h>
#include <sys/kthread.h>

#include <machine/bus.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>

#define KTOC(k)			((k - 2732) / 10)
#define ACPITZ_MAX_AC		(10)
#define ACPITZ_TMP_RETRY	(3)

struct acpitz_softc {
	struct device		sc_dev;

	struct acpi_softc	*sc_acpi;
	struct aml_node		*sc_devnode;

	int			sc_tmp;
	int			sc_crt;
	int			sc_hot;
	int			sc_ac[ACPITZ_MAX_AC];
	int			sc_ac_stat[ACPITZ_MAX_AC];
	int			sc_pse;
	int			sc_psv;
	int			sc_tc1;
	int			sc_tc2;
	int			sc_lasttmp;

	struct ksensor		sc_sens;
	struct ksensordev	sc_sensdev;

	struct acpi_devlist_head	sc_psl;
	struct acpi_devlist_head	sc_alx[ACPITZ_MAX_AC];
};

int	acpitz_match(struct device *, void *, void *);
void	acpitz_attach(struct device *, struct device *, void *);
int	acpitz_activate(struct device *, int);

struct cfattach acpitz_ca = {
	sizeof(struct acpitz_softc), acpitz_match, acpitz_attach,
	NULL, acpitz_activate
};

struct cfdriver acpitz_cd = {
	NULL, "acpitz", DV_DULL
};

void	acpitz_init_perf(void *);
void	acpitz_setperf(int);
void	acpitz_monitor(struct acpitz_softc *);
void	acpitz_refresh(void *);
int	acpitz_notify(struct aml_node *, int, void *);
int	acpitz_gettempreading(struct acpitz_softc *, char *);
int	acpitz_getreading(struct acpitz_softc *, char *);
int	acpitz_setfan(struct acpitz_softc *, int, char *);
void	acpitz_init(struct acpitz_softc *, int);

void		(*acpitz_cpu_setperf)(int);
int		acpitz_perflevel = -1;
extern void	(*cpu_setperf)(int);
extern int	perflevel;
#define PERFSTEP 10

#define ACPITZ_TRIPS	(1L << 0)
#define ACPITZ_DEVLIST	(1L << 1)
#define ACPITZ_INIT	(ACPITZ_TRIPS|ACPITZ_DEVLIST)

extern struct aml_node aml_root;

void
acpitz_init_perf(void *arg)
{
	if (acpitz_perflevel == -1)
		acpitz_perflevel = perflevel;

	if (cpu_setperf != acpitz_setperf) {
		acpitz_cpu_setperf = cpu_setperf;
		cpu_setperf = acpitz_setperf;
	}
}

void
acpitz_setperf(int level)
{
	extern struct acpi_softc *acpi_softc;

	if (level < 0 || level > 100)
		return;

	if (acpi_softc == NULL)
		return;
	if (acpi_softc->sc_pse && level > acpitz_perflevel)
		return;

	if (acpitz_cpu_setperf)
		acpitz_cpu_setperf(level);
}

void
acpitz_init(struct acpitz_softc *sc, int flag)
{
	int i;
	char name[5];
	struct aml_value res;

	/* Read trip points */
	if (flag & ACPITZ_TRIPS) {
		sc->sc_psv = acpitz_getreading(sc, "_PSV");
		for (i = 0; i < ACPITZ_MAX_AC; i++) {
			snprintf(name, sizeof(name), "_AC%d", i);
			sc->sc_ac[i] = acpitz_getreading(sc, name);
			sc->sc_ac_stat[i] = -1;
		}
	}

	/* Read device lists */
	if (flag & ACPITZ_DEVLIST) {
		if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSL",
		     0, NULL, &res)) {
			acpi_freedevlist(&sc->sc_psl);
			acpi_getdevlist(&sc->sc_psl, sc->sc_devnode, &res, 0);
			aml_freevalue(&res);
		}
		for (i = 0; i < ACPITZ_MAX_AC; i++) {
			snprintf(name, sizeof(name), "_AL%d", i);
			if (!aml_evalname(sc->sc_acpi, sc->sc_devnode, name,
			    0, NULL, &res)) {
				acpi_freedevlist(&sc->sc_alx[i]);
				acpi_getdevlist(&sc->sc_alx[i],
				    sc->sc_devnode, &res, 0);
				aml_freevalue(&res);
			}
		}
	}
}

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->value->type != AML_OBJTYPE_THERMZONE)
		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;
	int i;
	char name[5];

	sc->sc_acpi = (struct acpi_softc *)parent;
	sc->sc_devnode = aa->aaa_node;

	TAILQ_INIT(&sc->sc_psl);
	for (i = 0; i < ACPITZ_MAX_AC; i++)
		TAILQ_INIT(&sc->sc_alx[i]);

	/*
	 * Preread the trip points (discard/ignore values read here as we will
	 * re-read them later)
	 */
	acpitz_gettempreading(sc, "_CRT");
	acpitz_gettempreading(sc, "_HOT");
	acpitz_gettempreading(sc, "_PSV");
	for (i = 0; i < ACPITZ_MAX_AC; i++) {
		snprintf(name, sizeof(name), "_AC%d", i);
		acpitz_getreading(sc, name);
	}
	acpitz_gettempreading(sc, "_TMP");

	sc->sc_lasttmp = -1;
	if ((sc->sc_tmp = acpitz_gettempreading(sc, "_TMP")) == -1) {
		dnprintf(10, ": failed to read _TMP\n");
		return;
	}

	if ((sc->sc_crt = acpitz_gettempreading(sc, "_CRT")) == -1)
		printf(": no critical temperature defined\n");
	else
		printf(": critical temperature is %d degC\n", KTOC(sc->sc_crt));

	sc->sc_hot = acpitz_gettempreading(sc, "_HOT");
	sc->sc_tc1 = acpitz_getreading(sc, "_TC1");
	sc->sc_tc2 = acpitz_getreading(sc, "_TC2");

	/* get _PSL, _ALx */
	acpitz_init(sc, ACPITZ_INIT);

	dnprintf(10, "%s: _HOT: %d _TC1: %d _TC2: %d _PSV: %d _TMP: %d "
	    "_CRT: %d\n", DEVNAME(sc), sc->sc_hot, sc->sc_tc1, sc->sc_tc2,
	    sc->sc_psv, sc->sc_tmp, sc->sc_crt);

	strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
	    sizeof(sc->sc_sensdev.xname));
	strlcpy(sc->sc_sens.desc, "zone temperature",
	    sizeof(sc->sc_sens.desc));
	sc->sc_sens.type = SENSOR_TEMP;
	sensor_attach(&sc->sc_sensdev, &sc->sc_sens);
	sensordev_install(&sc->sc_sensdev);

	aml_register_notify(sc->sc_devnode, NULL,
	    acpitz_notify, sc, ACPIDEV_POLL);

	/*
	 * XXX use kthread_create_deferred to ensure we are the very last
	 * piece of code that touches this pointer after all CPUs have been
	 * fully attached
	 */
	kthread_create_deferred(acpitz_init_perf, sc);
}

int
acpitz_activate(struct device *self, int act)
{
	struct acpitz_softc	*sc = (struct acpitz_softc *)self;

	switch (act) {
	case DVACT_WAKEUP:
		acpitz_init(sc, ACPITZ_INIT);
		break;
	}
	return 0;
}

int
acpitz_setfan(struct acpitz_softc *sc, int i, char *method)
{
	struct aml_node		*node;
	struct aml_value	res1, *ref;
	char			name[8];
	int			rv = 1, x, y;
	int64_t			sta;
	struct acpi_devlist    *dl;

	dnprintf(20, "%s: acpitz_setfan(%d, %s)\n", DEVNAME(sc), i, method);

	x = 0;
	snprintf(name, sizeof(name), "_AL%d", i);
	TAILQ_FOREACH(dl, &sc->sc_alx[i], dev_link) {
		if (aml_evalname(sc->sc_acpi, dl->dev_node, "_PR0",0 , NULL,
		    &res1)) {
			printf("%s: %s[%d] _PR0 failed\n", DEVNAME(sc),
			    name, x);
			aml_freevalue(&res1);
			x++;
			continue;
		}
		if (res1.type != AML_OBJTYPE_PACKAGE) {
			printf("%s: %s[%d] _PR0 not a package\n", DEVNAME(sc),
			    name, x);
			aml_freevalue(&res1);
			x++;
			continue;
		}
		for (y = 0; y < res1.length; y++) {
			ref = res1.v_package[y];
			if (ref->type == AML_OBJTYPE_STRING) {
				node = aml_searchrel(sc->sc_devnode,
				    ref->v_string);
				if (node == NULL) {
					printf("%s: %s[%d.%d] _PRO"
					    " not a valid device\n",
					    DEVNAME(sc), name, x, y);
					continue;
				}
				ref = node->value;
			}
			if (ref->type == AML_OBJTYPE_OBJREF) {
				ref = ref->v_objref.ref;
			}
			if (ref->type != AML_OBJTYPE_DEVICE &&
			    ref->type != AML_OBJTYPE_POWERRSRC) {
				printf("%s: %s[%d.%d] _PRO not a package\n",
				    DEVNAME(sc), name, x, y);
				continue;
			}
			if (aml_evalname(sc->sc_acpi, ref->node, method, 0,
			    NULL, NULL))
				printf("%s: %s[%d.%d] %s fails\n",
				    DEVNAME(sc), name, x, y, method);

			/* save off status of fan */
			if (aml_evalinteger(sc->sc_acpi, ref->node, "_STA", 0,
			    NULL, &sta))
				printf("%s: %s[%d.%d] _STA fails\n",
				    DEVNAME(sc), name, x, y);
			else {
				sc->sc_ac_stat[i] = sta;
			}
		}
		aml_freevalue(&res1);
		x++;
	}
	rv = 0;
	return (rv);
}

void
acpitz_refresh(void *arg)
{
	struct acpitz_softc	*sc = arg;
	int			i, trend, nperf;

	dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc),
	    sc->sc_devnode->name);

	/* get _TMP and debounce the value */
	if (-1 == (sc->sc_tmp = acpitz_gettempreading(sc, "_TMP"))) {
		printf("%s: %s: failed to read temp\n", DEVNAME(sc),
		    sc->sc_devnode->name);
		return;
	}
	/* critical trip points */
	if (sc->sc_crt != -1 && sc->sc_crt <= sc->sc_tmp) {
		/* do critical shutdown */
		printf("%s: critical temperature exceeded %dC, shutting "
		    "down\n", DEVNAME(sc), KTOC(sc->sc_tmp));
		prsignal(initprocess, SIGUSR2);
	}
	if (sc->sc_hot != -1 && sc->sc_hot <= sc->sc_tmp) {
		printf("%s: _HOT temperature\n", DEVNAME(sc));
		/* XXX go to S4, until then cool as hard as we can */
	}

	/* passive cooling */
	if (sc->sc_lasttmp != -1 && sc->sc_tc1 != -1 && sc->sc_tc2 != -1 &&
	    sc->sc_psv != -1) {
		dnprintf(30, "%s: passive cooling: lasttmp: %d tc1: %d "
		    "tc2: %d psv: %d\n", DEVNAME(sc), sc->sc_lasttmp,
		    sc->sc_tc1, sc->sc_tc2, sc->sc_psv);

		nperf = acpitz_perflevel;
		if (sc->sc_psv <= sc->sc_tmp) {
			/* Passive cooling enabled */
			dnprintf(1, "%s: enabling passive %d %d\n",
			    DEVNAME(sc), sc->sc_tmp, sc->sc_psv);
			if (!sc->sc_pse)
				sc->sc_acpi->sc_pse++;
			sc->sc_pse = 1;

			trend = sc->sc_tc1 * (sc->sc_tmp - sc->sc_lasttmp) +
			    sc->sc_tc2 * (sc->sc_tmp - sc->sc_psv);

			/* Depending on trend, slow down/speed up */
			if (trend > 0)
				nperf -= PERFSTEP;
			else
				nperf += PERFSTEP;
		}
		else {
			/* Passive cooling disabled, increase % */
			dnprintf(1, "%s: disabling passive %d %d\n",
			    DEVNAME(sc), sc->sc_tmp, sc->sc_psv);
			if (sc->sc_pse)
				sc->sc_acpi->sc_pse--;
			sc->sc_pse = 0;
			nperf += PERFSTEP;
		}
		if (nperf < 0)
			nperf = 0;
		else if (nperf > 100)
			nperf = 100;

		/* clamp passive cooling request */
		if (nperf > perflevel)
			nperf = perflevel;

		/* Perform CPU setperf */
		if (acpitz_cpu_setperf && nperf != acpitz_perflevel) {
			acpitz_perflevel = nperf;
			acpitz_cpu_setperf(nperf);
		}
	}
	sc->sc_lasttmp = sc->sc_tmp;

	/* active cooling */
	for (i = 0; i < ACPITZ_MAX_AC; i++) {
		if (sc->sc_ac[i] != -1 && sc->sc_ac[i] <= sc->sc_tmp) {
			/* turn on fan i */
			if (sc->sc_ac_stat[i] <= 0)
				acpitz_setfan(sc, i, "_ON_");
		} else if (sc->sc_ac[i] != -1) {
			/* turn off fan i */
			if (sc->sc_ac_stat[i] > 0)
				acpitz_setfan(sc, i, "_OFF");
		}
	}
	sc->sc_sens.value = sc->sc_tmp * 100000 - 50000;
}

int
acpitz_getreading(struct acpitz_softc *sc, char *name)
{
	u_int64_t		val;

	if (!aml_evalinteger(sc->sc_acpi, sc->sc_devnode, name, 0, NULL, &val))
		return (val);

	return (-1);
}

int
acpitz_gettempreading(struct acpitz_softc *sc, char *name)
{
	int			rv = -1, tmp = -1, i;

	for (i = 0; i < ACPITZ_TMP_RETRY; i++) {
		tmp = acpitz_getreading(sc, name);
		if (tmp == -1)
			goto out;
		if (KTOC(tmp) >= 0) {
			rv = tmp;
			break;
		} else {
			dnprintf(20, "%s: %d invalid reading on %s, "
			    "debouncing\n", DEVNAME(sc), tmp, name);
		}

		acpi_sleep(1000, "acpitz");	/* debounce: 1000 msec */
	}
	if (i >= ACPITZ_TMP_RETRY) {
		printf("%s: %s: failed to read %s\n", DEVNAME(sc),
		    sc->sc_devnode->name, name);
		goto out;
	}
 out:
	dnprintf(30, "%s: name: %s tmp: %d => %dC, rv: %d\n", DEVNAME(sc),
	    name, tmp, KTOC(tmp), rv);
	return (rv);
}

int
acpitz_notify(struct aml_node *node, int notify_type, void *arg)
{
	struct acpitz_softc	*sc = arg;

	dnprintf(10, "%s notify: %.2x %s\n", DEVNAME(sc), notify_type,
	    sc->sc_devnode->name);

	switch (notify_type) {
	case 0x80:	/* hardware notifications */
		break;
	case 0x81:	/* operating Points changed */
		acpitz_init(sc, ACPITZ_TRIPS);
		break;
	case 0x82:	/* re-evaluate thermal device list */
		acpitz_init(sc, ACPITZ_DEVLIST);
		break;
	default:
		break;
	}

	acpitz_refresh(sc);
	return (0);
}


code:
/* $OpenBSD: acpiutil.c,v 1.8 2015/03/14 03:38:47 jsg Exp $ */
/*
 * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
 *
 * 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/types.h>
#include <sys/systm.h>
#include <sys/device.h>

#include <dev/acpi/acpivar.h>

u_int
acpi_checksum(const void *v, size_t len)
{
	const u_char *p = v;
	u_char s = 0;
	int i;

	for (i = 0; i < len; i++)
		s += p[i];

	if (s)
		dnprintf(0,"\nacpi0: bad checksum at %p", v);

	return (s);
}