1 /* $OpenBSD: acpi_x86.c,v 1.15 2022/03/06 15:12:00 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> 4 * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 23 #include <dev/acpi/acpireg.h> 24 #include <dev/acpi/acpivar.h> 25 #include <dev/acpi/acpidev.h> 26 #include <dev/acpi/dsdt.h> 27 28 #include <machine/apmvar.h> 29 30 int 31 sleep_showstate(void *v, int sleepmode) 32 { 33 struct acpi_softc *sc = v; 34 35 switch (sleepmode) { 36 case SLEEP_SUSPEND: 37 sc->sc_state = ACPI_STATE_S3; 38 break; 39 case SLEEP_HIBERNATE: 40 sc->sc_state = ACPI_STATE_S4; 41 break; 42 default: 43 return (EOPNOTSUPP); 44 } 45 46 if (sc->sc_sleeptype[sc->sc_state].slp_typa == -1 || 47 sc->sc_sleeptype[sc->sc_state].slp_typb == -1) { 48 if (sc->sc_state == ACPI_STATE_S4) { 49 sc->sc_state = ACPI_STATE_S5; /* No S4, use S5 */ 50 printf("%s: S4 unavailable, using S5\n", 51 sc->sc_dev.dv_xname); 52 } else { 53 printf("%s: state S%d unavailable\n", 54 sc->sc_dev.dv_xname, sc->sc_state); 55 return (EOPNOTSUPP); 56 } 57 } 58 59 /* 1st suspend AML step: _TTS(tostate) */ 60 if (aml_node_setval(sc, sc->sc_tts, sc->sc_state) != 0) 61 return (EINVAL); 62 acpi_indicator(sc, ACPI_SST_WAKING); /* blink */ 63 return 0; 64 } 65 66 int 67 sleep_setstate(void *v) 68 { 69 struct acpi_softc *sc = v; 70 71 /* 2nd suspend AML step: _PTS(tostate) */ 72 if (aml_node_setval(sc, sc->sc_pts, sc->sc_state) != 0) 73 return (EINVAL); 74 acpi_indicator(sc, ACPI_SST_WAKING); /* blink */ 75 return 0; 76 } 77 78 int 79 gosleep(void *v) 80 { 81 struct acpi_softc *sc = v; 82 int ret; 83 84 acpibtn_enable_psw(); /* enable _LID for wakeup */ 85 acpi_indicator(sc, ACPI_SST_SLEEPING); 86 87 /* 3rd suspend AML step: _GTS(tostate) */ 88 aml_node_setval(sc, sc->sc_gts, sc->sc_state); 89 90 /* Clear fixed event status */ 91 acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0, ACPI_PM1_ALL_STS); 92 93 /* Enable wake GPEs */ 94 acpi_disable_allgpes(sc); 95 acpi_enable_wakegpes(sc, sc->sc_state); 96 97 ret = acpi_sleep_cpu(sc, sc->sc_state); 98 acpi_resume_cpu(sc, sc->sc_state); 99 sc->sc_state = ACPI_STATE_S0; 100 101 return ret; 102 } 103 104 void 105 sleep_abort(void *v) 106 { 107 struct acpi_softc *sc = v; 108 109 sc->sc_state = ACPI_STATE_S0; 110 } 111 112 int 113 sleep_resume(void *v) 114 { 115 struct acpi_softc *sc = v; 116 117 acpibtn_disable_psw(); /* disable _LID for wakeup */ 118 119 /* 3rd resume AML step: _TTS(runstate) */ 120 if (aml_node_setval(sc, sc->sc_tts, sc->sc_state) != 0) 121 return (EINVAL); 122 acpi_indicator(sc, ACPI_SST_WAKING); /* blink */ 123 return 0; 124 } 125 126 127 static int 128 checklids(struct acpi_softc *sc) 129 { 130 extern int lid_action; 131 int lids; 132 133 lids = acpibtn_numopenlids(); 134 if (lids == 0 && lid_action != 0) 135 return EAGAIN; 136 return 0; 137 } 138 139 140 int 141 suspend_finish(void *v) 142 { 143 struct acpi_softc *sc = v; 144 145 acpi_record_event(sc, APM_NORMAL_RESUME); 146 acpi_indicator(sc, ACPI_SST_WORKING); 147 148 /* If we woke up but all the lids are closed, go back to sleep */ 149 return checklids(sc); 150 } 151