diff options
author | Marco Peereboom <marco@cvs.openbsd.org> | 2008-06-06 09:13:03 +0000 |
---|---|---|
committer | Marco Peereboom <marco@cvs.openbsd.org> | 2008-06-06 09:13:03 +0000 |
commit | fe519eca1819b5b510dc92c55629f48058d21c62 (patch) | |
tree | b34cfff1474e966519942e89f95d03f250d27a09 /sys/dev/acpi | |
parent | 4d1c24b6554350893cc4ff6fd5dcd4c16d68d925 (diff) |
Add _?RS methods evaluation to obtain additional heuristics and setting
interrupt routing. Fixes several HP & IBM machines.
ok deraadt ketennis
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r-- | sys/dev/acpi/acpiprt.c | 79 |
1 files changed, 72 insertions, 7 deletions
diff --git a/sys/dev/acpi/acpiprt.c b/sys/dev/acpi/acpiprt.c index cd63da05583..8bb3cf79fb1 100644 --- a/sys/dev/acpi/acpiprt.c +++ b/sys/dev/acpi/acpiprt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpiprt.c,v 1.25 2008/06/01 17:59:55 marco Exp $ */ +/* $OpenBSD: acpiprt.c,v 1.26 2008/06/06 09:13:02 marco Exp $ */ /* * Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org> * @@ -68,6 +68,7 @@ struct cfdriver acpiprt_cd = { void acpiprt_prt_add(struct acpiprt_softc *, struct aml_value *); int acpiprt_getpcibus(struct acpiprt_softc *, struct aml_node *); +void acpiprt_route_interrupt(struct acpiprt_softc *, struct aml_node *); int acpiprt_match(struct device *parent, void *match, void *aux) @@ -166,7 +167,7 @@ acpiprt_getirq(union acpi_resource *crs, void *arg) *irq = aml_letohost32(crs->lr_extirq.irq[0]); break; default: - printf("Unknown interrupt : %x\n", typ); + printf("Unknown interrupt: %x\n", typ); } return (0); } @@ -220,16 +221,30 @@ acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v) } if (pp->type == AML_OBJTYPE_DEVICE) { node = pp->node; - if (aml_evalname(sc->sc_acpi, node, "_STA", 0, NULL, &res)) + if (aml_evalname(sc->sc_acpi, node, "_STA", 0, NULL, &res)) { printf("no _STA method\n"); + return; + } - sta = aml_val2int(&res) & STA_ENABLED; + sta = aml_val2int(&res); aml_freevalue(&res); - if (sta == 0) - return; + if ((sta & STA_ENABLED) == 0) { + if ((sta & STA_PRESENT) == 0) + return; + + acpiprt_route_interrupt(sc, node); - if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) + aml_evalname(sc->sc_acpi, node, "_STA", 0, NULL, &res); + sta = aml_val2int(&res); + aml_freevalue(&res); + if ((sta & STA_ENABLED) == 0) + return; + } + + if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) { printf("no _CRS method\n"); + return; + } if (res.type != AML_OBJTYPE_BUFFER || res.length < 6) { printf("invalid _CRS object\n"); @@ -396,3 +411,53 @@ acpiprt_getpcibus(struct acpiprt_softc *sc, struct aml_node *node) } return (0); } + +void +acpiprt_route_interrupt(struct acpiprt_softc *sc, struct aml_node *node) +{ + struct aml_value res, res2; + union acpi_resource *crs; + int irq; + + if (aml_evalname(sc->sc_acpi, node, "_PRS", 0, NULL, &res)) { + printf("no _PRS method\n"); + return; + } + + if (res.type != AML_OBJTYPE_BUFFER || res.length < 6) { + printf("invalid _PRS object\n"); + aml_freevalue(&res); + return; + } + aml_parse_resource(res.length, res.v_buffer, acpiprt_getirq, &irq); + aml_freevalue(&res); + + if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) { + printf("no _PRS method\n"); + return; + } + + if (res.type != AML_OBJTYPE_BUFFER || res.length < 6) { + printf("invalid _CRS object\n"); + aml_freevalue(&res); + return; + } + + crs = (union acpi_resource *)res.v_buffer; + switch (AML_CRSTYPE(crs)) { + case SR_IRQ: + crs->sr_irq.irq_mask = htole16(1 << irq); + break; + case LR_EXTIRQ: + crs->lr_extirq.irq[0] = htole32(irq); + break; + } + + if (aml_evalname(sc->sc_acpi, node, "_SRS", 1, &res, &res2)) { + printf("no _SRS method\n"); + aml_freevalue(&res); + return; + } + aml_freevalue(&res); + aml_freevalue(&res2); +} |