1 /* $OpenBSD: acpi_apm.c,v 1.3 2023/08/06 14:30:08 tobhe 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/fcntl.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/conf.h> 29 #include <machine/cpufunc.h> 30 31 #ifdef HIBERNATE 32 #include <sys/hibernate.h> 33 #endif 34 35 #include <machine/apmvar.h> 36 #define APMUNIT(dev) (minor(dev)&0xf0) 37 #define APMDEV(dev) (minor(dev)&0x0f) 38 #define APMDEV_NORMAL 0 39 #define APMDEV_CTL 8 40 41 #ifndef SMALL_KERNEL 42 43 int 44 acpiopen(dev_t dev, int flag, int mode, struct proc *p) 45 { 46 int error = 0; 47 struct acpi_softc *sc = acpi_softc; 48 int s; 49 50 if (sc == NULL) 51 return (ENXIO); 52 53 s = splbio(); 54 switch (APMDEV(dev)) { 55 case APMDEV_CTL: 56 if (!(flag & FWRITE)) { 57 error = EINVAL; 58 break; 59 } 60 if (sc->sc_flags & SCFLAG_OWRITE) { 61 error = EBUSY; 62 break; 63 } 64 sc->sc_flags |= SCFLAG_OWRITE; 65 break; 66 case APMDEV_NORMAL: 67 if (!(flag & FREAD) || (flag & FWRITE)) { 68 error = EINVAL; 69 break; 70 } 71 sc->sc_flags |= SCFLAG_OREAD; 72 break; 73 default: 74 error = ENXIO; 75 break; 76 } 77 splx(s); 78 return (error); 79 } 80 81 int 82 acpiclose(dev_t dev, int flag, int mode, struct proc *p) 83 { 84 int error = 0; 85 struct acpi_softc *sc = acpi_softc; 86 int s; 87 88 if (sc == NULL) 89 return (ENXIO); 90 91 s = splbio(); 92 switch (APMDEV(dev)) { 93 case APMDEV_CTL: 94 sc->sc_flags &= ~SCFLAG_OWRITE; 95 break; 96 case APMDEV_NORMAL: 97 sc->sc_flags &= ~SCFLAG_OREAD; 98 break; 99 default: 100 error = ENXIO; 101 break; 102 } 103 splx(s); 104 return (error); 105 } 106 107 int 108 acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 109 { 110 int error = 0; 111 struct acpi_softc *sc = acpi_softc; 112 struct apm_power_info *pi = (struct apm_power_info *)data; 113 int s; 114 115 if (sc == NULL) 116 return (ENXIO); 117 118 s = splbio(); 119 /* fake APM */ 120 switch (cmd) { 121 #ifdef SUSPEND 122 case APM_IOC_SUSPEND: 123 case APM_IOC_STANDBY: 124 if ((flag & FWRITE) == 0) { 125 error = EBADF; 126 break; 127 } 128 error = request_sleep(SLEEP_SUSPEND); 129 if (error) 130 break; 131 acpi_wakeup(sc); 132 break; 133 #ifdef HIBERNATE 134 case APM_IOC_HIBERNATE: 135 if ((error = suser(p)) != 0) 136 break; 137 if ((flag & FWRITE) == 0) { 138 error = EBADF; 139 break; 140 } 141 if (get_hibernate_io_function(swdevt[0].sw_dev) == NULL) { 142 error = EOPNOTSUPP; 143 break; 144 } 145 error = request_sleep(SLEEP_HIBERNATE); 146 if (error) 147 break; 148 acpi_wakeup(sc); 149 break; 150 #endif 151 #endif 152 case APM_IOC_GETPOWER: 153 error = acpi_apminfo(pi); 154 break; 155 156 default: 157 error = ENOTTY; 158 } 159 160 splx(s); 161 return (error); 162 } 163 164 void acpi_filtdetach(struct knote *); 165 int acpi_filtread(struct knote *, long); 166 167 const struct filterops acpiread_filtops = { 168 .f_flags = FILTEROP_ISFD, 169 .f_attach = NULL, 170 .f_detach = acpi_filtdetach, 171 .f_event = acpi_filtread, 172 }; 173 174 int 175 acpikqfilter(dev_t dev, struct knote *kn) 176 { 177 struct acpi_softc *sc = acpi_softc; 178 int s; 179 180 if (sc == NULL) 181 return (ENXIO); 182 183 switch (kn->kn_filter) { 184 case EVFILT_READ: 185 kn->kn_fop = &acpiread_filtops; 186 break; 187 default: 188 return (EINVAL); 189 } 190 191 kn->kn_hook = sc; 192 193 s = splbio(); 194 klist_insert_locked(&sc->sc_note, kn); 195 splx(s); 196 197 return (0); 198 } 199 200 void 201 acpi_filtdetach(struct knote *kn) 202 { 203 struct acpi_softc *sc = kn->kn_hook; 204 int s; 205 206 s = splbio(); 207 klist_remove_locked(&sc->sc_note, kn); 208 splx(s); 209 } 210 211 int 212 acpi_filtread(struct knote *kn, long hint) 213 { 214 /* XXX weird kqueue_scan() semantics */ 215 if (hint && !kn->kn_data) 216 kn->kn_data = hint; 217 return (1); 218 } 219 220 #ifdef SUSPEND 221 int 222 request_sleep(int sleepmode) 223 { 224 struct acpi_softc *sc = acpi_softc; 225 226 #ifdef HIBERNATE 227 if (sleepmode == SLEEP_HIBERNATE) { 228 if (get_hibernate_io_function(swdevt[0].sw_dev) == NULL) 229 return EOPNOTSUPP; 230 } 231 #endif 232 acpi_addtask(sc, acpi_sleep_task, sc, sleepmode); 233 return 0; 234 } 235 #endif /* SUSPEND */ 236 237 #else /* SMALL_KERNEL */ 238 239 int 240 acpiopen(dev_t dev, int flag, int mode, struct proc *p) 241 { 242 return (ENXIO); 243 } 244 245 int 246 acpiclose(dev_t dev, int flag, int mode, struct proc *p) 247 { 248 return (ENXIO); 249 } 250 251 int 252 acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 253 { 254 return (ENXIO); 255 } 256 257 int 258 acpikqfilter(dev_t dev, struct knote *kn) 259 { 260 return (EOPNOTSUPP); 261 } 262 263 #endif /* SMALL_KERNEL */ 264