xref: /openbsd/sys/dev/acpi/acpi_apm.c (revision d415bd75)
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