summaryrefslogtreecommitdiff
path: root/sys/dev/acpi
diff options
context:
space:
mode:
authorAlexander Yurchenko <grange@cvs.openbsd.org>2006-02-19 19:03:50 +0000
committerAlexander Yurchenko <grange@cvs.openbsd.org>2006-02-19 19:03:50 +0000
commit5ad5de8bc814a5aeec9449af54eebf87f901ea37 (patch)
tree65077ff302403dc708c173132543c389fd7316d7 /sys/dev/acpi
parent55dd2ee4b955dfb1feb94b1a4b75fafe64e2dd27 (diff)
Fix acpi_enter_sleep_state() by replacing current ugly hack
with mostly correct sleeping state transition code. ok brad@ marco@
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r--sys/dev/acpi/acpi.c51
1 files changed, 45 insertions, 6 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c
index aa8be64ed10..b5d102a54ee 100644
--- a/sys/dev/acpi/acpi.c
+++ b/sys/dev/acpi/acpi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi.c,v 1.34 2006/02/19 04:50:46 marco Exp $ */
+/* $OpenBSD: acpi.c,v 1.35 2006/02/19 19:03:49 grange Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -28,6 +28,7 @@
#include <sys/kthread.h>
#include <machine/conf.h>
+#include <machine/cpufunc.h>
#include <machine/bus.h>
#include <dev/pci/pcivar.h>
@@ -981,12 +982,50 @@ void
acpi_enter_sleep_state(struct acpi_softc *sc, int state)
{
#ifdef ACPI_ENABLE
- u_int16_t flag;
+ u_int16_t rega, regb;
+ int retries;
- flag = acpi_read_pmreg(sc, ACPIREG_PM1_CNT);
- /* XXX This is sick and wrong and illegal! */
- acpi_write_pmreg(sc, ACPIREG_PM1_CNT, flag |= (state << 10));
- acpi_write_pmreg(sc, ACPIREG_PM1_CNT, flag |= ACPI_PM1_SLP_EN);
+ if (state == ACPI_STATE_S0)
+ return;
+ if (sc->sc_sleeptype[state].slp_typa == -1 ||
+ sc->sc_sleeptype[state].slp_typb == -1) {
+ printf("%s: state S%d unavailable\n",
+ sc->sc_dev.dv_xname, state);
+ return;
+ }
+
+ disable_intr();
+
+ /* Clear WAK_STS bit */
+ acpi_write_pmreg(sc, ACPIREG_PM1_STS, ACPI_PM1_WAK_STS);
+
+ /* Write SLP_TYPx values */
+ rega = acpi_read_pmreg(sc, ACPIREG_PM1A_CNT);
+ regb = acpi_read_pmreg(sc, ACPIREG_PM1B_CNT);
+ rega &= ~(ACPI_PM1_SLP_TYPX_MASK | ACPI_PM1_SLP_EN);
+ regb &= ~(ACPI_PM1_SLP_TYPX_MASK | ACPI_PM1_SLP_EN);
+ rega |= ACPI_PM1_SLP_TYPX(sc->sc_sleeptype[state].slp_typa);
+ regb |= ACPI_PM1_SLP_TYPX(sc->sc_sleeptype[state].slp_typb);
+ acpi_write_pmreg(sc, ACPIREG_PM1A_CNT, rega);
+ acpi_write_pmreg(sc, ACPIREG_PM1B_CNT, regb);
+
+ /* Set SLP_EN bit */
+ rega |= ACPI_PM1_SLP_EN;
+ regb |= ACPI_PM1_SLP_EN;
+ acpi_write_pmreg(sc, ACPIREG_PM1A_CNT, rega);
+ acpi_write_pmreg(sc, ACPIREG_PM1B_CNT, regb);
+
+ /* Loop on WAK_STS */
+ for (retries = 1000; retries > 0; retries--) {
+ rega = acpi_read_pmreg(sc, ACPIREG_PM1A_STS);
+ regb = acpi_read_pmreg(sc, ACPIREG_PM1B_STS);
+ if (rega & ACPI_PM1_WAK_STS ||
+ regb & ACPI_PM1_WAK_STS)
+ break;
+ DELAY(10);
+ }
+
+ enable_intr();
#endif
}