diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/acpi/acpi.c | 180 | ||||
-rw-r--r-- | sys/dev/acpi/acpiac.c | 8 | ||||
-rw-r--r-- | sys/dev/acpi/acpiasus.c | 6 | ||||
-rw-r--r-- | sys/dev/acpi/acpibat.c | 18 | ||||
-rw-r--r-- | sys/dev/acpi/acpibtn.c | 10 | ||||
-rw-r--r-- | sys/dev/acpi/acpidebug.c | 54 | ||||
-rw-r--r-- | sys/dev/acpi/acpidock.c | 14 | ||||
-rw-r--r-- | sys/dev/acpi/acpiec.c | 4 | ||||
-rw-r--r-- | sys/dev/acpi/acpiprt.c | 56 | ||||
-rw-r--r-- | sys/dev/acpi/acpithinkpad.c | 8 | ||||
-rw-r--r-- | sys/dev/acpi/acpitz.c | 14 | ||||
-rw-r--r-- | sys/dev/acpi/amltypes.h | 3 | ||||
-rw-r--r-- | sys/dev/acpi/dsdt.c | 2723 | ||||
-rw-r--r-- | sys/dev/acpi/dsdt.h | 3 |
14 files changed, 2969 insertions, 132 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 604a06f3016..21a8b6c1060 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.116 2008/04/27 16:23:16 jcs Exp $ */ +/* $OpenBSD: acpi.c,v 1.117 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -87,6 +87,8 @@ void acpi_enable_onegpe(struct acpi_softc *, int, int); int acpi_gpe_level(struct acpi_softc *, int, void *); int acpi_gpe_edge(struct acpi_softc *, int, void *); +struct gpe_block *acpi_find_gpe(struct acpi_softc *, int); + #define ACPI_LOCK(sc) #define ACPI_UNLOCK(sc) @@ -173,6 +175,9 @@ acpi_gasio(struct acpi_softc *sc, int iodir, int iospace, uint64_t address, *(uint32_t *)(pb+reg) = bus_space_read_4( sc->sc_iot, ioh, reg); break; + default: + printf("rdio: invalid size %d\n", access_size); + break; } } else { switch (access_size) { @@ -192,6 +197,9 @@ acpi_gasio(struct acpi_softc *sc, int iodir, int iospace, uint64_t address, bus_space_write_4(sc->sc_iot, ioh, reg, *(uint32_t *)(pb+reg)); break; + default: + printf("wrio: invalid size %d\n", access_size); + break; } } @@ -266,7 +274,7 @@ acpi_inidev(struct aml_node *node, void *arg) */ /* Evaluate _STA to decide _INI fate and walk fate */ - if (!aml_evalname(sc, node, "_STA", 0, NULL, &res)) + if (!aml_evalname(sc, node->parent, "_STA", 0, NULL, &res)) st = (int)aml_val2int(&res); aml_freevalue(&res); @@ -304,7 +312,7 @@ acpi_foundprt(struct aml_node *node, void *arg) st |= STA_BATTERY; /* Evaluate _STA to decide _PRT fate and walk fate */ - if (!aml_evalname(sc, node, "_STA", 0, NULL, &res)) + if (!aml_evalname(sc, node->parent, "_STA", 0, NULL, &res)) st = (int)aml_val2int(&res); aml_freevalue(&res); @@ -612,22 +620,22 @@ acpi_attach(struct device *parent, struct device *self, void *aux) acpi_softc = sc; /* initialize runtime environment */ - aml_find_node(aml_root.child, "_INI", acpi_inidev, sc); + aml_find_node(&aml_root, "_INI", acpi_inidev, sc); /* attach pci interrupt routing tables */ - aml_find_node(aml_root.child, "_PRT", acpi_foundprt, sc); + aml_find_node(&aml_root, "_PRT", acpi_foundprt, sc); #ifndef SMALL_KERNEL /* XXX EC needs to be attached first on some systems */ - aml_find_node(aml_root.child, "_HID", acpi_foundec, sc); + aml_find_node(&aml_root, "_HID", acpi_foundec, sc); aml_walknodes(&aml_root, AML_WALK_PRE, acpi_add_device, sc); /* attach battery, power supply and button devices */ - aml_find_node(aml_root.child, "_HID", acpi_foundhid, sc); + aml_find_node(&aml_root, "_HID", acpi_foundhid, sc); /* attach docks */ - aml_find_node(aml_root.child, "_DCK", acpi_founddock, sc); + aml_find_node(&aml_root, "_DCK", acpi_founddock, sc); /* create list of devices we want to query when APM come in */ SLIST_INIT(&sc->sc_ac); @@ -1138,6 +1146,9 @@ acpi_write_pmreg(struct acpi_softc *sc, int reg, int offset, int regval) sc->sc_pmregs[reg].name, sc->sc_pmregs[reg].addr, offset, regval); } +void +acpi_add_gpeblock(struct acpi_softc *sc, int reg, int len, int gpe); + int acpi_interrupt(void *arg) { @@ -1146,6 +1157,12 @@ acpi_interrupt(void *arg) processed = 0; +#if 0 + acpi_add_gpeblock(sc, sc->sc_fadt->gpe0_blk, sc->sc_fadt->gpe0_blk_len>>1, 0); + acpi_add_gpeblock(sc, sc->sc_fadt->gpe1_blk, sc->sc_fadt->gpe1_blk_len>>1, + sc->sc_fadt->gpe1_base); +#endif + dnprintf(40, "ACPI Interrupt\n"); for (idx = 0; idx < sc->sc_lastgpe; idx += 8) { sts = acpi_read_pmreg(sc, ACPIREG_GPE_STS, idx>>3); @@ -1244,19 +1261,18 @@ int acpi_set_gpehandler(struct acpi_softc *sc, int gpe, int (*handler) (struct acpi_softc *, int, void *), void *arg, const char *label) { - if (gpe >= sc->sc_lastgpe || handler == NULL) - return -EINVAL; + struct gpe_block *ptbl; - if (sc->gpe_table[gpe].handler != NULL) { + ptbl = acpi_find_gpe(sc, gpe); + if (ptbl == NULL || handler == NULL) + return -EINVAL; + if (ptbl->handler != NULL) { dnprintf(10, "error: GPE %.2x already enabled\n", gpe); return -EBUSY; } - dnprintf(50, "Adding GPE handler %.2x (%s)\n", gpe, label); - sc->gpe_table[gpe].handler = handler; - sc->gpe_table[gpe].arg = arg; - - /* Defer enabling GPEs */ + ptbl->handler = handler; + ptbl->arg = arg; return (0); } @@ -1341,6 +1357,112 @@ acpi_foundprw(struct aml_node *node, void *arg) return 0; } +struct gpe_block * +acpi_find_gpe(struct acpi_softc *sc, int gpe) +{ +#if 1 + if (gpe >= sc->sc_lastgpe) + return NULL; + return &sc->gpe_table[gpe]; +#else + SIMPLEQ_FOREACH(pgpe, &sc->sc_gpes, gpe_link) { + if (gpe >= pgpe->start && gpe <= (pgpe->start+7)) + return &pgpe->table[gpe & 7]; + } + return NULL; +#endif +} + +#if 0 +/* New GPE handling code: Create GPE block */ +void +acpi_init_gpeblock(struct acpi_softc *sc, int reg, int len, int base) +{ + int i, j; + + if (!reg || !len) + return; + for (i=0; i<len; i++) { + pgpe = acpi_os_malloc(sizeof(gpeblock)); + if (pgpe == NULL) + return; + + /* Allocate GPE Handler Block */ + pgpe->start = base + i; + acpi_bus_space_map(sc->sc_iot, reg+i, 1, 0, &pgpe->sts_ioh); + acpi_bus_space_map(sc->sc_iot, reg+i+len, 1, 0, &pgpe->en_ioh); + SIMPLEQ_INSERT_TAIL(&sc->sc_gpes, gpe, gpe_link); + + /* Clear pending GPEs */ + bus_space_write_1(sc->sc_iot, pgpe->sts_ioh, 0, 0xFF); + bus_space_write_1(sc->sc_iot, pgpe->en_ioh, 0, 0x00); + } + + /* Search for GPE handlers */ + for (i=0; i<len*8; i++) { + char gpestr[32]; + struct aml_node *h; + + snprintf(gpestr, sizeof(gpestr), "\\_GPE._L%.2X", base+i); + h = aml_searchnode(&aml_root, gpestr); + if (acpi_set_gpehandler(sc, base+i, acpi_gpe_level, h, "level") != 0) { + snprintf(gpestr, sizeof(gpestr), "\\_GPE._E%.2X", base+i); + h = aml_searchnode(&aml_root, gpestr); + acpi_set_gpehandler(sc, base+i, acpi_gpe_edge, h, "edge"); + } + } +} + +/* Process GPE interrupts */ +int +acpi_handle_gpes(struct acpi_softc *sc) +{ + uint8_t en, sts; + int processed, i; + + processed=0; + SIMPLEQ_FOREACH(pgpe, &sc->sc_gpes, gpe_link) { + sts = bus_space_read_1(sc->sc_iot, pgpe->sts_ioh, 0); + en = bus_space_read_1(sc->sc_iot, pgpe->en_ioh, 0); + for (i=0; i<8; i++) { + if (en & sts & (1L << i)) { + pgpe->table[i].active = 1; + processed=1; + } + } + } + return processed; +} +#endif + +void +acpi_add_gpeblock(struct acpi_softc *sc, int reg, int len, int gpe) +{ + int idx, jdx; + u_int8_t en, sts; + + if (!reg || !len) + return; + for (idx=0; idx<len; idx++) { + sts = inb(reg + idx); + en = inb(reg + len + idx); + printf("-- gpe %.2x-%.2x : en:%.2x sts:%.2x %.2x\n", + gpe+idx*8, gpe+idx*8+7, en, sts, en&sts); + for (jdx=0; jdx<8; jdx++) { + char gpestr[32]; + struct aml_node *l, *e; + + if (en & sts & (1L << jdx)) { + snprintf(gpestr,sizeof(gpestr), "\\_GPE._L%.2X", gpe+idx*8+jdx); + l = aml_searchname(&aml_root, gpestr); + snprintf(gpestr,sizeof(gpestr), "\\_GPE._E%.2X", gpe+idx*8+jdx); + e = aml_searchname(&aml_root, gpestr); + printf(" GPE %.2x active L%x E%x\n", gpe+idx*8+jdx, l, e); + } + } + } +} + void acpi_init_gpes(struct acpi_softc *sc) { @@ -1348,6 +1470,12 @@ acpi_init_gpes(struct acpi_softc *sc) char name[12]; int idx, ngpe; +#if 0 + acpi_add_gpeblock(sc, sc->sc_fadt->gpe0_blk, sc->sc_fadt->gpe0_blk_len>>1, 0); + acpi_add_gpeblock(sc, sc->sc_fadt->gpe1_blk, sc->sc_fadt->gpe1_blk_len>>1, + sc->sc_fadt->gpe1_base); +#endif + sc->sc_lastgpe = sc->sc_fadt->gpe0_blk_len << 2; if (sc->sc_fadt->gpe1_blk_len) { } @@ -1380,7 +1508,7 @@ acpi_init_gpes(struct acpi_softc *sc) "edge"); } } - aml_find_node(aml_root.child, "_PRW", acpi_foundprw, sc); + aml_find_node(&aml_root, "_PRW", acpi_foundprw, sc); sc->sc_maxgpe = ngpe; } @@ -1395,7 +1523,7 @@ acpi_init_states(struct acpi_softc *sc) snprintf(name, sizeof(name), "_S%d_", i); sc->sc_sleeptype[i].slp_typa = -1; sc->sc_sleeptype[i].slp_typb = -1; - if (aml_evalname(sc, aml_root.child, name, 0, NULL, &res) == 0) { + if (aml_evalname(sc, &aml_root, name, 0, NULL, &res) == 0) { if (res.type == AML_OBJTYPE_PACKAGE) { sc->sc_sleeptype[i].slp_typa = aml_val2int(res.v_package[0]); sc->sc_sleeptype[i].slp_typb = aml_val2int(res.v_package[1]); @@ -1408,11 +1536,11 @@ acpi_init_states(struct acpi_softc *sc) void acpi_init_pm(struct acpi_softc *sc) { - sc->sc_tts = aml_searchname(aml_root.child, "_TTS"); - sc->sc_pts = aml_searchname(aml_root.child, "_PTS"); - sc->sc_wak = aml_searchname(aml_root.child, "_WAK"); - sc->sc_bfs = aml_searchname(aml_root.child, "_BFS"); - sc->sc_gts = aml_searchname(aml_root.child, "_GTS"); + sc->sc_tts = aml_searchname(&aml_root, "_TTS"); + sc->sc_pts = aml_searchname(&aml_root, "_PTS"); + sc->sc_wak = aml_searchname(&aml_root, "_WAK"); + sc->sc_bfs = aml_searchname(&aml_root, "_BFS"); + sc->sc_gts = aml_searchname(&aml_root, "_GTS"); } void @@ -1431,6 +1559,7 @@ acpi_enter_sleep_state(struct acpi_softc *sc, int state) return; } + memset(&env, 0, sizeof(env)); env.type = AML_OBJTYPE_INTEGER; env.v_integer = state; /* _TTS(state) */ @@ -1508,6 +1637,7 @@ acpi_resume(struct acpi_softc *sc) { struct aml_value env; + memset(&env, 0, sizeof(env)); env.type = AML_OBJTYPE_INTEGER; env.v_integer = sc->sc_state; @@ -1541,6 +1671,8 @@ acpi_powerdown(void) acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5); } +extern int aml_busy; + void acpi_isr_thread(void *arg) { @@ -1585,6 +1717,8 @@ acpi_isr_thread(void *arg) tsleep(sc, PWAIT, "acpi_idle", 0); sc->sc_wakeup = 1; dnprintf(10, "wakeup..\n"); + if (aml_busy) + continue; for (gpe = 0; gpe < sc->sc_lastgpe; gpe++) { struct gpe_block *pgpe = &sc->gpe_table[gpe]; diff --git a/sys/dev/acpi/acpiac.c b/sys/dev/acpi/acpiac.c index 4d9bcda0b49..bd349ede386 100644 --- a/sys/dev/acpi/acpiac.c +++ b/sys/dev/acpi/acpiac.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpiac.c,v 1.19 2007/11/03 22:51:21 canacar Exp $ */ +/* $OpenBSD: acpiac.c,v 1.20 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -66,9 +66,9 @@ acpiac_attach(struct device *parent, struct device *self, void *aux) struct acpi_attach_args *aa = aux; sc->sc_acpi = (struct acpi_softc *)parent; - sc->sc_devnode = aa->aaa_node->child; + sc->sc_devnode = aa->aaa_node; - aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev, + aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpiac_notify, sc, ACPIDEV_NOPOLL); acpiac_getsta(sc); @@ -125,7 +125,7 @@ acpiac_notify(struct aml_node *node, int notify_type, void *arg) struct acpiac_softc *sc = arg; dnprintf(10, "acpiac_notify: %.2x %s\n", notify_type, - sc->sc_devnode->parent->name); + sc->sc_devnode->name); switch (notify_type) { case 0x00: diff --git a/sys/dev/acpi/acpiasus.c b/sys/dev/acpi/acpiasus.c index 78e23f2bc02..2d1a83d1c03 100644 --- a/sys/dev/acpi/acpiasus.c +++ b/sys/dev/acpi/acpiasus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpiasus.c,v 1.1 2008/04/24 13:57:49 jsing Exp $ */ +/* $OpenBSD: acpiasus.c,v 1.2 2008/05/14 05:24:36 jordan Exp $ */ /* $NetBSD: asus_acpi.c,v 1.2.2.2 2008/04/03 12:42:37 mjf Exp $ */ /*- @@ -115,7 +115,7 @@ acpiasus_attach(struct device *parent, struct device *self, void *aux) struct acpi_attach_args *aa = aux; sc->sc_acpi = (struct acpi_softc *)parent; - sc->sc_devnode = aa->aaa_node->child; + sc->sc_devnode = aa->aaa_node; sc->sc_powerhook = powerhook_establish(acpiasus_power, sc); @@ -123,7 +123,7 @@ acpiasus_attach(struct device *parent, struct device *self, void *aux) acpiasus_init(self); - aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev, + aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpiasus_notify, sc, ACPIDEV_NOPOLL); } diff --git a/sys/dev/acpi/acpibat.c b/sys/dev/acpi/acpibat.c index 90d01e3608d..9ba4516ab09 100644 --- a/sys/dev/acpi/acpibat.c +++ b/sys/dev/acpi/acpibat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpibat.c,v 1.46 2007/11/16 13:58:18 deraadt Exp $ */ +/* $OpenBSD: acpibat.c,v 1.47 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -70,7 +70,7 @@ acpibat_attach(struct device *parent, struct device *self, void *aux) struct aml_value res; sc->sc_acpi = (struct acpi_softc *)parent; - sc->sc_devnode = aa->aaa_node->child; + sc->sc_devnode = aa->aaa_node; if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &res)) { dnprintf(10, "%s: no _STA\n", DEVNAME(sc)); @@ -81,7 +81,7 @@ acpibat_attach(struct device *parent, struct device *self, void *aux) acpibat_getbif(sc); acpibat_getbst(sc); - printf(": %s", sc->sc_devnode->parent->name); + printf(": %s", sc->sc_devnode->name); if (sc->sc_bif.bif_model[0]) printf(" model \"%s\"", sc->sc_bif.bif_model); if (sc->sc_bif.bif_serial[0]) @@ -92,7 +92,7 @@ acpibat_attach(struct device *parent, struct device *self, void *aux) printf(" oem \"%s\"", sc->sc_bif.bif_oem); printf("\n"); } else - printf(": %s not present\n", sc->sc_devnode->parent->name); + printf(": %s not present\n", sc->sc_devnode->name); aml_freevalue(&res); @@ -102,7 +102,7 @@ acpibat_attach(struct device *parent, struct device *self, void *aux) /* populate sensors */ acpibat_refresh(sc); - aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev, + aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpibat_notify, sc, ACPIDEV_POLL); } @@ -173,7 +173,7 @@ acpibat_refresh(void *arg) int i; dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc), - sc->sc_devnode->parent->name); + sc->sc_devnode->name); if (!sc->sc_bat_present) { for (i = 0; i < 8; i++) { @@ -398,13 +398,13 @@ acpibat_notify(struct aml_node *node, int notify_type, void *arg) struct acpibat_softc *sc = arg; dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type, - sc->sc_devnode->parent->name); + sc->sc_devnode->name); switch (notify_type) { case 0x80: /* _BST changed */ if (!sc->sc_bat_present) { printf("%s: %s: inserted\n", DEVNAME(sc), - sc->sc_devnode->parent->name); + sc->sc_devnode->name); sc->sc_bat_present = 1; } break; @@ -412,7 +412,7 @@ acpibat_notify(struct aml_node *node, int notify_type, void *arg) /* XXX consider this a device removal */ if (sc->sc_bat_present) { printf("%s: %s: removed\n", DEVNAME(sc), - sc->sc_devnode->parent->name); + sc->sc_devnode->name); sc->sc_bat_present = 0; } break; diff --git a/sys/dev/acpi/acpibtn.c b/sys/dev/acpi/acpibtn.c index 8d7ae2fdd42..cc1e70853f3 100644 --- a/sys/dev/acpi/acpibtn.c +++ b/sys/dev/acpi/acpibtn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpibtn.c,v 1.16 2008/04/12 12:49:28 kettenis Exp $ */ +/* $OpenBSD: acpibtn.c,v 1.17 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -84,7 +84,7 @@ acpibtn_attach(struct device *parent, struct device *self, void *aux) struct acpi_attach_args *aa = aux; sc->sc_acpi = (struct acpi_softc *)parent; - sc->sc_devnode = aa->aaa_node->child; + sc->sc_devnode = aa->aaa_node; if (!strcmp(aa->aaa_dev, ACPI_DEV_LD)) sc->sc_btn_type = ACPIBTN_LID; @@ -97,9 +97,9 @@ acpibtn_attach(struct device *parent, struct device *self, void *aux) acpibtn_getsta(sc); - printf(": %s\n", sc->sc_devnode->parent->name); + printf(": %s\n", sc->sc_devnode->name); - aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev, acpibtn_notify, + aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpibtn_notify, sc, ACPIDEV_NOPOLL); } @@ -120,7 +120,7 @@ acpibtn_notify(struct aml_node *node, int notify_type, void *arg) struct acpibtn_softc *sc = arg; dnprintf(10, "acpibtn_notify: %.2x %s\n", notify_type, - sc->sc_devnode->parent->name); + sc->sc_devnode->name); switch (sc->sc_btn_type) { case ACPIBTN_LID: diff --git a/sys/dev/acpi/acpidebug.c b/sys/dev/acpi/acpidebug.c index 0a80d43b0cd..5bcb8b86535 100644 --- a/sys/dev/acpi/acpidebug.c +++ b/sys/dev/acpi/acpidebug.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpidebug.c,v 1.16 2007/11/12 21:58:14 deraadt Exp $ */ +/* $OpenBSD: acpidebug.c,v 1.17 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2006 Marco Peereboom <marco@openbsd.org> * @@ -165,21 +165,21 @@ db_aml_showvalue(struct aml_value *value) AML_FIELD_UPDATE(value->v_field.flags), value->v_field.bitpos, value->v_field.bitlen); - - db_aml_showvalue(value->v_field.ref1); - db_aml_showvalue(value->v_field.ref2); + if (value->v_field.ref2) + db_printf(" index: %.3x %s\n", + value->v_field.ref3, + aml_nodename(value->v_field.ref2->node)); + if (value->v_field.ref1) + db_printf(" data: %s\n", + aml_nodename(value->v_field.ref1->node)); break; case AML_OBJTYPE_BUFFERFIELD: - db_printf("%s: pos=%.4x len=%.4x ", + db_printf("%s: pos=%.4x len=%.4x\n", aml_mnem(value->v_field.type, NULL), value->v_field.bitpos, value->v_field.bitlen); - - db_aml_dump(aml_bytelen(value->v_field.bitlen), - value->v_field.ref1->v_buffer + - aml_bytepos(value->v_field.bitpos)); - - db_aml_showvalue(value->v_field.ref1); + db_printf(" buffer: %s\n", + aml_nodename(value->v_field.ref1->node)); break; case AML_OBJTYPE_OPREGION: db_printf("opregion: %s,0x%llx,0x%x\n", @@ -306,6 +306,24 @@ db_acpi_showval(db_expr_t addr, int haddr, db_expr_t count, char *modif) } void +aml_disasm(struct aml_scope *scope, int lvl, + void (*dbprintf)(void *, const char *, ...), + void *arg); +void db_disprint(void *, const char *, ...); + +void db_disprint(void *arg, const char *fmt, ...) +{ + va_list ap; + char stre[64]; + + va_start(ap,fmt); + vsnprintf(stre, sizeof(stre), fmt, ap); + va_end(ap); + + db_printf(stre); +} + +void db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif) { struct aml_node *node; @@ -315,10 +333,24 @@ db_acpi_disasm(db_expr_t addr, int haddr, db_expr_t count, char *modif) node = aml_searchname(&aml_root, scope); if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) { + struct aml_scope ns; + + memset(&ns, 0, sizeof(ns)); + ns.pos = node->value->v_method.start; + ns.end = node->value->v_method.end; + ns.node = node; + while (ns.pos < ns.end) + aml_disasm(&ns, 0, db_disprint, 0); + } + else + db_printf("Not a valid method\n"); +#if 0 + if (node && node->value && node->value->type == AML_OBJTYPE_METHOD) { db_aml_disasm(node, node->value->v_method.start, node->value->v_method.end, -1, 0); } else db_printf("Not a valid method\n"); +#endif } void diff --git a/sys/dev/acpi/acpidock.c b/sys/dev/acpi/acpidock.c index 4103e40fbc0..397de321206 100644 --- a/sys/dev/acpi/acpidock.c +++ b/sys/dev/acpi/acpidock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpidock.c,v 1.27 2007/11/12 21:58:14 deraadt Exp $ */ +/* $OpenBSD: acpidock.c,v 1.28 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2006,2007 Michael Knudsen <mk@openbsd.org> * @@ -76,9 +76,9 @@ acpidock_attach(struct device *parent, struct device *self, void *aux) extern struct aml_node aml_root; sc->sc_acpi = (struct acpi_softc *)parent; - sc->sc_devnode = aa->aaa_node->child; + sc->sc_devnode = aa->aaa_node; - printf(": %s", sc->sc_devnode->parent->name); + printf(": %s", sc->sc_devnode->name); acpidock_status(sc); if (sc->sc_docked == ACPIDOCK_STATUS_DOCKED) { @@ -111,7 +111,7 @@ acpidock_attach(struct device *parent, struct device *self, void *aux) TAILQ_INIT(&sc->sc_deps_h); aml_find_node(aml_root.child, "_EJD", acpidock_foundejd, sc); - aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev, + aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpidock_notify, sc, ACPIDEV_NOPOLL); } @@ -270,7 +270,7 @@ acpidock_foundejd(struct aml_node *node, void *arg) struct acpidock_softc *sc = (struct acpidock_softc *)arg; struct aml_value res; - dnprintf(15, "%s: %s", DEVNAME(sc), node->parent->name); + dnprintf(15, "%s: %s", DEVNAME(sc), node->name); if (aml_evalnode(sc->sc_acpi, node, 0, NULL, &res) == -1) { printf(": error\n"); @@ -279,11 +279,11 @@ acpidock_foundejd(struct aml_node *node, void *arg) /* XXX debug */ dnprintf(10, "%s: %s depends on %s\n", DEVNAME(sc), - node->parent->name, res.v_string); + node->name, res.v_string); /* XXX more than one dock? */ n = malloc(sizeof(struct aml_nodelist), M_DEVBUF, M_WAITOK); - n->node = node->parent; + n->node = node; TAILQ_INSERT_TAIL(&sc->sc_deps_h, n, entries); } diff --git a/sys/dev/acpi/acpiec.c b/sys/dev/acpi/acpiec.c index 8f342914aa7..e505f552919 100644 --- a/sys/dev/acpi/acpiec.c +++ b/sys/dev/acpi/acpiec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpiec.c,v 1.21 2007/12/07 19:06:02 fgsch Exp $ */ +/* $OpenBSD: acpiec.c,v 1.22 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2006 Can Erkin Acar <canacar@openbsd.org> * @@ -279,7 +279,7 @@ acpiec_attach(struct device *parent, struct device *self, void *aux) struct acpi_attach_args *aa = aux; sc->sc_acpi = (struct acpi_softc *)parent; - sc->sc_devnode = aa->aaa_node->child; + sc->sc_devnode = aa->aaa_node; if (sc->sc_acpi->sc_ec != NULL) { printf(": Only single EC is supported\n"); diff --git a/sys/dev/acpi/acpiprt.c b/sys/dev/acpi/acpiprt.c index 187475bb603..a6a980f6798 100644 --- a/sys/dev/acpi/acpiprt.c +++ b/sys/dev/acpi/acpiprt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpiprt.c,v 1.20 2007/11/12 21:58:14 deraadt Exp $ */ +/* $OpenBSD: acpiprt.c,v 1.21 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org> * @@ -45,6 +45,7 @@ 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_getminbus(union acpi_resource *, void *); +int acpiprt_showprs(union acpi_resource *, void *); struct acpiprt_softc { @@ -119,6 +120,37 @@ acpiprt_attach(struct device *parent, struct device *self, void *aux) } int +acpiprt_showprs(union acpi_resource *crs, void *arg) +{ + int *irq = (int *)arg; + int typ; + + typ = AML_CRSTYPE(crs); + switch (typ) { + case SR_IRQ: + printf("possible irq:[ "); + for (typ=0; typ<sizeof(crs->sr_irq.irq_mask)*8; typ++) { + if (crs->sr_irq.irq_mask & (1L << typ)) { + printf("%d%s ", typ, (typ == *irq) ? "*" : ""); + } + } + printf("]\n"); + break; + case LR_EXTIRQ: + printf("possible irq: [ "); + for (typ=0; typ<crs->lr_extirq.irq_count; typ++) { + printf("%d%s ", crs->lr_extirq.irq[typ], + crs->lr_extirq.irq[typ] == *irq ? "*" : ""); + } + printf("]\n"); + break; + default: + printf("Unknown interrupt : %x\n", typ); + } + return (0); +} + +int acpiprt_getirq(union acpi_resource *crs, void *arg) { int *irq = (int *)arg; @@ -166,8 +198,17 @@ acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v) } pp = v->v_package[2]; + if (pp->type == AML_OBJTYPE_STRING) { + printf("STRING: %s\n", pp->v_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_searchname(sc->sc_devnode, pp->v_nameref); + node = aml_searchrel(sc->sc_devnode, pp->v_nameref); if (node == NULL) { printf("Invalid device\n"); return; @@ -198,6 +239,16 @@ acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v) aml_parse_resource(res.length, res.v_buffer, acpiprt_getirq, &irq); aml_freevalue(&res); + + if (!aml_evalname(sc->sc_acpi, node, "_PRS.", 0, NULL, &res)){ + if (res.type == AML_OBJTYPE_BUFFER && + res.length >= 6) + { + aml_parse_resource(res.length, res.v_buffer, + acpiprt_showprs, &irq); + } + aml_freevalue(&res); + } } else { irq = aml_val2int(v->v_package[3]); } @@ -340,6 +391,5 @@ acpiprt_getpcibus(struct acpiprt_softc *sc, struct aml_node *node) return (PPB_BUSINFO_SECONDARY(reg)); } } - return (0); } diff --git a/sys/dev/acpi/acpithinkpad.c b/sys/dev/acpi/acpithinkpad.c index a434bcff06b..a956d774127 100644 --- a/sys/dev/acpi/acpithinkpad.c +++ b/sys/dev/acpi/acpithinkpad.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpithinkpad.c,v 1.2 2008/05/14 02:02:05 jcs Exp $ */ +/* $OpenBSD: acpithinkpad.c,v 1.3 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2008 joshua stein <jcs@openbsd.org> @@ -112,7 +112,7 @@ thinkpad_match(struct device *parent, void *match, void *aux) aa->aaa_table != NULL) return (0); - if (aml_evalname((struct acpi_softc *)parent, aa->aaa_node->child, + if (aml_evalname((struct acpi_softc *)parent, aa->aaa_node, "MHKV", 0, NULL, &res)) goto fail; @@ -134,7 +134,7 @@ thinkpad_attach(struct device *parent, struct device *self, void *aux) struct acpi_attach_args *aa = aux; sc->sc_acpi = (struct acpi_softc *)parent; - sc->sc_devnode = aa->aaa_node->child; + sc->sc_devnode = aa->aaa_node; printf("\n"); @@ -142,7 +142,7 @@ thinkpad_attach(struct device *parent, struct device *self, void *aux) thinkpad_enable_events(sc); /* run thinkpad_hotkey on button presses */ - aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev, + aml_register_notify(sc->sc_devnode, aa->aaa_dev, thinkpad_hotkey, sc, ACPIDEV_NOPOLL); return; diff --git a/sys/dev/acpi/acpitz.c b/sys/dev/acpi/acpitz.c index 725cf65db1a..be6d35bbe41 100644 --- a/sys/dev/acpi/acpitz.c +++ b/sys/dev/acpi/acpitz.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpitz.c,v 1.23 2008/04/12 12:49:28 kettenis Exp $ */ +/* $OpenBSD: acpitz.c,v 1.24 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2006 Can Erkin Acar <canacar@openbsd.org> * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> @@ -104,7 +104,7 @@ acpitz_attach(struct device *parent, struct device *self, void *aux) char name[8]; sc->sc_acpi = (struct acpi_softc *)parent; - sc->sc_devnode = aa->aaa_node->child; + sc->sc_devnode = aa->aaa_node; sc->sc_lasttmp = -1; if ((sc->sc_tmp = acpitz_gettempreading(sc, "_TMP")) == -1) { @@ -142,7 +142,7 @@ acpitz_attach(struct device *parent, struct device *self, void *aux) sensordev_install(&sc->sc_sensdev); sc->sc_sens.value = 0; - aml_register_notify(sc->sc_devnode->parent, NULL, + aml_register_notify(sc->sc_devnode, NULL, acpitz_notify, sc, ACPIDEV_POLL); } @@ -252,12 +252,12 @@ acpitz_refresh(void *arg) int i, perc; dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc), - sc->sc_devnode->parent->name); + 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->parent->name); + sc->sc_devnode->name); return; } /* critical trip points */ @@ -351,7 +351,7 @@ acpitz_gettempreading(struct acpitz_softc *sc, char *name) } if (i >= ACPITZ_TMP_RETRY) { printf("%s: %s: failed to read %s\n", DEVNAME(sc), - sc->sc_devnode->parent->name, name); + sc->sc_devnode->name, name); goto out; } out: @@ -367,7 +367,7 @@ acpitz_notify(struct aml_node *node, int notify_type, void *arg) int crt; dnprintf(10, "%s notify: %.2x %s\n", DEVNAME(sc), notify_type, - sc->sc_devnode->parent->name); + sc->sc_devnode->name); switch (notify_type) { case 0x80: /* hardware notifications */ diff --git a/sys/dev/acpi/amltypes.h b/sys/dev/acpi/amltypes.h index 54fd887a99d..daa7d03fe30 100644 --- a/sys/dev/acpi/amltypes.h +++ b/sys/dev/acpi/amltypes.h @@ -1,4 +1,4 @@ -/* $OpenBSD: amltypes.h,v 1.26 2008/05/13 09:05:06 jordan Exp $ */ +/* $OpenBSD: amltypes.h,v 1.27 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> * @@ -275,6 +275,7 @@ struct aml_value { u_int8_t iospace; u_int64_t iobase; u_int32_t iolen; + int flag; } vopregion; struct { int flags; diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c index be6e3916367..90cd6e1524f 100644 --- a/sys/dev/acpi/dsdt.c +++ b/sys/dev/acpi/dsdt.c @@ -1,5 +1,5 @@ -/* $OpenBSD: dsdt.c,v 1.109 2008/02/07 17:48:59 henning Exp $ */ +/* $OpenBSD: dsdt.c,v 1.110 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> * @@ -184,9 +184,9 @@ struct aml_opcode aml_table[] = { { AMLOP_ARG6, "Arg6", "A", aml_parseref }, /* Control flow */ - { AMLOP_IF, "If", "pI", aml_parseif }, + { AMLOP_IF, "If", "piI", aml_parseif }, { AMLOP_ELSE, "Else", "pT" }, - { AMLOP_WHILE, "While", "piT", aml_parsewhile }, + { AMLOP_WHILE, "While", "pW", aml_parsewhile }, { AMLOP_BREAK, "Break", "" }, { AMLOP_CONTINUE, "Continue", "" }, { AMLOP_RETURN, "Return", "t", aml_parseref }, @@ -234,20 +234,20 @@ struct aml_opcode aml_table[] = { { AMLOP_OPREGION, "OpRegion", "Nbii", aml_parsenamed }, { AMLOP_SCOPE, "Scope", "pNT", aml_parsenamedscope }, { AMLOP_DEVICE, "Device", "pNT", aml_parsenamedscope }, - { AMLOP_POWERRSRC, "Power Resource", "pNbwT", aml_parsenamedscope }, + { AMLOP_POWERRSRC, "Power Resource", "pNbwT",aml_parsenamedscope }, { AMLOP_THERMALZONE, "ThermalZone", "pNT", aml_parsenamedscope }, { AMLOP_PROCESSOR, "Processor", "pNbdbT", aml_parsenamedscope }, - { AMLOP_METHOD, "Method", "pNfM", aml_parsemethod }, + { AMLOP_METHOD, "Method", "pNbM", aml_parsemethod }, /* Field operations */ - { AMLOP_FIELD, "Field", "pnfF", aml_parsefieldunit }, - { AMLOP_INDEXFIELD, "IndexField", "pntfF", aml_parsefieldunit }, - { AMLOP_BANKFIELD, "BankField", "pnnifF", aml_parsefieldunit }, + { AMLOP_FIELD, "Field", "pnbF", aml_parsefieldunit }, + { AMLOP_INDEXFIELD, "IndexField", "pnnbF",aml_parsefieldunit }, + { AMLOP_BANKFIELD, "BankField", "pnnibF",aml_parsefieldunit }, { AMLOP_CREATEFIELD, "CreateField", "tiiN", aml_parsebufferfield }, - { AMLOP_CREATEQWORDFIELD, "CreateQWordField","tiN", aml_parsebufferfield }, - { AMLOP_CREATEDWORDFIELD, "CreateDWordField","tiN", aml_parsebufferfield }, - { AMLOP_CREATEWORDFIELD, "CreateWordField", "tiN", aml_parsebufferfield }, - { AMLOP_CREATEBYTEFIELD, "CreateByteField", "tiN", aml_parsebufferfield }, + { AMLOP_CREATEQWORDFIELD, "CreateQWordField","tiN",aml_parsebufferfield }, + { AMLOP_CREATEDWORDFIELD, "CreateDWordField","tiN",aml_parsebufferfield }, + { AMLOP_CREATEWORDFIELD, "CreateWordField", "tiN",aml_parsebufferfield }, + { AMLOP_CREATEBYTEFIELD, "CreateByteField", "tiN",aml_parsebufferfield }, { AMLOP_CREATEBITFIELD, "CreateBitField", "tiN", aml_parsebufferfield }, /* Conversion operations */ @@ -255,36 +255,36 @@ struct aml_opcode aml_table[] = { { AMLOP_TOBUFFER, "ToBuffer", "tr", }, { AMLOP_TODECSTRING, "ToDecString", "ir", aml_parsestring }, { AMLOP_TOHEXSTRING, "ToHexString", "ir", aml_parsestring }, - { AMLOP_TOSTRING, "ToString", "t", aml_parsestring }, + { AMLOP_TOSTRING, "ToString", "tir", aml_parsestring }, { AMLOP_MID, "Mid", "tiir", aml_parsestring }, { AMLOP_FROMBCD, "FromBCD", "ir", aml_parsemath }, { AMLOP_TOBCD, "ToBCD", "ir", aml_parsemath }, /* Mutex/Signal operations */ - { AMLOP_ACQUIRE, "Acquire", "tw", aml_parsemuxaction }, - { AMLOP_RELEASE, "Release", "t", aml_parsemuxaction }, - { AMLOP_SIGNAL, "Signal", "t", aml_parsemuxaction }, - { AMLOP_WAIT, "Wait", "ti", aml_parsemuxaction }, - { AMLOP_RESET, "Reset", "t", aml_parsemuxaction }, + { AMLOP_ACQUIRE, "Acquire", "Sw", aml_parsemuxaction }, + { AMLOP_RELEASE, "Release", "S", aml_parsemuxaction }, + { AMLOP_SIGNAL, "Signal", "S", aml_parsemuxaction }, + { AMLOP_WAIT, "Wait", "Si", aml_parsemuxaction }, + { AMLOP_RESET, "Reset", "S", aml_parsemuxaction }, { AMLOP_INDEX, "Index", "tir", aml_parseref }, { AMLOP_DEREFOF, "DerefOf", "t", aml_parseref }, - { AMLOP_REFOF, "RefOf", "t", aml_parseref }, - { AMLOP_CONDREFOF, "CondRef", "nr", aml_parseref }, + { AMLOP_REFOF, "RefOf", "S", aml_parseref }, + { AMLOP_CONDREFOF, "CondRef", "SS", aml_parseref }, { AMLOP_LOADTABLE, "LoadTable", "tttttt" }, { AMLOP_STALL, "Stall", "i", aml_parsemisc2 }, { AMLOP_SLEEP, "Sleep", "i", aml_parsemisc2 }, - { AMLOP_LOAD, "Load", "nt", aml_parseref }, + { AMLOP_LOAD, "Load", "nS", aml_parseref }, { AMLOP_UNLOAD, "Unload", "t" }, - { AMLOP_STORE, "Store", "tr", aml_parseref }, + { AMLOP_STORE, "Store", "tS", aml_parseref }, { AMLOP_CONCAT, "Concat", "ttr", aml_parsestring }, { AMLOP_CONCATRES, "ConcatRes", "ttt" }, - { AMLOP_NOTIFY, "Notify", "ti", aml_parsemisc2 }, - { AMLOP_SIZEOF, "Sizeof", "t", aml_parsemisc3 }, + { AMLOP_NOTIFY, "Notify", "Si", aml_parsemisc2 }, + { AMLOP_SIZEOF, "Sizeof", "S", aml_parsemisc3 }, { AMLOP_MATCH, "Match", "tbibii", aml_parsematch }, - { AMLOP_OBJECTTYPE, "ObjectType", "t", aml_parsemisc3 }, - { AMLOP_COPYOBJECT, "CopyObject", "tr", aml_parseref }, + { AMLOP_OBJECTTYPE, "ObjectType", "S", aml_parsemisc3 }, + { AMLOP_COPYOBJECT, "CopyObject", "tS", aml_parseref }, }; int aml_pc(uint8_t *src) @@ -668,21 +668,40 @@ void acpi_poll_notify(void) * @@@: Namespace functions */ -struct aml_node *__aml_search(struct aml_node *, uint8_t *); +struct aml_node *__aml_search(struct aml_node *, uint8_t *, int); void aml_delchildren(struct aml_node *); /* Search for a name in children nodes */ struct aml_node * -__aml_search(struct aml_node *root, uint8_t *nameseg) +__aml_search(struct aml_node *root, uint8_t *nameseg, int create) { + struct aml_node **sp, *node; + + /* XXX: Replace with SLIST/SIMPLEQ routines */ if (root == NULL) return NULL; - for (root = root->child; root; root = root->sibling) { - if (!memcmp(root->name, nameseg, AML_NAMESEG_LEN)) - return root; + //rw_enter_read(&aml_nslock); + for (sp = &root->child; *sp; sp = &(*sp)->sibling) { + if (!strncmp((*sp)->name, nameseg, AML_NAMESEG_LEN)) { + //rw_exit_read(&aml_nslock); + return *sp; } - return NULL; + } + //rw_exit_read(&aml_nslock); + if (create) { + node = acpi_os_malloc(sizeof(struct aml_node)); + memcpy((void *)node->name, nameseg, AML_NAMESEG_LEN); + node->value = aml_allocvalue(0,0,NULL); + node->value->node = node; + node->parent = root; + node->sibling = NULL; + + //rw_enter_write(&aml_nslock); + *sp = node; + //rw_exit_write(&aml_nslock); + } + return *sp; } /* Get absolute pathname of AML node */ @@ -772,7 +791,7 @@ aml_createname(struct aml_node *root, const void *vname, struct aml_value *value node = NULL; while (count-- && root) { /* Create new name if it does not exist */ - if ((node = __aml_search(root, name)) == NULL) { + if ((node = __aml_search(root, name, 0)) == NULL) { node = acpi_os_malloc(sizeof(struct aml_node)); memcpy((void *)node->name, name, AML_NAMESEG_LEN); @@ -794,6 +813,7 @@ aml_createname(struct aml_node *root, const void *vname, struct aml_value *value } /* Search namespace for a named node */ +#if 0 struct aml_node * aml_searchname(struct aml_node *root, const void *vname) { @@ -826,23 +846,24 @@ aml_searchname(struct aml_node *root, const void *vname) default: if (name[4] == '.') { /* Called from user code */ - while (*name && (root = __aml_search(root, name)) != NULL) { + while (*name && (root = __aml_search(root, name, 0)) != NULL) { name += AML_NAMESEG_LEN+1; } return root; } /* Special case.. search relative for name */ - while (root && (node = __aml_search(root, name)) == NULL) { + while (root && (node = __aml_search(root, name, 0)) == NULL) { root = root->parent; } return node; } /* Search absolute for name*/ - while (count-- && (root = __aml_search(root, name)) != NULL) { + while (count-- && (root = __aml_search(root, name, 0)) != NULL) { name += AML_NAMESEG_LEN; } return root; } +#endif /* Free all children nodes/values */ void @@ -1034,7 +1055,8 @@ aml_getbufint(struct aml_value *src, int bitpos, int bitlen, long acpi_acquire_global_lock(void*); long acpi_release_global_lock(void*); static long global_lock_count = 0; - +#define acpi_acquire_global_lock(x) 1 +#define acpi_release_global_lock(x) 0 void aml_lockfield(struct aml_scope *scope, struct aml_value *field) { @@ -1963,7 +1985,7 @@ aml_evalexpr(int64_t lhs, int64_t rhs, int opcode) break; } - dnprintf(50,"aml_evalexpr: %s %llx %llx = %llx\n", + dnprintf(15,"aml_evalexpr: %s %llx %llx = %llx\n", aml_mnem(opcode, NULL), lhs, rhs, res); return res; @@ -2082,6 +2104,7 @@ aml_evalmethod(struct aml_scope *parent, struct aml_node *node, * evaluate an AML node * Returns a copy of the value in res (must be freed by user) */ +#if 0 int aml_evalnode(struct acpi_softc *sc, struct aml_node *node, int argc, struct aml_value *argv, struct aml_value *res) @@ -2160,6 +2183,7 @@ aml_evalinteger(struct acpi_softc *sc, struct aml_node *parent, } return 1; } +#endif void aml_walknodes(struct aml_node *node, int mode, @@ -3401,23 +3425,16 @@ char *aml_valid_osi[] = { struct aml_value * aml_callosi(struct aml_scope *scope, struct aml_value *val) { - struct aml_value tmpstr, *arg; - int idx, result; - - /* Perform comparison with valid strings */ - result = 0; - memset(&tmpstr, 0, sizeof(tmpstr)); - tmpstr.type = AML_OBJTYPE_STRING; - arg = aml_derefvalue(scope, &scope->args[0], ACPI_IOREAD); + int idx, result=0; + struct aml_value *fa; + fa = scope->args[0].v_objref.ref; for (idx=0; !result && aml_valid_osi[idx] != NULL; idx++) { - tmpstr.v_string = aml_valid_osi[idx]; - tmpstr.length = strlen(tmpstr.v_string); - - result = aml_cmpvalue(arg, &tmpstr, AMLOP_LEQUAL); + dnprintf(10,"osi: %s,%s\n", fa->v_string, aml_valid_osi[idx]); + result = !strcmp(fa->v_string, aml_valid_osi[idx]); } - aml_setvalue(scope, val, NULL, result); - return val; + dnprintf(10,"@@ OSI found: %x\n", result); + return aml_allocvalue(AML_OBJTYPE_INTEGER, result, NULL); } void @@ -3431,6 +3448,10 @@ aml_create_defaultobjects() osstring[15] = 'w'; osstring[18] = 'N'; + strlcpy(aml_root.name, "\\", sizeof(aml_root.name)); + aml_root.value = aml_allocvalue(0, 0, NULL); + aml_root.value->node = &aml_root; + for (def = aml_defobj; def->name; def++) { /* Allocate object value + add to namespace */ tmp = aml_allocvalue(def->type, def->ival, def->bval); @@ -3554,6 +3575,7 @@ aml_foreachpkg(struct aml_value *pkg, int start, fn(pkg->v_package[idx], arg); } +#if 0 int acpi_parse_aml(struct acpi_softc *sc, u_int8_t *start, u_int32_t length) { @@ -3572,6 +3594,7 @@ acpi_parse_aml(struct acpi_softc *sc, u_int8_t *start, u_int32_t length) return (0); } +#endif /* * Walk nodes and perform fixups for nameref @@ -3644,3 +3667,2599 @@ aml_val_to_string(const struct aml_value *val) return (buffer); } + +/* + * XXX: NEW PARSER CODE GOES HERE + */ +struct aml_value *aml_xeval(struct aml_scope *, struct aml_value *, int, int, + struct aml_value *); +struct aml_value *aml_xparsesimple(struct aml_scope *, char, + struct aml_value *); +struct aml_value *aml_xparse(struct aml_scope *, int, const char *); + +struct aml_scope *aml_xfindscope(struct aml_scope *, int, int); +struct aml_scope *aml_xpushscope(struct aml_scope *, struct aml_value *, + struct aml_node *, int); +struct aml_scope *aml_xpopscope(struct aml_scope *); + +void aml_showstack(struct aml_scope *); +void aml_xaddref(struct aml_value *, const char *); +void aml_xdelref(struct aml_value **, const char *); +void aml_xconvert(struct aml_value *, struct aml_value **, int, int); +int64_t aml_hextoint(const char *); + +int aml_xmatchtest(int64_t, int64_t, int); +int aml_xmatch(struct aml_value *, int, int, int, int, int); + +int aml_xcompare(struct aml_value *, struct aml_value *, int); +void aml_xconcat(struct aml_value *, struct aml_value *, + struct aml_value **); +void aml_xconcatres(struct aml_value *, struct aml_value *, + struct aml_value **); +int aml_ccrlen(union acpi_resource *, void *); +void aml_xmid(struct aml_value *, int, int, struct aml_value **); + +void aml_xstore(struct aml_scope *, struct aml_value *, int64_t, + struct aml_value *); + +int +valid_acpihdr(void *buf, int len, const char *sig) +{ + struct acpi_table_header *hdr = buf; + + if (sig && strncmp(hdr->signature, sig, 4)) { + return 0; + } + if (len < hdr->length) { + return 0; + } + if (acpi_checksum(hdr, hdr->length) != 0) { + return 0; + } + return 1; +} + +/* + * Reference Count functions + */ +void +aml_xaddref(struct aml_value *val, const char *lbl) +{ + if (val == NULL) + return; + dnprintf(50, "XAddRef: %p %s:[%s] %d\n", + val, lbl, + val->node ? aml_nodename(val->node) : "INTERNAL", + val->refcnt); + val->refcnt++; +} + +/* Decrease reference counter */ +void +aml_xdelref(struct aml_value **pv, const char *lbl) +{ + struct aml_value *val; + + if (pv == NULL || *pv == NULL) + return; + val = *pv; + val->refcnt--; + if (val->refcnt == 0) { + dnprintf(50, "XDelRef: %p %s %2d [%s] %s\n", + val, lbl, + val->refcnt, + val->node ? aml_nodename(val->node) : "INTERNAL", + val->refcnt ? "" : "---------------- FREEING"); + + aml_freevalue(val); + acpi_os_free(val); + *pv = NULL; + } +} + +/* Walk list of parent scopes until we find one of 'type' + * If endscope is set, mark all intermediate scopes as invalid (used for Method/While) */ +struct aml_scope * +aml_xfindscope(struct aml_scope *scope, int type, int endscope) +{ + while (scope) { + if (endscope) + scope->pos = NULL; + if (scope->type == type) + break; + scope = scope->parent; + } + return scope; +} + +/* Dump AML Stack */ +void +aml_showstack(struct aml_scope *scope) +{ + int idx; + + dnprintf(10, "===== Stack %s:%s\n", aml_nodename(scope->node), + aml_mnem(scope->type, 0)); + scope = aml_xfindscope(scope, AMLOP_METHOD, 0); + if (scope == NULL) + return; + for (idx=0; scope->args && idx<7; idx++) { + if (scope->args[idx].type) { + dnprintf(10," Arg%d: ", idx); + aml_showvalue(scope->args[idx].v_objref.ref, 10); + } + } + for (idx=0; scope->locals && idx<8; idx++) { + if (scope->locals[idx].type) { + dnprintf(10," Local%d: ", idx); + aml_showvalue(&scope->locals[idx], 10); + } + } +} + +/* Create a new scope object */ +struct aml_scope * +aml_xpushscope(struct aml_scope *parent, struct aml_value *range, + struct aml_node *node, int type) +{ + struct aml_scope *scope; + uint8_t *start, *end; + + if (range->type == AML_OBJTYPE_METHOD) { + start = range->v_method.start; + end = range->v_method.end; + } + else { + start = range->v_buffer; + end = start + range->length; + if (start == end) { + return NULL; + } + } + scope = acpi_os_malloc(sizeof(struct aml_scope)); + if (scope == NULL) + return NULL; + + scope->node = node; + scope->start = start; + scope->end = end; + scope->pos = scope->start; + scope->parent = parent; + scope->type = type; + scope->sc = dsdt_softc; + + aml_lastscope = scope; + + return scope; +} + +/* Free a scope object and any children */ +struct aml_scope * +aml_xpopscope(struct aml_scope *scope) +{ + struct aml_scope *nscope; + int idx; + + if (scope == NULL) + return NULL; + + nscope = scope->parent; + + if (scope->type == AMLOP_METHOD) { + aml_delchildren(scope->node); + } + if (scope->locals) { + for (idx=0; idx<8; idx++) { + aml_freevalue(&scope->locals[idx]); + } + acpi_os_free(scope->locals); + scope->locals = NULL; + } + if (scope->args) { + for (idx=0; idx<7; idx++) { + aml_freevalue(&scope->args[idx]); + } + acpi_os_free(scope->args); + scope->args = NULL; + } + acpi_os_free(scope); + aml_lastscope = nscope; + + return nscope; +} + +/* Test AMLOP_MATCH codes */ +int +aml_xmatchtest(int64_t a, int64_t b, int op) +{ + switch (op) { + case AML_MATCH_TR: + return (1); + case AML_MATCH_EQ: + return (a == b); + case AML_MATCH_LT: + return (a < b); + case AML_MATCH_LE: + return (a <= b); + case AML_MATCH_GE: + return (a >= b); + case AML_MATCH_GT: + return (a > b); + } + return 0; +} + +/* Search a package for a matching value */ +int +aml_xmatch(struct aml_value *pkg, int index, + int op1, int v1, + int op2, int v2) +{ + struct aml_value *tmp; + int flag; + + while (index < pkg->length) { + /* Convert package value to integer */ + aml_xconvert(pkg->v_package[index], &tmp, + AML_OBJTYPE_INTEGER, 0); + + /* Perform test */ + flag = aml_xmatchtest(tmp->v_integer, v1, op1) && + aml_xmatchtest(tmp->v_integer, v2, op2); + aml_xdelref(&tmp, "xmatch"); + + if (flag) + return index; + index++; + } + return -1; +} + +/* + * Namespace functions + */ +void ns_xdis(struct aml_node *node, int n, uint8_t *pos, void *arg); +void ns_xcreate(struct aml_node *node, int n, uint8_t *pos, void *arg); +void ns_xsearch(struct aml_node *node, int n, uint8_t *pos, void *arg); +uint8_t *aml_xparsename(uint8_t *pos, struct aml_node *node, + void (*fn)(struct aml_node *, int, uint8_t *, void *), void *arg); + +/* Search for name in namespace */ +void +ns_xsearch(struct aml_node *node, int n, uint8_t *pos, void *arg) +{ + struct aml_value **rv = arg; + struct aml_node *rnode; + + /* If name search is relative, check up parent nodes */ + for (rnode=node; n == 1 && rnode; rnode=rnode->parent) { + if (__aml_search(rnode, pos, 0) != NULL) { + break; + } + } + while (n--) { + rnode = __aml_search(rnode, pos, 0); + pos += 4; + } + if (rnode != NULL) { + *rv = rnode->value; + return; + } + *rv = NULL; +} + +/* Create name in namespace */ +void +ns_xcreate(struct aml_node *node, int n, uint8_t *pos, void *arg) +{ + struct aml_value **rv = arg; + + while (n--) { + node = __aml_search(node, pos, 1); + pos += 4; + } + *rv = node->value; +} + +void +ns_xdis(struct aml_node *node, int n, uint8_t *pos, void *arg) +{ + printf(aml_nodename(node)); + while (n--) { + printf("%s%c%c%c%c", n ? "." : "", + pos[0], pos[1], pos[2], pos[3]); + pos+=4; + } +} + +uint8_t * +aml_xparsename(uint8_t *pos, struct aml_node *node, + void (*fn)(struct aml_node *, int, uint8_t *, void *), void *arg) +{ + uint8_t *rpos = pos; + struct aml_value **rv = arg; + + if (*pos == AMLOP_ROOTCHAR) { + node = &aml_root; + pos++; + } + while (*pos == AMLOP_PARENTPREFIX) { + node = node ? node->parent : &aml_root; + pos++; + } + if (*pos == 0) { + fn(node, 0, pos, arg); + pos++; + } + else if (*pos == AMLOP_MULTINAMEPREFIX) { + fn(node, pos[1], pos+2, arg); + pos += 2 + 4 * pos[1]; + } + else if (*pos == AMLOP_DUALNAMEPREFIX) { + fn(node, 2, pos+1, arg); + pos += 9; + } + else if (*pos == '_' || (*pos >= 'A' && *pos <= 'Z')) { + fn(node, 1, pos, arg); + pos += 4; + } + else { + printf("Invalid name!!!\n"); + } + if (rv && *rv == NULL) { + *rv = aml_allocvalue(AML_OBJTYPE_NAMEREF, 0, rpos); + } + return pos; +} + +/* + * Conversion routines + */ +int64_t +aml_hextoint(const char *str) +{ + int64_t v = 0; + char c; + + while (*str) { + if (*str >= '0' && *str <= '9') { + c = *(str++) - '0'; + } + else if (*str >= 'a' && *str <= 'f') { + c = *(str++) - 'a' + 10; + } + else if (*str >= 'A' && *str <= 'F') { + c = *(str++) - 'A' + 10; + } + else { + break; + } + v = (v << 4) + c; + } + return v; + +} + +void +aml_xconvert(struct aml_value *a, struct aml_value **b, int ctype, int mode) +{ + struct aml_value *c = NULL; + + /* Object is already this type */ + if (a->type == ctype) { + aml_xaddref(a, "XConvert"); + *b = a; + return; + } + switch (ctype) { + case AML_OBJTYPE_BUFFER: + dnprintf(10,"convert to buffer\n"); + switch (a->type) { + case AML_OBJTYPE_INTEGER: + c = aml_allocvalue(AML_OBJTYPE_BUFFER, a->length, + &a->v_integer); + break; + case AML_OBJTYPE_STRING: + c = aml_allocvalue(AML_OBJTYPE_BUFFER, a->length, + a->v_string); + break; + } + break; + case AML_OBJTYPE_INTEGER: + dnprintf(10,"convert to integer : %x\n", a->type); + switch (a->type) { + case AML_OBJTYPE_BUFFER: + c = aml_allocvalue(AML_OBJTYPE_INTEGER, 0, NULL); + memcpy(&c->v_integer, a->v_buffer, + min(a->length, c->length)); + break; + case AML_OBJTYPE_STRING: + c = aml_allocvalue(AML_OBJTYPE_INTEGER, 0, NULL); + c->v_integer = aml_hextoint(a->v_string); + break; + case AML_OBJTYPE_UNINITIALIZED: + c = aml_allocvalue(AML_OBJTYPE_INTEGER, 0, NULL); + break; + } + break; + case AML_OBJTYPE_STRING: + dnprintf(10,"convert to string\n"); + switch (a->type) { + case AML_OBJTYPE_INTEGER: + c = aml_allocvalue(AML_OBJTYPE_STRING, 20, NULL); + snprintf(c->v_string, c->length, (mode == 'x') ? + "0x%llx" : "%lld", a->v_integer); + break; + case AML_OBJTYPE_BUFFER: + c = aml_allocvalue(AML_OBJTYPE_STRING, a->length, + a->v_buffer); + break; + } + break; + } + if (c == NULL) { + aml_showvalue(a, 0); + aml_die("Could not convert!!!\n"); + } + *b = c; +} + +int +aml_xcompare(struct aml_value *a1, struct aml_value *a2, int opcode) +{ + int rc = 0; + + /* Convert A2 to type of A1 */ + aml_xconvert(a2, &a2, a1->type, 0); + if (a1->type == AML_OBJTYPE_INTEGER) { + rc = aml_evalexpr(a1->v_integer, a2->v_integer, opcode); + } + else { + /* Perform String/Buffer comparison */ + rc = memcmp(a1->v_buffer, a2->v_buffer, + min(a1->length, a2->length)); + if (rc == 0) { + /* If buffers match, which one is longer */ + rc = a1->length - a2->length; + } + /* Perform comparison against zero */ + rc = aml_evalexpr(rc, 0, opcode); + } + /* Either deletes temp buffer, or decrease refcnt on original A2 */ + aml_xdelref(&a2, "xcompare"); + return rc; +} + +/* Concatenate two objects, returning pointer to new object */ +void +aml_xconcat(struct aml_value *a1, struct aml_value *a2, struct aml_value **res) +{ + struct aml_value *c; + + /* Convert arg2 to type of arg1 */ + aml_xconvert(a2, &a2, a1->type, 0); + switch (a1->type) { + case AML_OBJTYPE_INTEGER: + c = aml_allocvalue(AML_OBJTYPE_BUFFER, + a1->length + a2->length, NULL); + memcpy(c->v_buffer, &a1->v_integer, a1->length); + memcpy(c->v_buffer+a1->length, &a2->v_integer, a2->length); + break; + case AML_OBJTYPE_BUFFER: + c = aml_allocvalue(AML_OBJTYPE_BUFFER, + a1->length + a2->length, NULL); + memcpy(c->v_buffer, a1->v_buffer, a1->length); + memcpy(c->v_buffer+a1->length, a2->v_buffer, a2->length); + break; + case AML_OBJTYPE_STRING: + c = aml_allocvalue(AML_OBJTYPE_STRING, + a1->length + a2->length, NULL); + memcpy(c->v_string, a1->v_string, a1->length); + memcpy(c->v_string+a1->length, a2->v_string, a2->length); + break; + default: + aml_die("concat type mismatch %d != %d\n", a1->type, a2->type); + break; + } + /* Either deletes temp buffer, or decrease refcnt on original A2 */ + aml_xdelref(&a2, "xconcat"); + *res = c; +} + +/* Calculate length of Resource Template */ +int +aml_ccrlen(union acpi_resource *rs, void *arg) +{ + int *plen = arg; + + *plen += AML_CRSLEN(rs); + return 0; +} + +/* Concatenate resource templates, returning pointer to new object */ +void +aml_xconcatres(struct aml_value *a1, struct aml_value *a2, struct aml_value **res) +{ + struct aml_value *c; + int l1 = 0, l2 = 0; + + if (a1->type != AML_OBJTYPE_BUFFER || a2->type != AML_OBJTYPE_BUFFER) { + aml_die("concatres: not buffers\n"); + } + + /* Walk a1, a2, get length minus end tags, concatenate buffers, add end tag */ + aml_parse_resource(a1->length, a1->v_buffer, aml_ccrlen, &l1); + aml_parse_resource(a2->length, a2->v_buffer, aml_ccrlen, &l2); + + /* Concatenate buffers, add end tag */ + c = aml_allocvalue(AML_OBJTYPE_BUFFER, l1+l2+2, NULL); + memcpy(c->v_buffer, a1->v_buffer, l1); + memcpy(c->v_buffer+l1, a2->v_buffer, l2); + c->v_buffer[l1+l2+0] = 0x79; + c->v_buffer[l1+l2+1] = 0x00; + + *res = c; +} + +/* Extract substring from string or buffer */ +void +aml_xmid(struct aml_value *src, int index, int length, struct aml_value **res) +{ + int idx; + + for (idx=index; idx<index+length; idx++) { + if (idx >= src->length) + break; + if (src->v_buffer[idx] == 0) + break; + } + aml_die("mid\n"); +} + +/* + * Field I/O utility functions + */ +void aml_xresolve(struct aml_scope *, struct aml_value *); +void *aml_xgetptr(struct aml_value *, int); +void aml_xgasio(int, uint64_t, int, void *, int, int, const char *); +void aml_xfldio(struct aml_scope *, struct aml_value *, + struct aml_value *, int); +void aml_xcreatefield(struct aml_value *, int, struct aml_value *, int, int, + struct aml_value *, int); +void aml_xparsefieldlist(struct aml_scope *, int, int, + struct aml_value *, struct aml_value *, int); +int aml_evalhid(struct aml_node *, struct aml_value *); + +#define GAS_PCI_CFG_SPACE_UNEVAL 0xCC + +int +aml_evalhid(struct aml_node *node, struct aml_value *val) +{ + if (aml_evalname(dsdt_softc, node, "_HID", 0, NULL, val)) + return (-1); + + /* Integer _HID: convert to EISA ID */ + if (val->type == AML_OBJTYPE_INTEGER) + _aml_setvalue(val, AML_OBJTYPE_STRING, -1, aml_eisaid(val->v_integer)); + return (0); +} + +int +aml_xgetpci(struct aml_node *node, int64_t *base) +{ + struct aml_node *pci_root; + struct aml_value hid; + int64_t v; + + *base = 0; + dnprintf(10,"RESOLVE PCI: %s\n", aml_nodename(node)); + for (pci_root=node->parent; pci_root; pci_root=pci_root->parent) { + /* PCI Root object will have _HID value */ + if (aml_evalhid(pci_root, &hid) == 0) { + aml_freevalue(&hid); + break; + } + } + if (!aml_evalinteger(NULL, node->parent, "_ADR", 0, NULL, &v)) + *base += (v << 16L); + if (!aml_evalinteger(NULL, pci_root, "_BBN", 0, NULL, &v)) + *base += (v << 48L); + return 0; +} + +void +aml_xresolve(struct aml_scope *scope, struct aml_value *val) +{ + int64_t base; + + if (val->type != AML_OBJTYPE_OPREGION || val->v_opregion.flag) + return; + if (val->v_opregion.iospace != GAS_PCI_CFG_SPACE) + return; + + /* Evaluate PCI Address */ + aml_xgetpci(val->node, &base); + val->v_opregion.iobase += base; + val->v_opregion.flag = 1; +} + +/* Perform IO to address space + * type = GAS_XXXX + * base = base address + * rlen = length in bytes to read/write + * buf = buffer + * mode = ACPI_IOREAD/ACPI_IOWRITE + * sz = access_size (bits) + */ +void +aml_xgasio(int type, uint64_t base, int rlen, void *buf, int mode, int sz, + const char *lbl) +{ + sz >>= 3; + acpi_gasio(dsdt_softc, mode, type, base, sz, rlen, buf); +#ifdef ACPI_DEBUG + { + int idx; + printf("%sio: [%s] ty:%x bs=%.8llx sz=%.4x rlen=%.4x ", + mode == ACPI_IOREAD ? "rd" : "wr", lbl, + type, base, sz, rlen); + for (idx=0; idx<rlen; idx++) { + printf("%.2x ", ((uint8_t *)buf)[idx]); + } + } + printf("\n"); +#endif +} + +void * +aml_xgetptr(struct aml_value *tmp, int blen) +{ + if (blen > aml_intlen) { + _aml_setvalue(tmp, AML_OBJTYPE_BUFFER, aml_bytelen(blen), 0); + return tmp->v_buffer; + } + _aml_setvalue(tmp, AML_OBJTYPE_INTEGER, 0, NULL); + return &tmp->v_integer; +} + +/* Read and Write BufferField and FieldUnit objects */ +void +aml_xfldio(struct aml_scope *scope, struct aml_value *fld, + struct aml_value *buf, int mode) +{ + struct aml_value tmp, *data; + int bpos, blen, preserve=1, mask, aligned, rlen, slen; + void *sptr, *dptr; + + switch (AML_FIELD_ACCESS(fld->v_field.flags)) { + case AML_FIELD_WORDACC: + mask=15; + break; + case AML_FIELD_DWORDACC: + mask=31; + break; + case AML_FIELD_QWORDACC: + mask=63; + break; + default: + mask=7; + break; + } + data = fld->v_field.ref1; + bpos = fld->v_field.bitpos; + blen = fld->v_field.bitlen; + rlen = aml_bytelen((bpos & 7) + blen); + aligned = !((bpos|blen)&mask); + preserve = AML_FIELD_UPDATE(fld->v_field.flags); + + dnprintf(30,"\nquick: %s: [%s] %.4x-%.4x msk=%.2x algn=%d prsrv=%d [%s]\n", + mode == ACPI_IOREAD ? "read from" : "write to", + aml_nodename(fld->node), + bpos, blen, mask, aligned, preserve, + aml_mnem(fld->v_field.type, 0)); + + memset(&tmp, 0, sizeof(tmp)); + if (fld->v_field.ref2 != NULL) { + /* Write index */ + dnprintf(30,"writing index fldio: %d\n", fld->v_field.ref3); + _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, + fld->v_field.ref3, NULL); + aml_xfldio(scope, fld->v_field.ref2, &tmp, ACPI_IOWRITE); + } + + /* Get pointer to Data Object */ + switch (data->type) { + case AML_OBJTYPE_BUFFER: + dptr = data->v_buffer; + break; + case AML_OBJTYPE_STRING: + dptr = data->v_string; + break; + case AML_OBJTYPE_INTEGER: + dptr = &data->v_integer; + break; + case AML_OBJTYPE_OPREGION: + /* Depending on size, allocate buffer or integer */ + aml_xresolve(scope, data); + dptr = aml_xgetptr(&tmp, rlen << 3); + break; + case AML_OBJTYPE_FIELDUNIT: + case AML_OBJTYPE_BUFFERFIELD: + /* Set to integer for now.. */ + _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, 0x0, NULL); + dptr = &tmp.v_integer; + break; + default: + aml_die("jk XREAD/WRITE: unknown type: %x\n", data->type); + break; + } + + aml_lockfield(scope, fld); + if (mode == ACPI_IOREAD) { + sptr = aml_xgetptr(buf, blen); + switch (data->type) { + case AML_OBJTYPE_OPREGION: + /* Do GASIO into temp buffer, bitcopy into result */ + aml_xgasio(data->v_opregion.iospace, + data->v_opregion.iobase+(bpos>>3), + rlen, dptr, ACPI_IOREAD, mask+1, + aml_nodename(fld->node)); + aml_bufcpy(sptr, 0, dptr, bpos & 7, blen); + break; + case AML_OBJTYPE_FIELDUNIT: + case AML_OBJTYPE_BUFFERFIELD: + /* Do FieldIO into temp buffer, bitcopy into result */ + aml_xfldio(scope, data, &tmp, ACPI_IOREAD); + aml_bufcpy(sptr, 0, dptr, bpos & 7, blen); + break; + default: + /* bitcopy into result */ + aml_bufcpy(sptr, 0, dptr, bpos, blen); + break; + } + } + else { + switch (buf->type) { + case AML_OBJTYPE_INTEGER: + slen = aml_intlen; + break; + default: + slen = buf->length<<3; + break; + } + if (slen < blen) { + aml_showvalue(fld, 0); + aml_showvalue(buf, 0); + aml_die("BIG SOURCE %d %d %s", buf->length, blen>>3, ""); + } + if (buf->type != AML_OBJTYPE_INTEGER) + aml_die("writefield: not integer\n"); + sptr = &buf->v_integer; + + switch (data->type) { + case AML_OBJTYPE_OPREGION: + if (!aligned && preserve == AML_FIELD_PRESERVE) { + /* Preserve contents: read current value */ + aml_xgasio(data->v_opregion.iospace, + data->v_opregion.iobase+(bpos>>3), + rlen, dptr, ACPI_IOREAD, mask+1, + aml_nodename(fld->node)); + } + /* Bitcopy data into temp buffer, write GAS */ + if (preserve == AML_FIELD_WRITEASONES) + memset(dptr, 0xFF, tmp.length); + aml_bufcpy(dptr, bpos & 7, sptr, 0, blen); + aml_xgasio(data->v_opregion.iospace, + data->v_opregion.iobase+(bpos>>3), + rlen, dptr, ACPI_IOWRITE, mask+1, + aml_nodename(fld->node)); + break; + case AML_OBJTYPE_FIELDUNIT: + case AML_OBJTYPE_BUFFERFIELD: + if (!aligned && preserve == AML_FIELD_PRESERVE) { + /* Preserve contents: read current value */ + aml_xfldio(scope, data, &tmp, ACPI_IOREAD); + if (tmp.type != AML_OBJTYPE_INTEGER) + dptr = tmp.v_buffer; + } + else { + dptr = aml_xgetptr(&tmp, rlen<<3); + } + /* Bitcopy data into temp buffer, write field */ + if (preserve == AML_FIELD_WRITEASONES) + memset(dptr, 0xFF, tmp.length); + aml_bufcpy(dptr, bpos & 7, sptr, 0, blen); + aml_xfldio(scope, data, &tmp, ACPI_IOWRITE); + break; + default: + if (blen > aml_intlen) { + aml_die("jk Big Buffer other!\n"); + } + aml_bufcpy(dptr, bpos, sptr, 0, blen); + break; + } + } + aml_freevalue(&tmp); + aml_unlockfield(scope, fld); +} + +/* Create Field Object data index + * AMLOP_FIELD n:OpRegion NULL + * AMLOP_INDEXFIELD n:Field n:Field + * AMLOP_BANKFIELD n:OpRegion n:Field + * AMLOP_CREATEFIELD t:Buffer NULL + * AMLOP_CREATEBITFIELD t:Buffer NULL + * AMLOP_CREATEBYTEFIELD t:Buffer NULL + * AMLOP_CREATEWORDFIELD t:Buffer NULL + * AMLOP_CREATEDWORDFIELD t:Buffer NULL + * AMLOP_CREATEQWORDFIELD t:Buffer NULL + * AMLOP_INDEX t:Buffer NULL + */ +void +aml_xcreatefield(struct aml_value *field, int opcode, + struct aml_value *data, int bpos, int blen, + struct aml_value *index, int indexval) +{ + dnprintf(10, "## %s(%s): %s %.4x-%.4x\n", + aml_mnem(opcode, 0), + blen > aml_intlen ? "BUF" : "INT", + aml_nodename(field->node), bpos, blen); + if (index) { + dnprintf(10, " index:%s:%.2x\n", aml_nodename(index->node), + indexval); + } + dnprintf(10, " data:%s\n", aml_nodename(data->node)); + field->type = (opcode == AMLOP_FIELD || + opcode == AMLOP_INDEXFIELD || + opcode == AMLOP_BANKFIELD) ? + AML_OBJTYPE_FIELDUNIT : + AML_OBJTYPE_BUFFERFIELD; + field->v_field.type = opcode; + field->v_field.bitpos = bpos; + field->v_field.bitlen = blen; + field->v_field.ref3 = indexval; + field->v_field.ref2 = index; + field->v_field.ref1 = data; + + /* Increase reference count */ + aml_xaddref(data, "Field.Data"); + aml_xaddref(index, "Field.Index"); +} + +/* Parse Field/IndexField/BankField scope */ +void +aml_xparsefieldlist(struct aml_scope *mscope, int opcode, int flags, + struct aml_value *data, struct aml_value *index, int indexval) +{ + struct aml_value *rv; + int bpos, blen; + + if (mscope == NULL) + return; + bpos = 0; + while (mscope->pos < mscope->end) { + switch (*mscope->pos) { + case 0x00: // reserved, length + mscope->pos++; + blen = aml_parselength(mscope); + break; + case 0x01: // flags + mscope->pos += 3; + blen = 0; + break; + default: // 4-byte name, length + mscope->pos = aml_xparsename(mscope->pos, mscope->node, + ns_xcreate, &rv); + blen = aml_parselength(mscope); + rv->v_field.flags = flags; + switch (opcode) { + case AMLOP_FIELD: + /* nbF */ + aml_xcreatefield(rv, opcode, data, bpos, + blen, NULL, 0); + break; + case AMLOP_INDEXFIELD: + /* nnbF */ + aml_xcreatefield(rv, opcode, data, bpos & 7, + blen, index, bpos>>3); + break; + case AMLOP_BANKFIELD: + /* nnibF */ + aml_xcreatefield(rv, opcode, data, bpos, + blen, index, indexval); + break; + } + break; + } + bpos += blen; + } +} + +/* + * Mutex/Event utility functions + */ +int acpi_xmutex_acquire(struct aml_scope *, struct aml_value *, int); +void acpi_xmutex_release(struct aml_scope *, struct aml_value *); +int acpi_xevent_wait(struct aml_scope *, struct aml_value *, int); +void acpi_xevent_signal(struct aml_scope *, struct aml_value *); +void acpi_xevent_reset(struct aml_scope *, struct aml_value *); + +int +acpi_xmutex_acquire(struct aml_scope *scope, struct aml_value *mtx, + int timeout) +{ + int err; + + if (mtx->v_mtx.owner == NULL || scope == mtx->v_mtx.owner) { + /* We are now the owner */ + mtx->v_mtx.owner = scope; + if (mtx == aml_global_lock) { + dnprintf(10,"LOCKING GLOBAL\n"); + err = acpi_acquire_global_lock(&dsdt_softc->sc_facs->global_lock); + } + dnprintf(5,"%s acquires mutex %s\n", scope->node->name, + mtx->node->name); + return 0; + } + else if (timeout == 0) { + return 1; + } + /* Wait for mutex */ + return 0; +} + +void +acpi_xmutex_release(struct aml_scope *scope, struct aml_value *mtx) +{ + int err; + + if (mtx == aml_global_lock) { + dnprintf(10,"UNLOCKING GLOBAL\n"); + err=acpi_release_global_lock(&dsdt_softc->sc_facs->global_lock); + } + dnprintf(5, "%s releases mutex %s\n", scope->node->name, + mtx->node->name); + mtx->v_mtx.owner = NULL; + /* Wakeup waiters */ +} + +int +acpi_xevent_wait(struct aml_scope *scope, struct aml_value *evt, int timeout) +{ + if (evt->v_evt.state == 1) { + /* Object is signaled */ + return 0; + } + else if (timeout == 0) { + /* Zero timeout */ + return 1; + } + /* Wait for timeout or signal */ + return 0; +} + +void +acpi_xevent_signal(struct aml_scope *scope, struct aml_value *evt) +{ + evt->v_evt.state = 1; + /* Wakeup waiters */ +} + +void +acpi_xevent_reset(struct aml_scope *scope, struct aml_value *evt) +{ + evt->v_evt.state = 0; +} + +/* Store result value into an object */ +void +aml_xstore(struct aml_scope *scope, struct aml_value *lhs , int64_t ival, + struct aml_value *rhs) +{ + struct aml_value tmp; + int mlen; + + /* Already set */ + if (lhs == rhs || lhs == NULL || lhs->type == AML_OBJTYPE_NOTARGET) { + return; + } + memset(&tmp, 0, sizeof(tmp)); + tmp.refcnt=99; + if (rhs == NULL) { + rhs = _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, ival, NULL); + } + if (rhs->type == AML_OBJTYPE_BUFFERFIELD || + rhs->type == AML_OBJTYPE_FIELDUNIT) { + aml_xfldio(scope, rhs, &tmp, ACPI_IOREAD); + rhs = &tmp; + } + while (lhs->type == AML_OBJTYPE_OBJREF) { + lhs = lhs->v_objref.ref; + } + switch (lhs->type) { + case AML_OBJTYPE_UNINITIALIZED: + aml_copyvalue(lhs, rhs); + break; + case AML_OBJTYPE_BUFFERFIELD: + case AML_OBJTYPE_FIELDUNIT: + aml_xfldio(scope, lhs, rhs, ACPI_IOWRITE); + break; + case AML_OBJTYPE_DEBUGOBJ: + break; + case AML_OBJTYPE_INTEGER: + aml_xconvert(rhs, &rhs, lhs->type, 0); + lhs->v_integer = rhs->v_integer; + aml_xdelref(&rhs, "store.int"); + break; + case AML_OBJTYPE_BUFFER: + case AML_OBJTYPE_STRING: + aml_xconvert(rhs, &rhs, lhs->type, 0); + if (lhs->length < rhs->length) { + dnprintf(10,"Overrun! %d,%d\n", lhs->length, rhs->length); + aml_freevalue(lhs); + _aml_setvalue(lhs, rhs->type, rhs->length, NULL); + } + mlen = min(lhs->length, rhs->length); + memset(lhs->v_buffer, 0x00, lhs->length); + memcpy(lhs->v_buffer, rhs->v_buffer, mlen); + aml_xdelref(&rhs, "store.bufstr"); + break; + case AML_OBJTYPE_PACKAGE: + /* Convert to LHS type, copy into LHS */ + if (rhs->type != AML_OBJTYPE_PACKAGE) { + aml_die("Copy non-package into package?"); + } + aml_freevalue(lhs); + aml_copyvalue(lhs, rhs); + break; + default: + aml_die("Store to default type! %x\n", lhs->type); + break; + } + aml_freevalue(&tmp); +} + +/* Disassembler routines */ +void aml_disprintf(void *arg, const char *fmt, ...); + +void +aml_disprintf(void *arg, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +void +aml_disasm(struct aml_scope *scope, int lvl, + void (*dbprintf)(void *, const char *, ...), + void *arg) +{ + int pc, opcode; + struct aml_opcode *htab; + uint64_t ival; + struct aml_value *rv, tmp; + uint8_t *end; + struct aml_scope *ms; + char *ch; + char mch[64]; + + if (dbprintf == NULL) + dbprintf = aml_disprintf; + + pc = aml_pc(scope->pos); + opcode = aml_parseopcode(scope); + htab = aml_findopcode(opcode); + + /* Display address + indent */ + if (lvl <= 0x7FFF) { + dbprintf(arg, "%.4x ", pc); + for (pc=0; pc<lvl; pc++) { + dbprintf(arg, " "); + } + } + ch = NULL; + switch (opcode) { + case AMLOP_NAMECHAR: + scope->pos = aml_xparsename(scope->pos, scope->node, + ns_xsearch, &rv); + if (rv->type == AML_OBJTYPE_NAMEREF) { + ch = "@@@"; + aml_xdelref(&rv, "disasm"); + break; + } + /* if this is a method, get arguments */ + strlcpy(mch, aml_nodename(rv->node), sizeof(mch)); + if (rv->type == AML_OBJTYPE_METHOD) { + strlcat(mch, "(", sizeof(mch)); + for (ival=0; ival<AML_METHOD_ARGCOUNT(rv->v_method.flags); ival++) { + strlcat(mch, ival ? ", %z" : "%z", + sizeof(mch)); + } + strlcat(mch, ")", sizeof(mch)); + } + ch = mch; + break; + + case AMLOP_ZERO: + case AMLOP_ONE: + case AMLOP_ONES: + case AMLOP_LOCAL0: + case AMLOP_LOCAL1: + case AMLOP_LOCAL2: + case AMLOP_LOCAL3: + case AMLOP_LOCAL4: + case AMLOP_LOCAL5: + case AMLOP_LOCAL6: + case AMLOP_LOCAL7: + case AMLOP_ARG0: + case AMLOP_ARG1: + case AMLOP_ARG2: + case AMLOP_ARG3: + case AMLOP_ARG4: + case AMLOP_ARG5: + case AMLOP_ARG6: + case AMLOP_NOP: + case AMLOP_REVISION: + case AMLOP_DEBUG: + case AMLOP_CONTINUE: + case AMLOP_BREAKPOINT: + case AMLOP_BREAK: + ch="%m"; + break; + case AMLOP_BYTEPREFIX: + ch="%b"; + break; + case AMLOP_WORDPREFIX: + ch="%w"; + break; + case AMLOP_DWORDPREFIX: + ch="%d"; + break; + case AMLOP_QWORDPREFIX: + ch="%q"; + break; + case AMLOP_STRINGPREFIX: + ch="%a"; + break; + + case AMLOP_INCREMENT: + case AMLOP_DECREMENT: + case AMLOP_LNOT: + case AMLOP_SIZEOF: + case AMLOP_DEREFOF: + case AMLOP_REFOF: + case AMLOP_OBJECTTYPE: + case AMLOP_UNLOAD: + case AMLOP_RELEASE: + case AMLOP_SIGNAL: + case AMLOP_RESET: + case AMLOP_STALL: + case AMLOP_SLEEP: + case AMLOP_RETURN: + ch="%m(%n)"; + break; + case AMLOP_OR: + case AMLOP_ADD: + case AMLOP_AND: + case AMLOP_NAND: + case AMLOP_XOR: + case AMLOP_SHL: + case AMLOP_SHR: + case AMLOP_NOR: + case AMLOP_MOD: + case AMLOP_SUBTRACT: + case AMLOP_MULTIPLY: + case AMLOP_INDEX: + case AMLOP_CONCAT: + case AMLOP_CONCATRES: + case AMLOP_TOSTRING: + ch="%m(%n, %n, %n)"; + break; + case AMLOP_CREATEBYTEFIELD: + case AMLOP_CREATEWORDFIELD: + case AMLOP_CREATEDWORDFIELD: + case AMLOP_CREATEQWORDFIELD: + case AMLOP_CREATEBITFIELD: + ch="%m(%n, %n, %N)"; + break; + case AMLOP_CREATEFIELD: + ch="%m(%n, %n, %n, %N)"; + break; + case AMLOP_DIVIDE: + case AMLOP_MID: + ch="%m(%n, %n, %n, %n)"; + break; + case AMLOP_LAND: + case AMLOP_LOR: + case AMLOP_LNOTEQUAL: + case AMLOP_LLESSEQUAL: + case AMLOP_LLESS: + case AMLOP_LEQUAL: + case AMLOP_LGREATEREQUAL: + case AMLOP_LGREATER: + case AMLOP_NOT: + case AMLOP_FINDSETLEFTBIT: + case AMLOP_FINDSETRIGHTBIT: + case AMLOP_TOINTEGER: + case AMLOP_TOBUFFER: + case AMLOP_TOHEXSTRING: + case AMLOP_TODECSTRING: + case AMLOP_FROMBCD: + case AMLOP_TOBCD: + case AMLOP_WAIT: + case AMLOP_LOAD: + case AMLOP_STORE: + case AMLOP_NOTIFY: + case AMLOP_COPYOBJECT: + ch="%m(%n, %n)"; + break; + case AMLOP_ACQUIRE: + ch = "%m(%n, %w)"; + break; + case AMLOP_CONDREFOF: + ch="%m(%R, %n)"; + break; + case AMLOP_ALIAS: + ch="%m(%n, %N)"; + break; + case AMLOP_NAME: + ch="%m(%N, %n)"; + break; + case AMLOP_EVENT: + ch="%m(%N)"; + break; + case AMLOP_MUTEX: + ch = "%m(%N, %b)"; + break; + case AMLOP_OPREGION: + ch = "%m(%N, %b, %n, %n)"; + break; + case AMLOP_DATAREGION: + ch="%m(%N, %n, %n, %n)"; + break; + case AMLOP_FATAL: + ch = "%m(%b, %d, %n)"; + break; + case AMLOP_IF: + case AMLOP_WHILE: + case AMLOP_SCOPE: + case AMLOP_THERMALZONE: + case AMLOP_VARPACKAGE: + end = aml_parseend(scope); + ch = "%m(%n) {\n%T}"; + break; + case AMLOP_DEVICE: + end = aml_parseend(scope); + ch = "%m(%N) {\n%T}"; + break; + case AMLOP_POWERRSRC: + end = aml_parseend(scope); + ch = "%m(%N, %b, %w) {\n%T}"; + break; + case AMLOP_PROCESSOR: + end = aml_parseend(scope); + ch = "%m(%N, %b, %d, %b) {\n%T}"; + break; + case AMLOP_METHOD: + end = aml_parseend(scope); + ch = "%m(%N, %b) {\n%T}"; + break; + case AMLOP_PACKAGE: + end = aml_parseend(scope); + ch = "%m(%b) {\n%T}"; + break; + case AMLOP_ELSE: + end = aml_parseend(scope); + ch = "%m {\n%T}"; + break; + case AMLOP_BUFFER: + end = aml_parseend(scope); + ch = "%m(%n) { %B }"; + break; + case AMLOP_INDEXFIELD: + end = aml_parseend(scope); + ch = "%m(%n, %n, %b) {\n%F}"; + break; + case AMLOP_BANKFIELD: + end = aml_parseend(scope); + ch = "%m(%n, %n, %n, %b) {\n%F}"; + break; + case AMLOP_FIELD: + end = aml_parseend(scope); + ch = "%m(%n, %b) {\n%F}"; + break; + case AMLOP_MATCH: + ch = "%m(%n, %b, %n, %b, %n, %n)"; + break; + case AMLOP_LOADTABLE: + ch = "%m(%n, %n, %n, %n, %n, %n)"; + break; + default: + aml_die("opcode = %x\n", opcode); + break; + } + + /* Parse printable buffer args */ + while (ch && *ch) { + char c; + + if (*ch != '%') { + dbprintf(arg,"%c", *(ch++)); + continue; + } + c = *(++ch); + switch (c) { + case 'b': + case 'w': + case 'd': + case 'q': + /* Parse simple object: don't allocate */ + aml_xparsesimple(scope, c, &tmp); + dbprintf(arg,"0x%llx", tmp.v_integer); + break; + case 'a': + dbprintf(arg, "\'%s\'", scope->pos); + scope->pos += strlen(scope->pos)+1; + break; + case 'N': + /* Create Name */ + rv = aml_xparsesimple(scope, c, NULL); + dbprintf(arg,aml_nodename(rv->node)); + break; + case 'm': + /* display mnemonic */ + dbprintf(arg,htab->mnem); + break; + case 'R': + /* Search name */ + scope->pos = aml_xparsename(scope->pos, scope->node, + ns_xdis, &rv); + break; + case 'z': + case 'n': + /* generic arg: recurse */ + aml_disasm(scope, lvl | 0x8000, dbprintf, arg); + break; + case 'B': + /* Buffer */ + scope->pos = end; + break; + case 'F': + /* Field List */ + tmp.v_buffer = scope->pos; + tmp.length = end - scope->pos; + + ms = aml_xpushscope(scope, &tmp, scope->node, 0); + while (ms && ms->pos < ms->end) { + if (*ms->pos == 0x00) { + ms->pos++; + aml_parselength(ms); + } + else if (*ms->pos == 0x01) { + ms->pos+=3; + } + else { + ms->pos = aml_xparsename(ms->pos, + ms->node, ns_xcreate, &rv); + aml_parselength(ms); + dbprintf(arg," %s\n", + aml_nodename(rv->node)); + } + } + aml_xpopscope(ms); + + /* Display address and closing bracket */ + dbprintf(arg,"%.4x ", aml_pc(scope->pos)); + for (pc=0; pc<(lvl & 0x7FFF); pc++) { + dbprintf(arg," "); + } + scope->pos = end; + break; + case 'T': + /* Scope: Termlist */ + tmp.v_buffer = scope->pos; + tmp.length = end - scope->pos; + + ms = aml_xpushscope(scope, &tmp, scope->node, 0); + while (ms && ms->pos < ms->end) { + aml_disasm(ms, (lvl + 1) & 0x7FFF, + dbprintf, arg); + } + aml_xpopscope(ms); + + /* Display address and closing bracket */ + dbprintf(arg,"%.4x ", aml_pc(scope->pos)); + for (pc=0; pc<(lvl & 0x7FFF); pc++) { + dbprintf(arg," "); + } + scope->pos = end; + break; + } + ch++; + } + if (lvl <= 0x7FFF) { + dbprintf(arg,"\n"); + } +} + +int aml_busy; + +/* Evaluate method or buffervalue objects */ +struct aml_value * +aml_xeval(struct aml_scope *scope, struct aml_value *my_ret, int ret_type, + int argc, struct aml_value *argv) +{ + struct aml_value *tmp = my_ret; + struct aml_scope *ms; + int idx; + + switch (tmp->type) { + case AML_OBJTYPE_METHOD: + dnprintf(10,"\n--== Eval Method [%s, %d args] to %c ==--\n", + aml_nodename(tmp->node), + AML_METHOD_ARGCOUNT(tmp->v_method.flags), + ret_type); + ms = aml_xpushscope(scope, tmp, tmp->node, AMLOP_METHOD); + ms->args = acpi_os_malloc(7 * sizeof(struct aml_value)); + + /* Parse method arguments */ + for (idx=0; idx<AML_METHOD_ARGCOUNT(tmp->v_method.flags); idx++) { + ms->args[idx].type = AML_OBJTYPE_OBJREF; + ms->args[idx].v_objref.type = AMLOP_ARG0 + idx; + if (argv) { + ms->args[idx].v_objref.ref = &argv[idx]; + argv[idx].refcnt = 99; + } + else { + ms->args[idx].v_objref.ref = + aml_xparse(scope, 't', "ARGX"); + } + } +#ifdef ACPI_DEBUG + aml_showstack(ms); +#endif + + /* Evaluate method scope */ + if (tmp->v_method.fneval != NULL) { + my_ret = tmp->v_method.fneval(ms, NULL); + } + else { + aml_xparse(ms, 'T', "METHEVAL"); + my_ret = ms->retv; + } + dnprintf(10,"\n--==Finished evaluating method: %s %c\n", + aml_nodename(tmp->node), ret_type); +#ifdef ACPI_DEBUG + aml_showvalue(my_ret, 0); + aml_showstack(ms); +#endif + aml_xpopscope(ms); + break; + case AML_OBJTYPE_BUFFERFIELD: + case AML_OBJTYPE_FIELDUNIT: + my_ret = aml_allocvalue(0,0,NULL); + dnprintf(20,"quick: Convert Bufferfield to %c 0x%x\n", + ret_type, my_ret); + aml_xfldio(scope, tmp, my_ret, ACPI_IOREAD); + break; + } + if (ret_type == 'i' && my_ret && my_ret->type != AML_OBJTYPE_INTEGER) { + aml_showvalue(my_ret, 8-100); + aml_die("Not Integer"); + } + return my_ret; +} + +/* + * The following opcodes produce return values + * TOSTRING -> Str + * TOHEXSTR -> Str + * TODECSTR -> Str + * STRINGPFX -> Str + * BUFFER -> Buf + * CONCATRES -> Buf + * TOBUFFER -> Buf + * MID -> Buf|Str + * CONCAT -> Buf|Str + * PACKAGE -> Pkg + * VARPACKAGE -> Pkg + * LOCALx -> Obj + * ARGx -> Obj + * NAMECHAR -> Obj + * REFOF -> ObjRef + * INDEX -> ObjRef + * DEREFOF -> DataRefObj + * COPYOBJECT -> DataRefObj + * STORE -> DataRefObj + + * ZERO -> Int + * ONE -> Int + * ONES -> Int + * REVISION -> Int + * B/W/D/Q -> Int + * OR -> Int + * AND -> Int + * ADD -> Int + * NAND -> Int + * XOR -> Int + * SHL -> Int + * SHR -> Int + * NOR -> Int + * MOD -> Int + * SUBTRACT -> Int + * MULTIPLY -> Int + * DIVIDE -> Int + * NOT -> Int + * TOBCD -> Int + * FROMBCD -> Int + * FSLEFTBIT -> Int + * FSRIGHTBIT -> Int + * INCREMENT -> Int + * DECREMENT -> Int + * TOINTEGER -> Int + * MATCH -> Int + * SIZEOF -> Int + * OBJECTTYPE -> Int + * TIMER -> Int + + * CONDREFOF -> Bool + * ACQUIRE -> Bool + * WAIT -> Bool + * LNOT -> Bool + * LAND -> Bool + * LOR -> Bool + * LLESS -> Bool + * LEQUAL -> Bool + * LGREATER -> Bool + * LNOTEQUAL -> Bool + * LLESSEQUAL -> Bool + * LGREATEREQ -> Bool + + * LOADTABLE -> DDB + * DEBUG -> Debug + + * The following opcodes do not generate a return value: + * NOP + * BREAKPOINT + * RELEASE + * RESET + * SIGNAL + * NAME + * ALIAS + * OPREGION + * DATAREGION + * EVENT + * MUTEX + * SCOPE + * DEVICE + * THERMALZONE + * POWERRSRC + * PROCESSOR + * METHOD + * CREATEFIELD + * CREATEBITFIELD + * CREATEBYTEFIELD + * CREATEWORDFIELD + * CREATEDWORDFIELD + * CREATEQWORDFIELD + * FIELD + * INDEXFIELD + * BANKFIELD + * STALL + * SLEEP + * NOTIFY + * FATAL + * LOAD + * UNLOAD + * IF + * ELSE + * WHILE + * BREAK + * CONTINUE + */ + +/* Parse a simple object from AML Bytestream */ +struct aml_value * +aml_xparsesimple(struct aml_scope *scope, char ch, struct aml_value *rv) +{ + if (ch == AML_ARG_CREATENAME) { + scope->pos = aml_xparsename(scope->pos, scope->node, + ns_xcreate, &rv); + return rv; + } + else if (ch == AML_ARG_SEARCHNAME) { + scope->pos = aml_xparsename(scope->pos, scope->node, + ns_xsearch, &rv); + return rv; + } + if (rv == NULL) + rv = aml_allocvalue(0,0,NULL); + switch (ch) { + case AML_ARG_REVISION: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, AML_REVISION, NULL); + break; + case AML_ARG_DEBUG: + _aml_setvalue(rv, AML_OBJTYPE_DEBUGOBJ, 0, NULL); + break; + case AML_ARG_BYTE: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, + aml_get8(scope->pos), NULL); + scope->pos += 1; + break; + case AML_ARG_WORD: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, + aml_get16(scope->pos), NULL); + scope->pos += 2; + break; + case AML_ARG_DWORD: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, + aml_get32(scope->pos), NULL); + scope->pos += 4; + break; + case AML_ARG_QWORD: + _aml_setvalue(rv, AML_OBJTYPE_INTEGER, + aml_get64(scope->pos), NULL); + scope->pos += 8; + break; + case AML_ARG_STRING: + _aml_setvalue(rv, AML_OBJTYPE_STRING, -1, scope->pos); + scope->pos += rv->length+1; + break; + } + return rv; +} + +/* + * Main Opcode Parser/Evaluator + * + * ret_type is expected type for return value + * 'o' = Data Object (Int/Str/Buf/Pkg/Name) + * 'i' = Integer + * 't' = TermArg (Int/Str/Buf/Pkg) + * 'r' = Target (NamedObj/Local/Arg/Null) + * 'S' = SuperName (NamedObj/Local/Arg) + * 'T' = TermList + */ +#define aml_debugger(x) + +struct aml_value * +aml_xparse(struct aml_scope *scope, int ret_type, const char *stype) +{ + int opcode, idx, pc, optype[8]; + struct aml_opcode *htab; + struct aml_value *opargs[8], *my_ret, *tmp, *cname; + struct aml_scope *mscope; + const char *ch; + int64_t ival; + + my_ret = NULL; + if (scope == NULL || scope->pos >= scope->end) { + return NULL; + } + start: + if (odp++ > 125) + panic("depth"); + + /* --== Stage 0: Get Opcode ==-- */ + pc = aml_pc(scope->pos); + aml_debugger(scope); + + opcode = aml_parseopcode(scope); + delay(amlop_delay); + + htab = aml_findopcode(opcode); + if (htab == NULL) { + /* No opcode handler */ + aml_die("Unknown opcode: %.4x @ %.4x", opcode, + aml_pc(scope->pos - opsize(opcode))); + } + dnprintf(18,"%.4x %s\n", pc, aml_mnem(opcode, scope->pos)); + + /* --== Stage 1: Process opcode arguments ==-- */ + cname = NULL; + memset(opargs, 0, sizeof(opargs)); + memset(optype, 0, sizeof(optype)); + idx = 0; + for (ch = htab->args; *ch; ch++) { + struct aml_value *rv; + uint8_t *end; + + rv = NULL; + switch (*ch) { + case AML_ARG_OBJLEN: + end = aml_parseend(scope); + break; + case AML_ARG_IFELSE: + /* Special Case: IF-ELSE:piTbpT or IF:piT */ + ch = (*end == AMLOP_ELSE && end < scope->end) ? + "-TbpT" : "-T"; + break; + + /* Complex arguments */ + case 's': + case 'S': + case AML_ARG_TARGET: + case AML_ARG_TERMOBJ: + case AML_ARG_INTEGER: + if (*ch == 'r' && *scope->pos == AMLOP_ZERO) { + /* Special case: NULL Target */ + rv = aml_allocvalue(AML_OBJTYPE_NOTARGET, 0, NULL); + scope->pos++; + } + else { + rv = aml_xparse(scope, *ch, htab->mnem); + if (rv == NULL) + aml_die("NULL RESULT"); + } + break; + + /* Simple arguments */ + case AML_ARG_WHILE: + case AML_ARG_BUFFER: + case AML_ARG_METHOD: + case AML_ARG_FIELDLIST: + case AML_ARG_TERMOBJLIST: + rv = aml_allocvalue(AML_OBJTYPE_SCOPE, 0, NULL); + rv->v_buffer = scope->pos; + rv->length = end - scope->pos; + scope->pos = end; + break; + case AML_ARG_CONST: + rv = aml_allocvalue(AML_OBJTYPE_INTEGER, + (char)opcode, NULL); + break; + case AML_ARG_CREATENAME: + rv = aml_xparsesimple(scope, *ch, NULL); + cname = rv; + if (cname->type != 0 && opcode != AMLOP_SCOPE) + dnprintf(10, "%s value already exists %s\n", + aml_nodename(cname->node), + htab->mnem); + break; + case AML_ARG_SEARCHNAME: + rv = aml_xparsesimple(scope, *ch, NULL); + if (rv->type != AML_OBJTYPE_NAMEREF) + aml_xaddref(rv, "Search Name"); + break; + case AML_ARG_BYTE: + case AML_ARG_WORD: + case AML_ARG_DWORD: + case AML_ARG_QWORD: + case AML_ARG_DEBUG: + case AML_ARG_STRING: + case AML_ARG_REVISION: + rv = aml_xparsesimple(scope, *ch, NULL); + break; + case AML_ARG_STKLOCAL: + mscope = aml_xfindscope(scope, AMLOP_METHOD, 0); + if (mscope->locals == NULL) { + mscope->locals = acpi_os_malloc(8 * sizeof(struct aml_value)); + } + rv = &mscope->locals[opcode - AMLOP_LOCAL0]; + if (rv->refcnt == 0) { + rv->refcnt++; + } + rv->stack = opcode; + rv->node = mscope->node; + break; + case AML_ARG_STKARG: + mscope = aml_xfindscope(scope, AMLOP_METHOD, 0); + rv = mscope->args[opcode - AMLOP_ARG0].v_objref.ref; + break; + default: + aml_die("Unknown arg type: %c\n", *ch); + break; + } + if (rv != NULL) { + optype[idx] = *ch; + opargs[idx++] = rv; + } + } + + /* Check for Op(Src1,Src2,Src1) type operations */ + for (idx=0; optype[idx]; idx++) { + int jdx; + for (jdx=idx+1; optype[jdx]; jdx++) { + if (opargs[idx] == opargs[jdx]) { + dnprintf(12,"STORE SAME %s %d,%d -> [%s] ", + htab->mnem, idx, jdx, + aml_nodename(scope->node)); + } + } + } + + /* --== Stage 2: Process opcode ==-- */ + ival = 0; + my_ret = NULL; + mscope = NULL; + switch (opcode) { + case AMLOP_NOP: + case AMLOP_BREAKPOINT: + break; + case AMLOP_LOCAL0: + case AMLOP_LOCAL1: + case AMLOP_LOCAL2: + case AMLOP_LOCAL3: + case AMLOP_LOCAL4: + case AMLOP_LOCAL5: + case AMLOP_LOCAL6: + case AMLOP_LOCAL7: + my_ret = opargs[0]; + aml_xaddref(my_ret, htab->mnem); + if (ret_type == AML_ARG_INTEGER) { + /* Return copy of integer value */ + aml_xconvert(my_ret, &my_ret, AML_OBJTYPE_INTEGER, 0); + ival = my_ret->v_integer; + aml_xdelref(&my_ret, "local.int"); + my_ret = NULL; + } + else if (ret_type == AML_ARG_TARGET) { + /* Store to LocalX: free object */ + aml_freevalue(my_ret); + } + break; + case AMLOP_ARG0: + case AMLOP_ARG1: + case AMLOP_ARG2: + case AMLOP_ARG3: + case AMLOP_ARG4: + case AMLOP_ARG5: + case AMLOP_ARG6: + /* These are not allocated dynamically but do not have node */ + my_ret = opargs[0]; + aml_xaddref(my_ret, htab->mnem); + break; + case AMLOP_NAMECHAR: + /* opargs[0] = named object (node != NULL), or nameref */ + my_ret = opargs[0]; + if (ret_type == 'i' || ret_type == 't' || ret_type == 'T') { + /* Return TermArg or Integer: Evaluate object */ + my_ret = aml_xeval(scope, my_ret, ret_type, 0, NULL); + } + else if (my_ret->type == AML_OBJTYPE_METHOD) { + /* This should only happen with CondRef */ + dnprintf(12,"non-termarg method : %s\n", stype); + aml_xaddref(my_ret, "zoom"); + } + break; + + case AMLOP_ZERO: + case AMLOP_ONE: + case AMLOP_ONES: + case AMLOP_DEBUG: + case AMLOP_REVISION: + case AMLOP_BYTEPREFIX: + case AMLOP_WORDPREFIX: + case AMLOP_DWORDPREFIX: + case AMLOP_QWORDPREFIX: + case AMLOP_STRINGPREFIX: + my_ret = opargs[0]; + break; + + case AMLOP_BUFFER: + /* Buffer: iB => Buffer */ + my_ret = aml_allocvalue(AML_OBJTYPE_BUFFER, + opargs[0]->v_integer, NULL); + memcpy(my_ret->v_buffer, opargs[1]->v_buffer, + opargs[1]->length); + break; + case AMLOP_PACKAGE: + case AMLOP_VARPACKAGE: + /* Package/VarPackage: bT/iT => Package */ + my_ret = aml_allocvalue(AML_OBJTYPE_PACKAGE, + opargs[0]->v_integer, 0); + mscope = aml_xpushscope(scope, opargs[1], scope->node, + AMLOP_PACKAGE); + + for (idx=0; idx<my_ret->length; idx++) { + tmp = aml_xparse(mscope, 'o', "Package"); + if (tmp == NULL) { + continue; + } + if (tmp->node) { + /* Object is a named node: store as string */ + const char *nn = aml_nodename(tmp->node); + aml_xdelref(&tmp, "pkg.node"); + tmp = aml_allocvalue(AML_OBJTYPE_STRING, + -1, nn); + } + else if (tmp->type == AML_OBJTYPE_NAMEREF) { + const char *nn = aml_getname(tmp->v_nameref); + aml_xdelref(&tmp, "pkg.node"); + tmp = aml_allocvalue(AML_OBJTYPE_STRING, + -1, nn); + } + /* Package value already allocated; delete it + * and replace with pointer to return value */ + aml_xdelref(&my_ret->v_package[idx], "pkg/init"); + my_ret->v_package[idx] = tmp; + } + aml_xpopscope(mscope); + mscope = NULL; + break; + + /* Math/Logical operations */ + case AMLOP_OR: + case AMLOP_ADD: + case AMLOP_AND: + case AMLOP_NAND: + case AMLOP_XOR: + case AMLOP_SHL: + case AMLOP_SHR: + case AMLOP_NOR: + case AMLOP_MOD: + case AMLOP_SUBTRACT: + case AMLOP_MULTIPLY: + /* XXX: iir => I */ + ival = aml_evalexpr(opargs[0]->v_integer, + opargs[1]->v_integer, opcode); + aml_xstore(scope, opargs[2], ival, NULL); + break; + case AMLOP_DIVIDE: + /* Divide: iirr => I */ + ival = aml_evalexpr(opargs[0]->v_integer, + opargs[1]->v_integer, AMLOP_MOD); + aml_xstore(scope, opargs[2], ival, NULL); + + ival = aml_evalexpr(opargs[0]->v_integer, + opargs[1]->v_integer, AMLOP_DIVIDE); + aml_xstore(scope, opargs[3], ival, NULL); + break; + case AMLOP_NOT: + case AMLOP_TOBCD: + case AMLOP_FROMBCD: + case AMLOP_FINDSETLEFTBIT: + case AMLOP_FINDSETRIGHTBIT: + /* XXX: ir => I */ + ival = aml_evalexpr(opargs[0]->v_integer, 0, opcode); + aml_xstore(scope, opargs[1], ival, NULL); + break; + case AMLOP_INCREMENT: + case AMLOP_DECREMENT: + /* Inc/Dec: S => I */ + my_ret = aml_xeval(scope, opargs[0], AML_ARG_INTEGER, 0, NULL); + ival = aml_evalexpr(my_ret->v_integer, 1, opcode); + aml_xstore(scope, opargs[0], ival, NULL); + break; + case AMLOP_LNOT: + /* LNot: i => Bool */ + ival = aml_evalexpr(opargs[0]->v_integer, 0, opcode); + break; + case AMLOP_LOR: + case AMLOP_LAND: + /* XXX: ii => Bool */ + ival = aml_evalexpr(opargs[0]->v_integer, + opargs[1]->v_integer, opcode); + break; + case AMLOP_LLESS: + case AMLOP_LEQUAL: + case AMLOP_LGREATER: + case AMLOP_LNOTEQUAL: + case AMLOP_LLESSEQUAL: + case AMLOP_LGREATEREQUAL: + /* XXX: tt => Bool */ + ival = aml_xcompare(opargs[0], opargs[1], opcode); + break; + + /* Reference/Store operations */ + case AMLOP_CONDREFOF: + /* CondRef: rr => I */ + ival = 0; + if (opargs[0]->node != NULL) { + aml_freevalue(opargs[1]); + + /* Create Object Reference */ + _aml_setvalue(opargs[1], AML_OBJTYPE_OBJREF, 0, opargs[0]); + opargs[1]->v_objref.type = AMLOP_REFOF; + aml_xaddref(opargs[1], "CondRef"); + + /* Mark that we found it */ + ival = -1; + } + break; + case AMLOP_REFOF: + /* RefOf: r => ObjRef */ + my_ret = aml_allocvalue(AML_OBJTYPE_OBJREF, 0, opargs[0]); + my_ret->v_objref.type = AMLOP_REFOF; + aml_xaddref(my_ret->v_objref.ref, "RefOf"); + break; + case AMLOP_INDEX: + /* Index: tir => ObjRef */ + idx = opargs[1]->v_integer; + if (idx >= opargs[0]->length || idx < 0) { + aml_showvalue(opargs[0], 0); + aml_die("Index out of bounds %d/%d\n", idx, + opargs[0]->length); + } + switch (opargs[0]->type) { + case AML_OBJTYPE_PACKAGE: + /* Don't set opargs[0] to NULL */ + if (ret_type == 't' || ret_type == 'i' || ret_type == 'T') { + my_ret = opargs[0]->v_package[idx]; + aml_xaddref(my_ret, "Index.Package"); + } + else { + my_ret = aml_allocvalue(AML_OBJTYPE_OBJREF, 0, + opargs[0]->v_package[idx]); + my_ret->v_objref.type = AMLOP_PACKAGE; + aml_xaddref(my_ret->v_objref.ref, + "Index.Package"); + } + break; + case AML_OBJTYPE_BUFFER: + case AML_OBJTYPE_STRING: + case AML_OBJTYPE_INTEGER: + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + if (ret_type == 't' || ret_type == 'i' || ret_type == 'T') { + dnprintf(12,"Index.Buf Term: %d = %x\n", + idx, tmp->v_buffer[idx]); + ival = tmp->v_buffer[idx]; + } + else { + dnprintf(12, "Index.Buf Targ\n"); + my_ret = aml_allocvalue(0,0,NULL); + aml_xcreatefield(my_ret, AMLOP_INDEX, tmp, + 8 * idx, 8, NULL, 0); + } + aml_xdelref(&tmp, "Index.BufStr"); + break; + default: + aml_die("Unknown index : %x\n", opargs[0]->type); + break; + } + aml_xstore(scope, opargs[2], ival, my_ret); + break; + case AMLOP_DEREFOF: + /* DerefOf: t:ObjRef => DataRefObj */ + if (opargs[0]->type == AML_OBJTYPE_OBJREF) { + my_ret = opargs[0]->v_objref.ref; + aml_xaddref(my_ret, "DerefOf"); + } + else { + my_ret = opargs[0]; + //aml_xaddref(my_ret, "DerefOf"); + } + break; + case AMLOP_COPYOBJECT: + /* CopyObject: t:DataRefObj, s:implename => DataRefObj */ + my_ret = opargs[0]; + aml_freevalue(opargs[1]); + aml_copyvalue(opargs[1], opargs[0]); + break; + case AMLOP_STORE: + /* Store: t:DataRefObj, S:upername => DataRefObj */ + my_ret = opargs[0]; + aml_xstore(scope, opargs[1], 0, opargs[0]); + break; + + /* Conversion */ + case AMLOP_TOINTEGER: + /* Source:CData, Result => Integer */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_INTEGER, 0); + aml_xstore(scope, opargs[1], 0, my_ret); + break; + case AMLOP_TOBUFFER: + /* Source:CData, Result => Buffer */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_BUFFER, 0); + aml_xstore(scope, opargs[1], 0, my_ret); + break; + case AMLOP_TOHEXSTRING: + /* Source:CData, Result => String */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_STRING, 'x'); + aml_xstore(scope, opargs[1], 0, my_ret); + break; + case AMLOP_TODECSTRING: + /* Source:CData, Result => String */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_STRING, 'd'); + aml_xstore(scope, opargs[1], 0, my_ret); + break; + case AMLOP_TOSTRING: + /* Source:B, Length:I, Result => String */ + aml_xconvert(opargs[0], &my_ret, AML_OBJTYPE_STRING, 0); + aml_die("tostring\n"); + break; + case AMLOP_CONCAT: + /* Source1:CData, Source2:CData, Result => CData */ + aml_xconcat(opargs[0], opargs[1], &my_ret); + aml_xstore(scope, opargs[2], 0, my_ret); + break; + case AMLOP_CONCATRES: + /* Concat two resource buffers: buf1, buf2, result => Buffer */ + aml_xconcatres(opargs[0], opargs[1], &my_ret); + aml_xstore(scope, opargs[2], 0, my_ret); + break; + case AMLOP_MID: + /* Source:BS, Index:I, Length:I, Result => BS */ + aml_xmid(opargs[0], opargs[1]->v_integer, + opargs[2]->v_integer, &my_ret); + aml_xstore(scope, opargs[3], 0, my_ret); + break; + case AMLOP_MATCH: + /* Match: Pkg, Op1, Val1, Op2, Val2, Index */ + ival = aml_xmatch(opargs[0], opargs[5]->v_integer, + opargs[1]->v_integer, opargs[2]->v_integer, + opargs[3]->v_integer, opargs[4]->v_integer); + break; + case AMLOP_SIZEOF: + /* Sizeof: S => i */ + ival = opargs[0]->length; + break; + case AMLOP_OBJECTTYPE: + /* ObjectType: S => i */ + ival = opargs[0]->type; + break; + + /* Mutex/Event handlers */ + case AMLOP_ACQUIRE: + /* Acquire: Sw => Bool */ + ival = acpi_xmutex_acquire(scope, opargs[0], + opargs[1]->v_integer); + break; + case AMLOP_RELEASE: + /* Release: S */ + acpi_xmutex_release(scope, opargs[0]); + break; + case AMLOP_WAIT: + /* Wait: Si => Bool */ + ival = acpi_xevent_wait(scope, opargs[0], + opargs[1]->v_integer); + break; + case AMLOP_RESET: + /* Reset: S */ + acpi_xevent_reset(scope, opargs[0]); + break; + case AMLOP_SIGNAL: + /* Signal: S */ + acpi_xevent_signal(scope, opargs[0]); + break; + + /* Named objects */ + case AMLOP_NAME: + /* Name: Nt */ + aml_freevalue(cname); + aml_copyvalue(cname, opargs[1]); + break; + case AMLOP_ALIAS: + /* Alias: nN */ + cname->type = AML_OBJTYPE_OBJREF; + cname->v_objref.type = AMLOP_ALIAS; + cname->v_objref.ref = opargs[0]; + while (cname->v_objref.ref->type == AML_OBJTYPE_OBJREF) { + /* Single indirection level */ + cname->v_objref.ref = cname->v_objref.ref->v_objref.ref; + } + aml_xaddref(cname->v_objref.ref, "Alias"); + break; + case AMLOP_OPREGION: + /* OpRegion: Nbii */ + cname->type = AML_OBJTYPE_OPREGION; + cname->v_opregion.iospace = opargs[1]->v_integer; + cname->v_opregion.iobase = opargs[2]->v_integer; + cname->v_opregion.iolen = opargs[3]->v_integer; + cname->v_opregion.flag = 0; + break; + case AMLOP_DATAREGION: + /* DataTableRegion: N,t:SigStr,t:OemIDStr,t:OemTableIDStr */ + cname->type = AML_OBJTYPE_OPREGION; + cname->v_opregion.iospace = GAS_SYSTEM_MEMORY; + cname->v_opregion.iobase = 0; + cname->v_opregion.iolen = 0; + aml_die("AML-DataTableRegion\n"); + break; + case AMLOP_EVENT: + /* Event: N */ + cname->type = AML_OBJTYPE_EVENT; + cname->v_integer = 0; + break; + case AMLOP_MUTEX: + /* Mutex: Nw */ + cname->type = AML_OBJTYPE_MUTEX; + cname->v_mtx.synclvl = opargs[1]->v_integer; + break; + case AMLOP_SCOPE: + /* Scope: NT */ + mscope = aml_xpushscope(scope, opargs[1], cname->node, opcode); + break; + case AMLOP_DEVICE: + /* Device: NT */ + cname->type = AML_OBJTYPE_DEVICE; + mscope = aml_xpushscope(scope, opargs[1], cname->node, opcode); + break; + case AMLOP_THERMALZONE: + /* ThermalZone: NT */ + cname->type = AML_OBJTYPE_THERMZONE; + mscope = aml_xpushscope(scope, opargs[1], cname->node, opcode); + break; + case AMLOP_POWERRSRC: + /* PowerRsrc: NbwT */ + cname->type = AML_OBJTYPE_POWERRSRC; + cname->v_powerrsrc.pwr_level = opargs[1]->v_integer; + cname->v_powerrsrc.pwr_order = opargs[2]->v_integer; + mscope = aml_xpushscope(scope, opargs[3], cname->node, opcode); + break; + case AMLOP_PROCESSOR: + /* Processor: NbdbT */ + cname->type = AML_OBJTYPE_PROCESSOR; + cname->v_processor.proc_id = opargs[1]->v_integer; + cname->v_processor.proc_addr = opargs[2]->v_integer; + cname->v_processor.proc_len = opargs[3]->v_integer; + mscope = aml_xpushscope(scope, opargs[4], cname->node, opcode); + break; + case AMLOP_METHOD: + /* Method: NbM */ + cname->type = AML_OBJTYPE_METHOD; + cname->v_method.flags = opargs[1]->v_integer; + cname->v_method.start = opargs[2]->v_buffer; + cname->v_method.end = cname->v_method.start + opargs[2]->length; + cname->v_method.base = aml_root.start; + break; + + /* Field objects */ + case AMLOP_CREATEFIELD: + /* Source:B, BitIndex:I, NumBits:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer, + opargs[2]->v_integer, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + break; + case AMLOP_CREATEBITFIELD: + /* Source:B, BitIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer, + 1, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + break; + case AMLOP_CREATEBYTEFIELD: + /* Source:B, ByteIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer*8, + 8, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + cname->v_field.flags = AML_FIELD_BYTEACC; + break; + case AMLOP_CREATEWORDFIELD: + /* Source:B, ByteIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer*8, + 16, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + cname->v_field.flags = AML_FIELD_WORDACC; + break; + case AMLOP_CREATEDWORDFIELD: + /* Source:B, ByteIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer*8, + 32, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + cname->v_field.flags = AML_FIELD_DWORDACC; + break; + case AMLOP_CREATEQWORDFIELD: + /* Source:B, ByteIndex:I, FieldName */ + aml_xconvert(opargs[0], &tmp, AML_OBJTYPE_BUFFER, 0); + aml_xcreatefield(cname, opcode, tmp, opargs[1]->v_integer*8, + 64, NULL, 0); + aml_xdelref(&tmp, htab->mnem); + cname->v_field.flags = AML_FIELD_QWORDACC; + break; + case AMLOP_FIELD: + /* Field: n:OpRegion, b:Flags, F:ieldlist */ + mscope = aml_xpushscope(scope, opargs[2], scope->node, opcode); + aml_xparsefieldlist(mscope, opcode, opargs[1]->v_integer, + opargs[0], NULL, 0); + break; + case AMLOP_INDEXFIELD: + /* IndexField: n:Index, n:Data, b:Flags, F:ieldlist */ + mscope = aml_xpushscope(scope, opargs[3], scope->node, opcode); + aml_xparsefieldlist(mscope, opcode, opargs[2]->v_integer, + opargs[1], opargs[0], 0); + break; + case AMLOP_BANKFIELD: + /* BankField: n:OpRegion, n:Field, i:Bank, b:Flags, F:ieldlist */ + mscope = aml_xpushscope(scope, opargs[4], scope->node, opcode); + aml_xparsefieldlist(mscope, opcode, opargs[3]->v_integer, + opargs[0], opargs[1], opargs[2]->v_integer); + break; + + /* Misc functions */ + case AMLOP_STALL: + /* Stall: i */ + acpi_stall(opargs[0]->v_integer); + break; + case AMLOP_SLEEP: + /* Sleep: i */ + acpi_sleep(opargs[0]->v_integer); + break; + case AMLOP_NOTIFY: + /* Notify: Si */ + dnprintf(50,"Notifying: %s %x\n", + aml_nodename(opargs[0]->node), + opargs[1]->v_integer); + aml_notify(opargs[0]->node, opargs[1]->v_integer); + break; + case AMLOP_TIMER: + /* Timer: => i */ + ival = 0xDEADBEEF; + break; + case AMLOP_FATAL: + /* Fatal: bdi */ + aml_die("AML FATAL ERROR: %x,%x,%x\n", + opargs[0]->v_integer, opargs[1]->v_integer, + opargs[2]->v_integer); + break; + case AMLOP_LOADTABLE: + /* LoadTable(Sig:Str, OEMID:Str, OEMTable:Str, [RootPath:Str], [ParmPath:Str], + [ParmData:DataRefObj]) => DDBHandle */ + aml_die("LoadTable"); + break; + case AMLOP_LOAD: + /* Load(Object:NameString, DDBHandle:SuperName) */ + tmp = opargs[0]; + if (tmp->type != AML_OBJTYPE_OPREGION || + tmp->v_opregion.iospace != GAS_SYSTEM_MEMORY) { + aml_die("LOAD: not a memory region!\n"); + } +#if 0 + /* Create buffer and read from memory */ + aml_xgasio(tmp->v_opregion.iospace, tmp->v_opregion.iobase, + tmp->v_opregion.iolen, + opargs[1], ACPI_IOREAD); + + /* Validate that this is a SSDT */ + if (!valid_acpihdr(opargs[1]->v_buffer, opargs[1]->length, + "SSDT")) { + aml_die("LOAD: Not a SSDT!\n"); + } + + /* Parse block */ + mscope = aml_xpushscope(scope, opargs[1], scope->node, + AMLOP_SCOPE); +#endif + break; + case AMLOP_UNLOAD: + /* DDBHandle */ + aml_die("Unload"); + break; + + /* Control Flow */ + case AMLOP_IF: + /* Arguments: iT or iTbT */ + if (opargs[0]->v_integer) { + dnprintf(10,"parse-if @ %.4x\n", pc); + mscope = aml_xpushscope(scope, opargs[1], scope->node, + AMLOP_IF); + } + else if (opargs[3] != NULL) { + dnprintf(10,"parse-else @ %.4x\n", pc); + mscope = aml_xpushscope(scope, opargs[3], scope->node, + AMLOP_ELSE); + } + break; + case AMLOP_WHILE: + mscope = aml_xpushscope(scope, opargs[0], scope->node, + AMLOP_WHILE); + while (mscope->pos != NULL) { + /* At beginning of scope.. reset and perform test */ + mscope->pos = mscope->start; + tmp = aml_xparse(mscope, AML_ARG_INTEGER, "While-Test"); + ival = tmp->v_integer; + aml_xdelref(&tmp, "while"); + + dnprintf(10,"@@@@@@ WHILE: %llx @ %x\n", ival, pc); + if (ival == 0) { + break; + } + aml_xparse(mscope, 'T', "While"); + } + aml_xpopscope(mscope); + mscope = NULL; + break; + case AMLOP_BREAK: + /* Break: Find While Scope parent, mark type as null */ + mscope = aml_xfindscope(scope, AMLOP_WHILE, 1); + mscope->pos = NULL; + mscope = NULL; + break; + case AMLOP_CONTINUE: + /* Find Scope.. mark all objects as invalid on way to root */ + mscope = aml_xfindscope(scope, AMLOP_WHILE, 1); + mscope->pos = mscope->start; + mscope = NULL; + break; + case AMLOP_RETURN: + mscope = aml_xfindscope(scope, AMLOP_METHOD, 1); + if (mscope->retv) { + aml_die("already allocated\n"); + } + mscope->retv = aml_allocvalue(0,0,NULL); + aml_copyvalue(mscope->retv, opargs[0]); + mscope = NULL; + break; + default: + /* may be set direct result */ + aml_die("Unknown opcode: %x:%s\n", opcode, htab->mnem); + break; + } + if (mscope != NULL) { + aml_xparse(mscope, 'T', htab->mnem); + aml_xpopscope(mscope); + } + if ((ret_type == 'i' || ret_type == 't') && my_ret == NULL) { + dnprintf(10,"quick: %.4x [%s] allocating return integer = 0x%llx\n", + pc, htab->mnem, ival); + my_ret = aml_allocvalue(AML_OBJTYPE_INTEGER, ival, NULL); + } + if (ret_type == 'i' && my_ret && my_ret->type != AML_OBJTYPE_INTEGER) { + dnprintf(10,"quick: %.4x convert to integer %s -> %s\n", + pc, htab->mnem, stype); + } + if (my_ret != NULL) { + /* Display result */ + my_ret->stack = opcode; + dnprintf(20,"quick: %.4x %18s %c %.4x\n", pc, stype, + ret_type, my_ret->stack); + } + + /* End opcode: display/free arguments */ + for (idx=0; optype[idx] != 0; idx++) { + if (opargs[idx] == my_ret || optype[idx] == 'N') + opargs[idx] = NULL; + aml_xdelref(&opargs[idx], "oparg"); + } + odp--; + + /* If parsing whole scope and not done, start again */ + if (ret_type == 'T') { + aml_xdelref(&my_ret, "scope.loop"); + if (scope->pos && scope->pos < scope->end) + goto start; + } + dnprintf(50, ">>return [%s] %s %c %p\n", aml_nodename(scope->node), + stype, ret_type, my_ret); + return my_ret; +} + +int +acpi_parse_aml(struct acpi_softc *sc, u_int8_t *start, u_int32_t length) +{ + struct aml_scope *scope; + struct aml_value res; + + dsdt_softc = sc; + + aml_root.start = start; + memset(&res, 0, sizeof(res)); + res.type = AML_OBJTYPE_SCOPE; + res.length = length; + res.v_buffer = start; + + /* Push toplevel scope, parse AML */ + scope = aml_xpushscope(NULL, &res, &aml_root, AMLOP_SCOPE); + aml_busy++; + aml_xparse(scope, 'T', "TopLevel"); + aml_busy--; + aml_xpopscope(scope); + + return 0; +} + +/* + * @@@: External API + * + * evaluate an AML node + * Returns a copy of the value in res (must be freed by user) + */ +int +aml_evalnode(struct acpi_softc *sc, struct aml_node *node, + int argc, struct aml_value *argv, struct aml_value *res) +{ + struct aml_value *xres; + + if (node == NULL || node->value == NULL) + return (ACPI_E_BADVALUE); + dnprintf(12,"EVALNODE: %s %d\n", aml_nodename(node), acpi_nalloc); + switch (node->value->type) { + case AML_OBJTYPE_INTEGER: + case AML_OBJTYPE_PACKAGE: + case AML_OBJTYPE_STRING: + case AML_OBJTYPE_BUFFER: + case AML_OBJTYPE_PROCESSOR: + case AML_OBJTYPE_THERMZONE: + case AML_OBJTYPE_POWERRSRC: + if (res) + aml_copyvalue(res, node->value); + break; + case AML_OBJTYPE_BUFFERFIELD: + case AML_OBJTYPE_FIELDUNIT: + case AML_OBJTYPE_METHOD: + aml_busy++; + xres = aml_xeval(NULL, node->value, 't', argc, argv); + aml_busy--; + if (res && xres) + aml_copyvalue(res, xres); + if (xres != node->value) + aml_xdelref(&xres, "EvalNode"); + break; + default: + return (-1); + } + return (0); + + /* Pass object off to Eval Function */ + xres = aml_xeval(NULL, node->value, 't', argc, argv); + aml_copyvalue(res, xres); + if (xres != node->value) + aml_xdelref(&xres, "EvalNode"); + + return (0); +} + +/* + * evaluate an AML name + * Returns a copy of the value in res (must be freed by user) + */ +int +aml_evalname(struct acpi_softc *sc, struct aml_node *parent, const char *name, + int argc, struct aml_value *argv, struct aml_value *res) +{ + parent = aml_searchname(parent, name); + return aml_evalnode(sc, parent, argc, argv, res); +} + +/* + * evaluate an AML integer object + */ +int +aml_evalinteger(struct acpi_softc *sc, struct aml_node *parent, + const char *name, int argc, struct aml_value *argv, int64_t *ival) +{ + struct aml_value res; + int rc; + + parent = aml_searchname(parent, name); + rc = aml_evalnode(sc, parent, argc, argv, &res); + *ival = aml_val2int(&res); + aml_freevalue(&res); + + return rc; +} + +/* + * Search for an AML name in namespace.. root only + */ +struct aml_node * +aml_searchname(struct aml_node *root, const void *vname) +{ + char *name = (char *)vname; + + dnprintf(25,"Searchname: %s:%s = ", aml_nodename(root), vname); + if (*name == AMLOP_ROOTCHAR) { + root = &aml_root; + name++; + } + while (*name != 0) { + root = __aml_search(root, name, 0); + name += (name[4] == '.') ? 5 : 4; + } + dnprintf(25,"%p %s\n", root, aml_nodename(root)); + return root; +} + +/* + * Search for relative name + */ +struct aml_node * +aml_searchrel(struct aml_node *root, const void *vname) +{ + struct aml_node *res; + + while (root) { + res = aml_searchname(root, vname); + if (res != NULL) + return res; + root = root->parent; + } + return NULL; +} diff --git a/sys/dev/acpi/dsdt.h b/sys/dev/acpi/dsdt.h index 5ec041f0d8f..4b2ca856c18 100644 --- a/sys/dev/acpi/dsdt.h +++ b/sys/dev/acpi/dsdt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dsdt.h,v 1.32 2008/05/13 09:05:06 jordan Exp $ */ +/* $OpenBSD: dsdt.h,v 1.33 2008/05/14 05:24:36 jordan Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -54,6 +54,7 @@ const char *aml_args(int); const char *aml_mnem(int, uint8_t *); int64_t aml_val2int(struct aml_value *); struct aml_node *aml_searchname(struct aml_node *, const void *); +struct aml_node *aml_searchrel(struct aml_node *, const void *); struct aml_node *aml_createname(struct aml_node *, const void *, struct aml_value *); |