/*-
 * Copyright (c) 1999 Takanori Watanabe <takawata@shidahara1.planet.sci.kobe-u.ac.jp>
 * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.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.
 *
 * $FreeBSD$
 */
#include "opt_acpi.h"
#include <sys/param.h>
#include <sys/proc.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <vm/vm.h>
#include <vm/vm_prot.h>
#include <vm/pmap.h>
#include <machine/clock.h>
#include <machine/md_var.h>
#include <machine/segments.h>
#include <machine/stdarg.h>
#include <machine/tss.h>
#include <machine/vmparam.h>
#include <machine/pc/bios.h>
#include <machine/pc/acpi.h>
#include <isa/pnpreg.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/resource.h>
#include <sys/rman.h>
#include <sys/bus.h>
#include <sys/conf.h>
/*
 * ACPI pmap subsystem
 */
#define ACPI_SMAP_MAX_SIZE      16

struct ACPIaddr {
	int             entries;
	vm_offset_t     pa_base[ACPI_SMAP_MAX_SIZE];
	vm_offset_t     va_base[ACPI_SMAP_MAX_SIZE];
	vm_size_t       size[ACPI_SMAP_MAX_SIZE];
	u_int32_t       type[ACPI_SMAP_MAX_SIZE];
};

static void     acpi_pmap_init(device_t dev);
static void     acpi_pmap_release(device_t dev);
static vm_offset_t acpi_pmap_ptv(device_t dev, vm_offset_t pa);
static vm_offset_t acpi_pmap_vtp(device_t dev, vm_offset_t va);

/*
 * These data cannot be in acpi_softc because they should be initialized
 * before probing device.
 */

static struct ACPIaddr acpi_addr;
struct ACPIrsdp *acpi_rsdp;

/* softc */
struct acpi_softc {
	struct ACPIsdt *rsdt;
	struct ACPIsdt *facp;
	struct FACPbody *facp_body;
	struct ACPIsdt *dsdt;
	struct FACS    *facs;
	device_t        dev;
};

/* Character device stuff */

static d_open_t acpiopen;
static d_close_t acpiclose;
static d_ioctl_t acpiioctl;
static d_mmap_t acpimmap;
#define CDEV_MAJOR 210
static struct cdevsw acpi_cdevsw = {
	 /* open */ acpiopen,
	 /* close */ acpiclose,
	 /* read */ noread,
	 /* write */ nowrite,
	 /* ioctl */ acpiioctl,
	 /* stop */ nostop,
	 /* reset */ noreset,
	 /* devtotty */ nodevtotty,
	 /* poll */ nopoll,
	 /* mmap */ acpimmap,
	 /* strategy */ nostrategy,
	 /* name */ "acpi",
	 /* parms */ noparms,
	 /* maj */ CDEV_MAJOR,
	 /* dump */ nodump,
	 /* psize */ nopsize,
	 /* flags */ 0,
	 /* maxio */ 0,
	 /* bmaj */ -1
};

/* Miscellous utility functions */
static void     acpi_facp_proc(device_t dev);
static int      acpi_sdt_checksum(struct ACPIsdt * sdt);

#define	ACPI_REGISTERS_INPUT	0
#define	ACPI_REGISTERS_OUTPUT	1
static void     acpi_enable_disable(device_t dev, boolean_t enable);
static void     acpi_io_pm1_status(device_t dev, boolean_t io, u_int32_t *a, u_int32_t *b);
static void     acpi_io_pm1_enable(device_t dev, boolean_t io, u_int32_t *a, u_int32_t *b);
static void     acpi_io_gpe0_status(device_t dev, boolean_t io, u_int32_t *val);
static void     acpi_io_gpe0_enable(device_t dev, boolean_t io, u_int32_t *val);
static void     acpi_io_gpe1_status(device_t dev, boolean_t io, u_int32_t *val);
static void     acpi_io_gpe1_enable(device_t dev, boolean_t io, u_int32_t *val);

void
acpi_init_addr_range()
{
	acpi_addr.entries = 0;
}

void
acpi_register_addr_range(u_int64_t base, u_int64_t size, u_int32_t type)
{
	int             i;
	vm_offset_t     pa_base, pa_next_base;
	u_int32_t       ext_size;

	if (acpi_addr.entries == ACPI_SMAP_MAX_SIZE)
		return;		/* no room */

	for (i = 0; i < acpi_addr.entries; i++) {
		if (type != acpi_addr.type[i])
			continue;

		pa_base = acpi_addr.pa_base[i];
		pa_next_base = pa_base + acpi_addr.size[i];

		/* continuous or overlap? */
		if (base > pa_base && base <= pa_next_base) {
			ext_size = size - (pa_next_base - base);
			acpi_addr.size[i] += ext_size;
			return;
		}
	}

	i = acpi_addr.entries;
	acpi_addr.pa_base[i] = base;
	acpi_addr.size[i] = size;
	acpi_addr.type[i] = type;
	acpi_addr.entries++;
}

static void
acpi_pmap_init(device_t dev)
{
	int             i;
	vm_offset_t     va;

	for (i = 0; i < acpi_addr.entries; i++) {
		va = (vm_offset_t) pmap_mapdev(acpi_addr.pa_base[i],
					       acpi_addr.size[i]);
		acpi_addr.va_base[i] = va;
		device_printf(dev, "ADDR RANGE %x %x (mapped 0x%x)\n",
			      acpi_addr.pa_base[i], acpi_addr.size[i], va);
	}
}

static void
acpi_pmap_release(device_t dev)
{
#if 0
	int             i;

	for (i = 0; i < acpi_addr.entries; i++) {
		pmap_unmapdev(acpi_addr.va_base[i], acpi_addr.size[i]);
	}
#endif
}

static vm_offset_t
acpi_pmap_ptv(device_t dev, vm_offset_t pa)
{
	int             i;
	vm_offset_t     va = 0;

	for (i = 0; i < acpi_addr.entries; i++) {
		if (pa >= acpi_addr.pa_base[i] &&
		    pa < acpi_addr.pa_base[i] + acpi_addr.size[i]) {
			va = acpi_addr.va_base[i] + pa - acpi_addr.pa_base[i];
			return (va);
		}
	}

	return (va);
}

static vm_offset_t
acpi_pmap_vtp(device_t dev, vm_offset_t va)
{
	int             i;
	vm_offset_t     pa = 0;

	for (i = 0; i < acpi_addr.entries; i++) {
		if (va >= acpi_addr.va_base[i] &&
		    va < acpi_addr.va_base[i] + acpi_addr.size[i]) {
			pa = acpi_addr.pa_base[i] + va - acpi_addr.va_base[i];
			return (pa);
		}
	}

	return (pa);
}

static int
acpi_sdt_checksum(struct ACPIsdt *sdt)
{
	int             i;
	u_char          cksm = 0, *ckbf = (u_char *) sdt;

	for (i = 0; i < sdt->len; i++)
		cksm += ckbf[i];

	return (cksm == 0) ? 0 : EINVAL;
}

static void
acpi_facp_proc(device_t dev)
{
	struct acpi_softc *sc = device_get_softc(dev);
	struct ACPIsdt *facp = sc->facp, *dsdt;
	struct FACPbody *body = (struct FACPbody *) facp->body;
	struct FACS    *facs;

	device_printf(dev, "	FACP found\n");
	sc->facp_body = body;
	dsdt = (struct ACPIsdt *) acpi_pmap_ptv(dev, body->dsdt_ptr);
	sc->dsdt = NULL;
	sc->facs = NULL;
	if (dsdt == NULL) {
		return;
	}

	if (strncmp(dsdt->signature, "DSDT", 4) == 0 &&
	    acpi_sdt_checksum(dsdt) == 0) {
		device_printf(dev, "	DSDT found Size=%d bytes\n", dsdt->len);
		sc->dsdt = dsdt;
	}

	facs = (struct FACS *) acpi_pmap_ptv(dev, body->facs_ptr);
	if (facs == NULL) {
		return;
	}

	/*
	 * FACS has no checksum (modified by both OS and BIOS) and in many
	 * cases,It is in NVS area.
	 */
	if (strncmp(facs->signature, "FACS", 4) == 0) {
		sc->facs = facs;
		device_printf(dev, "	FACS Found Size=%d bytes\n", facs->len);
	}
}

#define	ACPI_PM1_ALL_ENABLE_BITS	0x0721	/* 0000 0111 0010 0001 */

static void
acpi_intr(void *data)
{
	struct acpi_softc *sc = (struct acpi_softc *) data;
	u_int32_t       enable_a, enable_b, enable_0, enable_1;
	u_int32_t       status_a, status_b, status_0, status_1;
	u_int32_t       val_a, val_b;

	/* Power Management 1 Status Registers */
	acpi_io_pm1_status(sc->dev, ACPI_REGISTERS_INPUT, &status_a, &status_b);
	/* Get Current Intrrupt Mask */
	acpi_io_pm1_enable(sc->dev, ACPI_REGISTERS_INPUT, &enable_a, &enable_b);
	/* Disable events and re-enable again */
	if ((status_a & enable_a) != 0 || (status_b & enable_b) != 0) {

		printf("ACPI: pm1_status intr CALLED\n");

		/* Disable all intrrupt generation */
		val_a = enable_a & (~ACPI_PM1_ALL_ENABLE_BITS);
		val_b = enable_b & (~ACPI_PM1_ALL_ENABLE_BITS);
		acpi_io_pm1_enable(sc->dev, ACPI_REGISTERS_OUTPUT,
				   &val_a, &val_b);

		/* Clear intrrupt status */
		val_a = enable_a & ACPI_PM1_ALL_ENABLE_BITS;
		val_b = enable_b & ACPI_PM1_ALL_ENABLE_BITS;
		acpi_io_pm1_status(sc->dev, ACPI_REGISTERS_OUTPUT,
				   &val_a, &val_b);

		/* Re-enable intrrupt */
		acpi_io_pm1_enable(sc->dev, ACPI_REGISTERS_OUTPUT,
				   &enable_a, &enable_b);
	}

	/* General-Purpose Events 0 Status Registers */
	acpi_io_gpe0_status(sc->dev, ACPI_REGISTERS_INPUT, &status_0);
	/* Get Current Intrrupt Mask */
	acpi_io_gpe0_enable(sc->dev, ACPI_REGISTERS_INPUT, &enable_0);
	/* Disable events and re-enable again */
	if ((status_0 & enable_0) != 0) {

		printf("ACPI: gpe0_status intr CALLED\n");

		/* Disable all intrrupt generation */
		val_a = enable_0 & ~status_0;
#if 0
		/* or should we disable all? */
		val_a = 0x0;
#endif
		acpi_io_gpe0_enable(sc->dev, ACPI_REGISTERS_OUTPUT, &val_a);

		/* Clear intrrupt status */
		val_a = enable_0;	/* XXX */
		acpi_io_gpe0_status(sc->dev, ACPI_REGISTERS_OUTPUT, &val_a);

		/* Re-enable intrrupt */
		acpi_io_gpe0_enable(sc->dev, ACPI_REGISTERS_OUTPUT, &enable_0);
	}

	/* General-Purpose Events 1 Status Registers */
	acpi_io_gpe1_status(sc->dev, ACPI_REGISTERS_INPUT, &status_1);
	/* Get Current Intrrupt Mask */
	acpi_io_gpe1_enable(sc->dev, ACPI_REGISTERS_INPUT, &enable_1);
	/* Disable events and re-enable again */
	if ((status_1 & enable_1) != 0) {

		printf("ACPI: gpe1_status intr CALLED\n");

		/* Disable all intrrupt generation */
		val_a = enable_1 & ~status_1;
#if 0
		/* or should we disable all? */
		val_a = 0x0;
#endif
		acpi_io_gpe1_enable(sc->dev, ACPI_REGISTERS_OUTPUT, &val_a);

		/* Clear intrrupt status */
		val_a = enable_1;	/* XXX */
		acpi_io_gpe1_status(sc->dev, ACPI_REGISTERS_OUTPUT, &val_a);

		/* Re-enable intrrupt */
		acpi_io_gpe1_enable(sc->dev, ACPI_REGISTERS_OUTPUT, &enable_1);
	}

	/* do something to handle the events... */
	DELAY(1000);	/* :-) */
}

static void
acpi_identify(driver_t *driver, device_t parent)
{
	device_t        child;

	child = BUS_ADD_CHILD(parent, 0, "acpi", 0);

	if (child == NULL)
		panic("acpi_identify");
}

static int
acpi_probe(device_t dev)
{
	static char     oemstring[7];

	if (acpi_rsdp == NULL) {
		return (ENXIO);
	}
	bzero(oemstring, sizeof(oemstring));
	strncpy(oemstring, acpi_rsdp->oem, sizeof(acpi_rsdp->oem));

	printf("ACPI: Found ACPI BIOS data at %p (<%s>, RSDT@%x)\n",
	       acpi_rsdp, oemstring, acpi_rsdp->addr);

	device_set_desc(dev, oemstring);
	return (0);
}

static int
acpi_attach(device_t dev)
{
	struct acpi_softc *sc = device_get_softc(dev);
	struct ACPIsdt *rsdt, *sdt;
	struct resource *res_port, *res_irq;
	int             entries;
	int             i;
	int             rid;
	int             port, irq;
	int             err;
	u_int32_t      *ptrs;
	u_int32_t      status_a, status_b;
	void           *ih;
	char            sigstring[5];

	acpi_pmap_init(dev);

	rsdt = (struct ACPIsdt *) acpi_pmap_ptv(dev, acpi_rsdp->addr);
	if (rsdt == 0) {
		device_printf(dev, "cannot map physical memory\n");
		return (ENXIO);
	}
	if ((strncmp(rsdt->signature, "RSDT", 4) != 0) &&
	    (acpi_sdt_checksum(rsdt) != 0)) {
		device_printf(dev, "RSDT is broken\n");
		acpi_pmap_release(dev);
		return (ENXIO);
	}
	sc->rsdt = rsdt;
	entries = (rsdt->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t);
	device_printf(dev, "RSDT have %d entries\n", entries);
	ptrs = (u_int32_t *) & rsdt->body;

	for (i = 0; i < entries; i++) {
		sdt = (struct ACPIsdt *) acpi_pmap_ptv(dev, (vm_offset_t) ptrs[i]);
		bzero(sigstring, sizeof(sigstring));
		strncpy(sigstring, sdt->signature, sizeof(sdt->signature));
		device_printf(dev, "RSDT entry%d %s\n", i, sigstring);

		if (strncmp(sdt->signature, "FACP", 4) == 0 &&
		    acpi_sdt_checksum(sdt) == 0) {
			sc->facp = sdt;
			acpi_facp_proc(dev);
		}
	}

	/* Allocate the port range and interrupt */
	port = sc->facp_body->smi_cmd;
	rid = 0;
	res_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, port, port, 1, RF_ACTIVE);

	if (res_port == NULL) {
		device_printf(dev, "could not allocate port\n");
		acpi_pmap_release(dev);
		return (ENOMEM);
	}
	irq = sc->facp_body->sci_int;
	rid = 0;
	res_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1,
				     RF_SHAREABLE | RF_ACTIVE);

	if (res_irq == NULL) {
		bus_release_resource(dev, SYS_RES_IOPORT, 0, res_port);
		acpi_pmap_release(dev);
		return (ENOMEM);
	}
	err = bus_setup_intr(dev, res_irq, INTR_TYPE_MISC,
			     (driver_intr_t *) acpi_intr, sc, &ih);
	if (err) {
		device_printf(dev, "could not setup irq, %d\n", err);
		acpi_pmap_release(dev);
		return (err);
	}

	acpi_enable_disable(dev, 1);
	device_printf(dev, "at 0x%x irq %d\n", port, irq);

	/* print all event status for debugging */
	acpi_io_pm1_status(dev, ACPI_REGISTERS_INPUT, &status_a, &status_b);
	acpi_io_pm1_enable(dev, ACPI_REGISTERS_INPUT,  &status_a, &status_b);
	acpi_io_gpe0_status(dev, ACPI_REGISTERS_INPUT, &status_a);
	acpi_io_gpe0_enable(dev, ACPI_REGISTERS_INPUT, &status_a);
	acpi_io_gpe1_status(dev, ACPI_REGISTERS_INPUT, &status_a);
	acpi_io_gpe1_enable(dev, ACPI_REGISTERS_INPUT, &status_a);

	acpi_pmap_release(dev);
	sc->dev = dev;
	return (0);
}

static device_method_t acpi_methods[] = {
	/* Device interface */
	DEVMETHOD(device_identify, acpi_identify),
	DEVMETHOD(device_probe, acpi_probe),
	DEVMETHOD(device_attach, acpi_attach),

	{0, 0}
};

static driver_t acpi_driver = {
	"acpi",
	acpi_methods,
	sizeof(struct acpi_softc),	/* no softc (XXX) */
};

static devclass_t acpi_devclass;

DEV_DRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, acpi_cdevsw, 0, 0);

/*
 * ACPI Registers I/O
 */

static void
acpi_registers_input(u_int32_t ioaddr, u_int32_t *value, u_int32_t size)
{
	int		i;
	u_int32_t	val;

	val = 0;
	for (i = size - 1; i >= 0; i--) {
		val = (val << 8) | inb(ioaddr + i);
	}
	*value = val;
}

static void
acpi_registers_output(u_int32_t ioaddr, u_int32_t *value, u_int32_t size)
{
	int		i;
	u_int32_t	val;

	val = *value;
	for (i = 0; i < size; i++) {
		outb(ioaddr + i, val & 0xff);
		val >>= 8;
	}
}

static void
acpi_enable_disable(device_t dev, boolean_t enable)
{
	struct acpi_softc *sc = device_get_softc(dev);
	struct FACPbody *facp = sc->facp_body;
	u_int32_t	ioaddr = facp->smi_cmd;
	u_char          val;

	if (enable) {
		val = facp->acpi_enable;
	} else {
		val = facp->acpi_disable;
	}

	outb(ioaddr, val);

#ifdef ACPI_DEBUG
	device_printf(dev, "acpi_enable_disable(%d) = (%x)\n", enable, val);
#endif
}

static void
acpi_io_pm1_status(device_t dev, boolean_t io, u_int32_t *status_a, u_int32_t *status_b)
{
	struct acpi_softc *sc = device_get_softc(dev);
	struct FACPbody *facp = sc->facp_body;
	int		size = facp->pm1_evt_len / 2;

	if (io == ACPI_REGISTERS_INPUT) {
		acpi_registers_input(facp->pm1a_evt_blk, status_a, size);

		*status_b = 0;
		if (facp->pm1b_evt_blk) {
			acpi_registers_input(facp->pm1b_evt_blk, status_b, size);
		}
	} else {
		acpi_registers_output(facp->pm1a_evt_blk, status_a, size);

		if (facp->pm1b_evt_blk) {
			acpi_registers_output(facp->pm1b_evt_blk, status_b, size);
		}
	}

#ifdef ACPI_DEBUG
	device_printf(dev, "acpi_io_pm1_status(%d) = (%x, %x)\n",
			io, *status_a, *status_b);
#endif

	return;
}

static void
acpi_io_pm1_enable(device_t dev, boolean_t io, u_int32_t *status_a, u_int32_t *status_b)
{
	struct acpi_softc *sc = device_get_softc(dev);
	struct FACPbody *facp = sc->facp_body;
	int		size = facp->pm1_evt_len / 2;

	if (io == ACPI_REGISTERS_INPUT) {
		acpi_registers_input(facp->pm1a_evt_blk + size, status_a, size);

		*status_b = 0;
		if (facp->pm1b_evt_blk) {
			acpi_registers_input(facp->pm1b_evt_blk + size, status_b, size);
		}
	} else {
		acpi_registers_output(facp->pm1a_evt_blk + size, status_a, size);

		if (facp->pm1b_evt_blk) {
			acpi_registers_output(facp->pm1b_evt_blk + size, status_b, size);
		}
	}

#ifdef ACPI_DEBUG
	device_printf(dev, "acpi_io_pm1_enable(%d) = (%x, %x)\n",
			io, *status_a, *status_b);
#endif

	return;
}

static void
acpi_io_gpe0_status(device_t dev, boolean_t io, u_int32_t *val)
{
	struct acpi_softc *sc = device_get_softc(dev);
	struct FACPbody *facp = sc->facp_body;
	int		size = facp->gpe0_len / 2;

	if (io == ACPI_REGISTERS_INPUT) {
		acpi_registers_input(facp->gpe0_blk, val, size);
	} else {
		acpi_registers_output(facp->gpe0_blk, val, size);
	}

#ifdef ACPI_DEBUG
	device_printf(dev, "acpi_io_gpe0_status(%d) = (%x)\n",
			io, *val);
#endif

	return;
}

static void
acpi_io_gpe0_enable(device_t dev, boolean_t io, u_int32_t *val)
{
	struct acpi_softc *sc = device_get_softc(dev);
	struct FACPbody *facp = sc->facp_body;
	int		size = facp->gpe0_len / 2;

	if (io == ACPI_REGISTERS_INPUT) {
		acpi_registers_input(facp->gpe0_blk + size, val, size);
	} else {
		acpi_registers_output(facp->gpe0_blk + size, val, size);
	}

#ifdef ACPI_DEBUG
	device_printf(dev, "acpi_io_gpe0_enable(%d) = (%x)\n",
			io, *val);
#endif

	return;
}

static void
acpi_io_gpe1_status(device_t dev, boolean_t io, u_int32_t *val)
{
	struct acpi_softc *sc = device_get_softc(dev);
	struct FACPbody *facp = sc->facp_body;
	int		size = facp->gpe1_len / 2;

	if (io == ACPI_REGISTERS_INPUT) {
		acpi_registers_input(facp->gpe1_blk, val, size);
	} else {
		acpi_registers_output(facp->gpe1_blk, val, size);
	}

#ifdef ACPI_DEBUG
	device_printf(dev, "acpi_io_gpe1_status(%d) = (%x)\n",
			io, *val);
#endif

	return;
}

static void
acpi_io_gpe1_enable(device_t dev, boolean_t io, u_int32_t *val)
{
	struct acpi_softc *sc = device_get_softc(dev);
	struct FACPbody *facp = sc->facp_body;
	int		size = facp->gpe1_len / 2;

	if (io == ACPI_REGISTERS_INPUT) {
		acpi_registers_input(facp->gpe1_blk + size, val, size);
	} else {
		acpi_registers_output(facp->gpe1_blk + size, val, size);
	}

#ifdef ACPI_DEBUG
	device_printf(dev, "acpi_io_gpe1_enable(%d) = (%x)\n",
			io, *val);
#endif

	return;
}

static int
acpiopen(dev_t dev, int flag, int fmt, struct proc * p)
{
	return 0;
}
static int
acpiclose(dev_t dev, int flag, int fmt, struct proc * p)
{
	return 0;
}
static int
acpiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc * p)
{
	return EINVAL;
}
static int
acpimmap(dev_t dev, vm_offset_t offset, int nprot)
{
	struct acpi_softc *sc = devclass_get_softc(acpi_devclass, minor(dev));
	if (sc == NULL) {
		return EINVAL;
	}
	return i386_btop(vtophys(sc->dsdt + offset));
}



