diff options
author | Can Erkin Acar <canacar@cvs.openbsd.org> | 2006-05-29 00:54:24 +0000 |
---|---|---|
committer | Can Erkin Acar <canacar@cvs.openbsd.org> | 2006-05-29 00:54:24 +0000 |
commit | f5aba5f9c1ba75e3e44e86095ed112ba01deab57 (patch) | |
tree | fd72d3f93027b62bb481c66dd280ff74e6023058 /sys/dev/acpi | |
parent | 450461b7cfe8a8d75fb5f85fa8782ad09d4c22e7 (diff) |
Add embedded controller support.
ok marco@ deraadt@ testing & ok gwk@
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r-- | sys/dev/acpi/acpi.c | 93 | ||||
-rw-r--r-- | sys/dev/acpi/acpiec.c | 537 | ||||
-rw-r--r-- | sys/dev/acpi/acpivar.h | 11 | ||||
-rw-r--r-- | sys/dev/acpi/files.acpi | 7 |
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 |