summaryrefslogtreecommitdiff
path: root/sys/dev/acpi
diff options
context:
space:
mode:
authorCan Erkin Acar <canacar@cvs.openbsd.org>2006-05-29 00:54:24 +0000
committerCan Erkin Acar <canacar@cvs.openbsd.org>2006-05-29 00:54:24 +0000
commitf5aba5f9c1ba75e3e44e86095ed112ba01deab57 (patch)
treefd72d3f93027b62bb481c66dd280ff74e6023058 /sys/dev/acpi
parent450461b7cfe8a8d75fb5f85fa8782ad09d4c22e7 (diff)
Add embedded controller support.
ok marco@ deraadt@ testing & ok gwk@
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r--sys/dev/acpi/acpi.c93
-rw-r--r--sys/dev/acpi/acpiec.c537
-rw-r--r--sys/dev/acpi/acpivar.h11
-rw-r--r--sys/dev/acpi/files.acpi7
4 files changed, 640 insertions, 8 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c
index d7242d908fc..56c308e92ec 100644
--- a/sys/dev/acpi/acpi.c
+++ b/sys/dev/acpi/acpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi.c,v 1.49 2006/05/19 09:24:32 canacar Exp $ */
+/* $OpenBSD: acpi.c,v 1.50 2006/05/29 00:54:23 canacar Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -59,6 +59,7 @@ void acpi_write_pmreg(struct acpi_softc *, int, int);
void acpi_foundpss(struct aml_node *, void *);
void acpi_foundhid(struct aml_node *, void *);
+void acpi_foundec(struct aml_node *, void *);
void acpi_foundtmp(struct aml_node *, void *);
void acpi_inidev(struct aml_node *, void *);
@@ -248,6 +249,14 @@ acpi_gasio(struct acpi_softc *sc, int iodir, int iospace, uint64_t address,
pb++;
}
break;
+ case GAS_EMBEDDED:
+ if (sc->sc_ec == NULL)
+ break;
+ if (iodir == ACPI_IOREAD)
+ acpiec_read(sc->sc_ec, (u_int8_t)address, len, buffer);
+ else
+ acpiec_write(sc->sc_ec, (u_int8_t)address, len, buffer);
+ break;
}
return (0);
}
@@ -556,6 +565,45 @@ acpi_foundhid(struct aml_node *node, void *arg)
config_found(self, &aaa, acpi_print);
}
+
+void
+acpi_foundec(struct aml_node *node, void *arg)
+{
+ struct acpi_softc *sc = (struct acpi_softc *)arg;
+ struct device *self = (struct device *)arg;
+ const char *dev;
+ struct aml_value res;
+ struct acpi_attach_args aaa;
+
+ dnprintf(10, "found hid device: %s ", node->parent->name);
+ aml_eval_object(sc, node, &res, 0, NULL);
+
+ switch (res.type) {
+ case AML_OBJTYPE_STRING:
+ dev = aml_strval(&res);
+ break;
+ case AML_OBJTYPE_INTEGER:
+ dev = aml_eisaid(aml_val2int(NULL, &res));
+ break;
+ default:
+ dev = "unknown";
+ break;
+ }
+ dnprintf(10, " device: %s\n", dev);
+
+ memset(&aaa, 0, sizeof(aaa));
+ aaa.aaa_iot = sc->sc_iot;
+ aaa.aaa_memt = sc->sc_memt;
+ aaa.aaa_node = node->parent;
+ aaa.aaa_dev = dev;
+
+ if (!strcmp(dev, ACPI_DEV_ECD))
+ aaa.aaa_name = "acpiec";
+
+ if (aaa.aaa_name)
+ config_found(self, &aaa, acpi_print);
+}
+
int
acpi_match(struct device *parent, void *match, void *aux)
{
@@ -766,6 +814,7 @@ acpi_attach(struct device *parent, struct device *self, void *aux)
aml_find_node(aml_root.child, "_INI", acpi_inidev, sc);
/* attach devices found in dsdt */
+ aml_find_node(aml_root.child, "_HID", acpi_foundec, sc);
aml_find_node(aml_root.child, "_HID", acpi_foundhid, sc);
/* attach devices found in dsdt */
@@ -941,8 +990,9 @@ int
acpi_interrupt(void *arg)
{
struct acpi_softc *sc = (struct acpi_softc *)arg;
- u_int32_t processed, sts, en;
+ u_int32_t ec, processed, sts, en;
+ ec = 0;
processed = 0;
sts = acpi_read_pmreg(sc, ACPIREG_GPE0_STS);
@@ -956,6 +1006,11 @@ acpi_interrupt(void *arg)
sc->sc_gpe_sts = sts;
sc->sc_gpe_en = en;
processed = 1;
+ if ((sc->sc_ec != NULL) && (sts & sc->sc_ec_gpemask)) {
+ ec = 1;
+ if ((sts & en) == sc->sc_ec_gpemask)
+ processed = 0;
+ }
}
sts = acpi_read_pmreg(sc, ACPIREG_PM1_STS);
@@ -963,7 +1018,7 @@ acpi_interrupt(void *arg)
if (sts & en) {
dnprintf(10,"GEN interrupt: %.4x\n", sts & en);
acpi_write_pmreg(sc, ACPIREG_PM1_EN, en & ~sts);
- acpi_write_pmreg(sc, ACPIREG_PM1_STS,en);
+ acpi_write_pmreg(sc, ACPIREG_PM1_STS, en);
acpi_write_pmreg(sc, ACPIREG_PM1_EN, en);
if (sts & ACPI_PM1_PWRBTN_STS)
sc->sc_powerbtn = 1;
@@ -971,12 +1026,25 @@ acpi_interrupt(void *arg)
sc->sc_sleepbtn = 1;
processed = 1;
}
+
+ if (ec) {
+ if (acpiec_intr(sc->sc_ec))
+ processed = 1;
+
+ sts = sc->sc_ec_gpemask;
+ en = acpi_read_pmreg(sc, ACPIREG_GPE0_EN);
+
+ /* enable SCI once again */
+ acpi_write_pmreg(sc, ACPIREG_GPE0_STS, sts);
+ acpi_write_pmreg(sc, ACPIREG_GPE0_EN, en | sts);
+ }
+
if (processed) {
sc->sc_wakeup = 0;
wakeup(sc);
}
- return (processed);
+ return (processed | ec);
}
void
@@ -1011,6 +1079,16 @@ acpi_init_gpes(struct acpi_softc *sc)
}
void
+acpi_enable_gpe(struct acpi_softc *sc, u_int32_t gpemask)
+{
+ u_int32_t mask;
+ dnprintf(10, "acpi_enable_gpe: mask 0x%08x\n", gpemask);
+ mask = acpi_read_pmreg(sc, ACPIREG_GPE0_EN);
+ acpi_write_pmreg(sc, ACPIREG_GPE0_EN, mask | gpemask);
+ dnprintf(10, "acpi_enable_gpe: GPE 0x%08x\n", mask | gpemask);
+}
+
+void
acpi_init_states(struct acpi_softc *sc)
{
struct acpi_context *ctx;
@@ -1346,8 +1424,9 @@ acpi_isr_thread(void *arg)
acpi_write_pmreg(sc, ACPIREG_GPE0_EN, 0);
acpi_write_pmreg(sc, ACPIREG_GPE0_STS, -1);
- /* XXX: Enable GPEs _L1D */
- acpi_write_pmreg(sc, ACPIREG_GPE0_EN, (1L << 0x1D));
+ /* Enable EC interrupt */
+ if (sc->sc_ec != NULL)
+ acpi_enable_gpe(sc, sc->sc_ec_gpemask);
}
while (thread->running) {
@@ -1395,6 +1474,8 @@ acpi_isr_thread(void *arg)
KNOTE(sc->sc_note, ACPI_EVENT_COMPOSE(ACPI_EV_SLPBTN,
acpi_evindex));
}
+ if (sc->sc_ec)
+ acpiec_handle_events(sc->sc_ec);
}
free(thread, M_DEVBUF);
diff --git a/sys/dev/acpi/acpiec.c b/sys/dev/acpi/acpiec.c
new file mode 100644
index 00000000000..14b5b9680b6
--- /dev/null
+++ b/sys/dev/acpi/acpiec.c
@@ -0,0 +1,537 @@
+/* $OpenBSD: acpiec.c,v 1.1 2006/05/29 00:54:23 canacar Exp $ */
+/*
+ * Copyright (c) 2006 Can Erkin Acar <canacar@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/rwlock.h>
+
+#include <machine/bus.h>
+
+#include <dev/acpi/acpireg.h>
+#include <dev/acpi/acpivar.h>
+#include <dev/acpi/acpidev.h>
+#include <dev/acpi/amltypes.h>
+#include <dev/acpi/dsdt.h>
+
+#include <sys/sensors.h>
+
+int acpiec_match(struct device *, void *, void *);
+void acpiec_attach(struct device *, struct device *, void *);
+int acpiec_notify(struct aml_node *, int, void *);
+
+u_int8_t acpiec_status(struct acpiec_softc *);
+u_int8_t acpiec_read_data(struct acpiec_softc *);
+void acpiec_write_cmd(struct acpiec_softc *, u_int8_t);
+void acpiec_write_data(struct acpiec_softc *, u_int8_t);
+void acpiec_burst_enable(struct acpiec_softc *sc);
+
+u_int8_t acpiec_read_1(struct acpiec_softc *, u_int8_t);
+void acpiec_write_1(struct acpiec_softc *, u_int8_t, u_int8_t);
+
+void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
+void acpiec_write(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
+
+int acpiec_getcrs(struct acpiec_softc *, struct acpi_attach_args *);
+int acpiec_getregister(const u_int8_t *, int, int *, bus_size_t *);
+
+void acpiec_wait(struct acpiec_softc *, u_int8_t, u_int8_t);
+void acpiec_wait_nosleep(struct acpiec_softc *, u_int8_t, u_int8_t);
+void acpiec_sci_event(struct acpiec_softc *);
+
+void acpiec_get_events(struct acpiec_softc *);
+
+struct aml_node *aml_find_name(struct acpi_softc *, struct aml_node *,
+ const char *);
+
+/* EC Staus bits */
+#define EC_STAT_SMI_EVT 0x40 /* SMI event pending */
+#define EC_STAT_SCI_EVT 0x20 /* SCI event pending */
+#define EC_STAT_BURST 0x10 /* Controller in burst mode */
+#define EC_STAT_CMD 0x08 /* data is command */
+#define EC_STAT_IBF 0x02 /* input buffer full */
+#define EC_STAT_OBF 0x01 /* output buffer full */
+
+/* EC Commands */
+#define EC_CMD_RD 0x80 /* Read */
+#define EC_CMD_WR 0x81 /* Write */
+#define EC_CMD_BE 0x82 /* Burst Enable */
+#define EC_CMD_BD 0x83 /* Burst Disable */
+#define EC_CMD_QR 0x84 /* Query */
+
+#define ACPIEC_MAX_EVENTS 256
+struct acpiec_event {
+ struct aml_node *event;
+ int active;
+};
+
+struct acpiec_softc {
+ struct device sc_dev;
+
+ /* command/status register */
+ bus_space_tag_t sc_cmd_bt;
+ bus_space_handle_t sc_cmd_bh;
+
+ /* data register */
+ bus_space_tag_t sc_data_bt;
+ bus_space_handle_t sc_data_bh;
+
+ struct acpi_softc *sc_acpi;
+ struct aml_node *sc_devnode;
+ u_int32_t sc_gpe;
+ struct acpiec_event sc_events[ACPIEC_MAX_EVENTS];
+ struct rwlock sc_lock;
+ int sc_locked;
+ int sc_pending;
+};
+
+
+int acpiec_reg(struct acpiec_softc *);
+
+struct cfattach acpiec_ca = {
+ sizeof(struct acpiec_softc), acpiec_match, acpiec_attach
+};
+
+struct cfdriver acpiec_cd = {
+ NULL, "acpiec", DV_DULL
+};
+
+int
+acpiec_intr(struct acpiec_softc *sc)
+{
+ u_int8_t stat;
+
+ stat = acpiec_status(sc);
+ dnprintf(40, "%s: EC interrupt, stat: %b\n", DEVNAME(sc), (int)stat,
+ "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
+
+ if (stat & (EC_STAT_IBF | EC_STAT_OBF | EC_STAT_BURST ))
+ wakeup(sc);
+ if ((stat & EC_STAT_SCI_EVT) != 0 && sc->sc_locked == 0)
+ acpiec_sci_event(sc);
+
+ return (sc->sc_pending);
+}
+
+void
+acpiec_wait(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val)
+{
+ u_int8_t stat;
+ dnprintf(40, "%s: EC wait for: %b == %02x\n", DEVNAME(sc), (int)mask,
+ "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val);
+
+ for (;;) {
+ if (((stat = acpiec_status(sc)) & mask) == val)
+ break;
+ tsleep(sc, PWAIT, "acpiec", 10);
+ }
+ dnprintf(40, "%s: EC wait, stat: %b\n", DEVNAME(sc), (int) stat,
+ "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
+}
+
+void
+acpiec_wait_nosleep(struct acpiec_softc *sc, u_int8_t mask, u_int8_t val)
+{
+ u_int8_t stat;
+ dnprintf(40, "%s: EC wait_ns for: %b == %02x\n", DEVNAME(sc), (int)mask,
+ "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF", (int)val);
+
+ for (;;) {
+ if (((stat = acpiec_status(sc)) & mask) == val)
+ break;
+ delay(1);
+ }
+ dnprintf(40, "%s: EC wait_ns, stat: %b\n", DEVNAME(sc), (int)stat,
+ "\20\x8IGN\x7SMI\x6SCI\05BURST\04CMD\03IGN\02IBF\01OBF");
+}
+
+u_int8_t
+acpiec_status(struct acpiec_softc *sc)
+{
+ return bus_space_read_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0);
+}
+
+void
+acpiec_write_data(struct acpiec_softc *sc, u_int8_t val)
+{
+ acpiec_wait(sc, EC_STAT_IBF, 0);
+ dnprintf(40, "acpiec: write_data -- %d\n", (int) val);
+ bus_space_write_1(sc->sc_data_bt, sc->sc_data_bh, 0, val);
+}
+
+void
+acpiec_write_cmd(struct acpiec_softc *sc, u_int8_t val)
+{
+ acpiec_wait(sc, EC_STAT_IBF, 0);
+ dnprintf(40, "acpiec: write_cmd -- %d\n", (int) val);
+ bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, val);
+}
+
+u_int8_t
+acpiec_read_data(struct acpiec_softc *sc)
+{
+ u_int8_t val;
+ acpiec_wait(sc, EC_STAT_OBF, EC_STAT_OBF);
+ dnprintf(40, "acpiec: read_data\n", (int) val);
+ val = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
+
+ return val;
+}
+
+void
+acpiec_sci_event(struct acpiec_softc *sc)
+{
+ u_int8_t evt;
+
+ acpiec_wait_nosleep(sc, EC_STAT_IBF, 0);
+ bus_space_write_1(sc->sc_cmd_bt, sc->sc_cmd_bh, 0, EC_CMD_QR);
+
+ acpiec_wait_nosleep(sc, EC_STAT_OBF, EC_STAT_OBF);
+ evt = bus_space_read_1(sc->sc_data_bt, sc->sc_data_bh, 0);
+
+ dnprintf(10, "%s: sci_event: 0x%02x\n", DEVNAME(sc), (int) evt);
+
+ sc->sc_events[evt].active = 1;
+ sc->sc_pending = 1;
+
+ sc->sc_acpi->sc_wakeup = 0;
+ wakeup(sc->sc_acpi);
+}
+
+u_int8_t
+acpiec_read_1(struct acpiec_softc *sc, u_int8_t addr)
+{
+ u_int8_t val;
+
+ if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
+ acpiec_sci_event(sc);
+
+ acpiec_write_cmd(sc, EC_CMD_RD);
+ acpiec_write_data(sc, addr);
+
+ val = acpiec_read_data(sc);
+
+ return val;
+}
+
+void
+acpiec_write_1(struct acpiec_softc *sc, u_int8_t addr, u_int8_t data)
+{
+ if ((acpiec_status(sc) & EC_STAT_SCI_EVT) == EC_STAT_SCI_EVT)
+ acpiec_sci_event(sc);
+
+ acpiec_write_cmd(sc, EC_CMD_WR);
+ acpiec_write_data(sc, addr);
+ acpiec_write_data(sc, data);
+}
+
+void
+acpiec_burst_enable(struct acpiec_softc *sc)
+{
+ acpiec_write_cmd(sc, EC_CMD_BE);
+ acpiec_read_data(sc);
+}
+
+void
+acpiec_read(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
+{
+ int reg;
+ rw_enter_write(&sc->sc_lock);
+ sc->sc_locked = 1;
+
+ acpiec_burst_enable(sc);
+ dnprintf(20, "%s: read %d, %d\n", DEVNAME(sc), (int) addr, len);
+
+ for (reg = 0; reg < len; reg++)
+ buffer[reg] = acpiec_read_1(sc, addr + reg);
+
+ sc->sc_locked = 0;
+ rw_exit_write(&sc->sc_lock);
+}
+
+void
+acpiec_write(struct acpiec_softc *sc, u_int8_t addr, int len, u_int8_t *buffer)
+{
+ int reg;
+ rw_enter_write(&sc->sc_lock);
+ sc->sc_locked = 1;
+
+ acpiec_burst_enable(sc);
+ dnprintf(20, "%s: write %d, %d\n", DEVNAME(sc), (int) addr, len);
+ for (reg = 0; reg < len; reg++)
+ acpiec_write_1(sc, addr + reg, buffer[reg]);
+
+ sc->sc_locked = 0;
+ rw_exit_write(&sc->sc_lock);
+}
+
+int
+acpiec_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
+acpiec_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct acpiec_softc *sc = (struct acpiec_softc *)self;
+ struct acpi_attach_args *aa = aux;
+
+ sc->sc_acpi = (struct acpi_softc *)parent;
+ sc->sc_devnode = aa->aaa_node->child;
+
+ rw_init(&sc->sc_lock, "acpi_ec");
+ sc->sc_locked = 0;
+
+ if (sc->sc_acpi->sc_ec != NULL) {
+ printf(": Only single EC is supported!\n");
+ return;
+ }
+
+ if (acpiec_getcrs(sc, aa)) {
+ printf(": Failed to read resource settings\n");
+ return;
+ }
+
+ if (acpiec_reg(sc)) {
+ printf(": Failed to register address space\n");
+ return;
+ }
+
+ acpiec_get_events(sc);
+
+ sc->sc_acpi->sc_ec = sc;
+ sc->sc_acpi->sc_ec_gpemask = (1L << sc->sc_gpe);
+
+ dnprintf(10, "%s: GPE: %d (%x)\n", DEVNAME(sc),
+ sc->sc_gpe, sc->sc_acpi->sc_ec_gpemask);
+
+ /* Enable EC interrupt */
+ acpi_enable_gpe(sc->sc_acpi, sc->sc_acpi->sc_ec_gpemask);
+
+ printf(": %s\n", sc->sc_devnode->parent->name);
+}
+
+void
+acpiec_get_events(struct acpiec_softc *sc)
+{
+ int idx;
+ char name[16];
+
+ memset(sc->sc_events, 0, sizeof(sc->sc_events));
+ for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) {
+ snprintf(name, sizeof(name), "_Q%02X", idx);
+ sc->sc_events[idx].event = aml_searchname(sc->sc_devnode, name);
+ if (sc->sc_events[idx].event != NULL)
+ dnprintf(10, "%s: Found event %s\n", DEVNAME(sc), name);
+ }
+}
+
+void
+acpiec_handle_events(struct acpiec_softc *sc)
+{
+ struct aml_value res;
+ int idx;
+
+ if (sc->sc_pending == 0)
+ return;
+
+ sc->sc_pending = 0;
+
+ for (idx = 0; idx < ACPIEC_MAX_EVENTS; idx++) {
+ if (sc->sc_events[idx].active == 0 ||
+ sc->sc_events[idx].event == NULL)
+ continue;
+ dnprintf(10, "%s: handling event 0x%02x\n", DEVNAME(sc), idx);
+ aml_eval_object(sc->sc_acpi, sc->sc_events[idx].event,
+ &res, 0, NULL);
+ sc->sc_events[idx].active = 0;
+ }
+}
+
+
+/* parse the resource buffer to get a 'register' value */
+int
+acpiec_getregister(const u_int8_t *buf, int size, int *type, bus_size_t *addr)
+{
+ int len, hlen;
+
+#define RES_TYPE_MASK 0x80
+#define RES_LENGTH_MASK 0x07
+#define RES_TYPE_IOPORT 0x47
+#define RES_TYPE_ENDTAG 0x79
+
+ if (size <= 0)
+ return (0);
+
+ if (*buf & RES_TYPE_MASK) {
+ /* large resource */
+ if (size < 3)
+ return (1);
+ len = (int) buf[1] + 256 * (int) buf[2];
+ hlen = 3;
+ } else {
+ /* small resource */
+ len = buf[0] & RES_LENGTH_MASK;
+ hlen = 1;
+ }
+
+ /* XXX todo: decode other types */
+ if (*buf != RES_TYPE_IOPORT)
+ return (0);
+
+ if (size < hlen + len)
+ return (0);
+
+ /* XXX validate? */
+ *type = GAS_SYSTEM_IOSPACE;
+ *addr = (int) buf[2] + 256 * (int) buf[3];
+
+ return (hlen + len);
+}
+
+int
+acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa)
+{
+ struct aml_value res, env;
+ bus_size_t ec_sc, ec_data;
+ int type1, type2;
+ char *buf;
+ int size, ret;
+
+ memset(&res, 0, sizeof(res));
+ memset(&env, 0, sizeof(env));
+
+ if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_GPE", &res, &env)) {
+ dnprintf(10, "%s: no _GPE\n", DEVNAME(sc));
+ return (1);
+ }
+
+ sc->sc_gpe = aml_val2int(NULL, &res);
+
+ if (aml_eval_name(sc->sc_acpi, sc->sc_devnode, "_CRS", &res, &env)) {
+ dnprintf(10, "%s: no _CRS\n", DEVNAME(sc));
+ return (1);
+ }
+
+ /* Parse CRS to get control and data registers */
+
+ if (res.type != AML_OBJTYPE_BUFFER) {
+ dnprintf(10, "%s: unknown _CRS type %d\n",
+ DEVNAME(sc), res.type);
+ return (1);
+ }
+
+ size = res.length;
+ buf = res.v_buffer;
+
+ ret = acpiec_getregister(buf, size, &type1, &ec_data);
+ if (ret <= 0) {
+ dnprintf(10, "%s: failed to read DATA from _CRS\n",
+ DEVNAME(sc));
+ return (1);
+ }
+
+ buf += ret;
+ size -= ret;
+
+ ret = acpiec_getregister(buf, size, &type2, &ec_sc);
+ if (ret <= 0) {
+ dnprintf(10, "%s: failed to read S/C from _CRS\n",
+ DEVNAME(sc));
+ return (1);
+ }
+
+ buf += ret;
+ size -= ret;
+
+ if (size != 2 || *buf != RES_TYPE_ENDTAG) {
+ dnprintf(10, "%s: no _CRS end tag\n", DEVNAME(sc));
+ return (1);
+ }
+
+ /* XXX: todo - validate _CRS checksum? */
+
+ dnprintf(10, "%s: Data: 0x%x, S/C: 0x%x\n",
+ DEVNAME(sc), ec_data, ec_sc);
+
+ if (type1 == GAS_SYSTEM_IOSPACE)
+ sc->sc_cmd_bt = aa->aaa_iot;
+ else
+ sc->sc_cmd_bt = aa->aaa_memt;
+
+ if (bus_space_map(sc->sc_cmd_bt, ec_sc, 1, 0, &sc->sc_cmd_bh)) {
+ dnprintf(10, "%s: failed to map S/C reg.\n", DEVNAME(sc));
+ return (1);
+ }
+
+ if (type2 == GAS_SYSTEM_IOSPACE)
+ sc->sc_data_bt = aa->aaa_iot;
+ else
+ sc->sc_data_bt = aa->aaa_memt;
+
+ if (bus_space_map(sc->sc_data_bt, ec_data, 1, 0, &sc->sc_data_bh)) {
+ dnprintf(10, "%s: failed to map DATA reg.\n", DEVNAME(sc));
+ bus_space_unmap(sc->sc_cmd_bt, sc->sc_cmd_bh, 1);
+ return (1);
+ }
+
+ return (0);
+}
+
+int
+acpiec_reg(struct acpiec_softc *sc)
+{
+ struct aml_value res, arg[2];
+ struct aml_node *root;
+
+ memset(&res, 0, sizeof(res));
+ memset(&arg, 0, sizeof(arg));
+
+#define REG_TYPE_EC 3
+
+ arg[0].type = AML_OBJTYPE_INTEGER;
+ arg[0].v_integer = REG_TYPE_EC;
+ arg[1].type = AML_OBJTYPE_INTEGER;
+ arg[1].v_integer = 1;
+
+ root = aml_find_name(sc->sc_acpi, sc->sc_devnode, "_REG");
+
+ if (root == NULL) {
+ dnprintf(10, "%s: no _REG method\n", DEVNAME(sc));
+ return (1);
+ }
+
+ if (aml_eval_object(sc->sc_acpi, root, &res, 2, arg)) {
+ dnprintf(10, "%s: evaluating method _REG failed.\n", DEVNAME(sc));
+ return (1);
+ }
+
+ return (0);
+}
diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h
index ad6b6ce48f6..a977de14c17 100644
--- a/sys/dev/acpi/acpivar.h
+++ b/sys/dev/acpi/acpivar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpivar.h,v 1.22 2006/04/11 02:35:35 gwk Exp $ */
+/* $OpenBSD: acpivar.h,v 1.23 2006/05/29 00:54:23 canacar Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
@@ -31,6 +31,7 @@ extern int acpi_debug;
#endif
struct klist;
+struct acpiec_softc;
struct acpi_attach_args {
char *aaa_name;
@@ -155,6 +156,8 @@ struct acpi_softc {
struct aml_node *sc_gts;
struct aml_node *sc_wak;
int sc_state;
+ struct acpiec_softc *sc_ec; /* XXX assume single EC */
+ u_int32_t sc_ec_gpemask;
};
#define GPE_NONE 0x00
@@ -197,6 +200,12 @@ void acpi_resume(struct acpi_softc *);
void acpi_delay(struct acpi_softc *, int64_t);
int acpi_gasio(struct acpi_softc *, int, int, uint64_t, int, int, void *);
+void acpi_enable_gpe(struct acpi_softc *, u_int32_t);
+
+int acpiec_intr(struct acpiec_softc *);
+void acpiec_read(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
+void acpiec_write(struct acpiec_softc *, u_int8_t, int, u_int8_t *);
+void acpiec_handle_events(struct acpiec_softc *);
#endif
#endif /* !_DEV_ACPI_ACPIVAR_H_ */
diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi
index 70c35c2ec5b..53018f9e704 100644
--- a/sys/dev/acpi/files.acpi
+++ b/sys/dev/acpi/files.acpi
@@ -1,4 +1,4 @@
-# $OpenBSD: files.acpi,v 1.11 2006/05/19 09:24:32 canacar Exp $
+# $OpenBSD: files.acpi,v 1.12 2006/05/29 00:54:23 canacar Exp $
#
# Config file and device description for machine-independent ACPI code.
# Included by ports that need it.
@@ -41,6 +41,11 @@ device acpihpet
attach acpihpet at acpi
file dev/acpi/acpihpet.c acpihpet
+# Embedded Controller
+device acpiec
+attach acpiec at acpi
+file dev/acpi/acpiec.c acpiec
+
# Thermal Zone
device acpitz
attach acpitz at acpi