xref: /freebsd/sys/amd64/acpica/acpi_machdep.c (revision 3ff369fed2a08f32dda232c10470b949bef9489f)
1 /*-
2  * Copyright (c) 2001 Mitsuru IWASAKI
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *      $FreeBSD$
27  */
28 
29 #include <sys/param.h>
30 #include <sys/bus.h>
31 #include <sys/conf.h>
32 #include <sys/fcntl.h>
33 #include <sys/uio.h>
34 
35 #include "acpi.h"
36 
37 #include <dev/acpica/acpivar.h>
38 #include <dev/acpica/acpiio.h>
39 
40 static device_t	acpi_dev;
41 
42 /*
43  * APM driver emulation
44  */
45 
46 #include <sys/selinfo.h>
47 
48 #include <machine/apm_bios.h>
49 #include <machine/pc/bios.h>
50 
51 #include <i386/apm/apm.h>
52 
53 static struct apm_softc	apm_softc;
54 
55 static d_open_t apmopen;
56 static d_close_t apmclose;
57 static d_write_t apmwrite;
58 static d_ioctl_t apmioctl;
59 static d_poll_t apmpoll;
60 
61 #define CDEV_MAJOR 39
62 static struct cdevsw apm_cdevsw = {
63 	/* open */	apmopen,
64 	/* close */	apmclose,
65 	/* read */	noread,
66 	/* write */	apmwrite,
67 	/* ioctl */	apmioctl,
68 	/* poll */	apmpoll,
69 	/* mmap */	nommap,
70 	/* strategy */	nostrategy,
71 	/* name */	"apm",
72 	/* maj */	CDEV_MAJOR,
73 	/* dump */	nodump,
74 	/* psize */	nopsize,
75 	/* flags */	0,
76 };
77 
78 static int
79 acpi_capm_convert_battstate(struct  acpi_battinfo *battp)
80 {
81 	int	state;
82 
83 	state = 0xff;	/* XXX unknown */
84 
85 	if (battp->state & ACPI_BATT_STAT_DISCHARG) {
86 		if (battp->cap >= 50) {
87 			state = 0;	/* high */
88 		} else {
89 			state = 1;	/* low */
90 		}
91 	}
92 	if (battp->state & ACPI_BATT_STAT_CRITICAL) {
93 		state = 2;		/* critical */
94 	}
95 	if (battp->state & ACPI_BATT_STAT_CHARGING) {
96 		state = 3;		/* charging */
97 	}
98 	return (state);
99 }
100 
101 static int
102 acpi_capm_convert_battflags(struct  acpi_battinfo *battp)
103 {
104 	int	flags;
105 
106 	flags = 0;
107 
108 	if (battp->cap >= 50) {
109 		flags |= APM_BATT_HIGH;
110 	} else {
111 		if (battp->state & ACPI_BATT_STAT_CRITICAL) {
112 			flags |= APM_BATT_CRITICAL;
113 		} else {
114 			flags |= APM_BATT_LOW;
115 		}
116 	}
117 	if (battp->state & ACPI_BATT_STAT_CHARGING) {
118 		flags |= APM_BATT_CHARGING;
119 	}
120 	if (battp->state == ACPI_BATT_STAT_NOT_PRESENT) {
121 		flags = APM_BATT_NOT_PRESENT;
122 	}
123 
124 	return (flags);
125 }
126 
127 static int
128 acpi_capm_get_info(apm_info_t aip)
129 {
130 	int	acline;
131 	struct	acpi_battinfo batt;
132 
133 	aip->ai_infoversion = 1;
134 	aip->ai_major       = 1;
135 	aip->ai_minor       = 2;
136 	aip->ai_status      = apm_softc.active;
137 	aip->ai_capabilities= 0xff00;	/* XXX unknown */
138 
139 	if (acpi_acad_get_acline(&acline)) {
140 		aip->ai_acline = 0xff;		/* unknown */
141 	} else {
142 		aip->ai_acline = acline;	/* on/off */
143 	}
144 
145 	if (acpi_battery_get_battinfo(-1, &batt)) {
146 		aip->ai_batt_stat = 0xff;	/* unknown */
147 		aip->ai_batt_life = 0xff;	/* unknown */
148 		aip->ai_batt_time = -1;		/* unknown */
149 		aip->ai_batteries = 0;
150 	} else {
151 		aip->ai_batt_stat = acpi_capm_convert_battstate(&batt);
152 		aip->ai_batt_life = batt.cap;
153 		aip->ai_batt_time = (batt.min == -1) ? -1 : batt.min * 60;
154 		aip->ai_batteries = acpi_battery_get_units();
155 	}
156 
157 	return (0);
158 }
159 
160 static int
161 acpi_capm_get_pwstatus(apm_pwstatus_t app)
162 {
163 	int	batt_unit;
164 	int	acline;
165 	struct	acpi_battinfo batt;
166 
167 	if (app->ap_device != PMDV_ALLDEV &&
168 	    (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) {
169 		return (1);
170 	}
171 
172 	if (app->ap_device == PMDV_ALLDEV) {
173 		batt_unit = -1;			/* all units */
174 	} else {
175 		batt_unit = app->ap_device - PMDV_BATT0;
176 	}
177 
178 	if (acpi_battery_get_battinfo(batt_unit, &batt)) {
179 		return (1);
180 	}
181 
182 	app->ap_batt_stat = acpi_capm_convert_battstate(&batt);
183 	app->ap_batt_flag = acpi_capm_convert_battflags(&batt);
184 	app->ap_batt_life = batt.cap;
185 	app->ap_batt_time = (batt.min == -1) ? -1 : batt.min * 60;
186 
187 	if (acpi_acad_get_acline(&acline)) {
188 		app->ap_acline = 0xff;		/* unknown */
189 	} else {
190 		app->ap_acline = acline;	/* on/off */
191 	}
192 
193 	return (0);
194 }
195 
196 static int
197 apmopen(dev_t dev, int flag, int fmt, struct thread *td)
198 {
199 	return (0);
200 }
201 
202 static int
203 apmclose(dev_t dev, int flag, int fmt, struct thread *td)
204 {
205 	return (0);
206 }
207 
208 static int
209 apmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
210 {
211 	int	error = 0;
212 	struct	acpi_softc *acpi_sc;
213 	struct apm_info info;
214 	apm_info_old_t aiop;
215 
216 	if ((acpi_sc = device_get_softc(acpi_dev)) == NULL) {
217 		return (ENXIO);
218 	}
219 
220 	switch (cmd) {
221 	case APMIO_SUSPEND:
222 		if (!(flag & FWRITE))
223 			return (EPERM);
224 		if (apm_softc.active)
225 			acpi_SetSleepState(acpi_sc, acpi_sc->acpi_suspend_sx);
226 		else
227 			error = EINVAL;
228 		break;
229 
230 	case APMIO_STANDBY:
231 		if (!(flag & FWRITE))
232 			return (EPERM);
233 		if (apm_softc.active)
234 			acpi_SetSleepState(acpi_sc, acpi_sc->acpi_standby_sx);
235 		else
236 			error = EINVAL;
237 		break;
238 
239 	case APMIO_GETINFO_OLD:
240 		if (acpi_capm_get_info(&info))
241 			error = ENXIO;
242 		aiop = (apm_info_old_t)addr;
243 		aiop->ai_major = info.ai_major;
244 		aiop->ai_minor = info.ai_minor;
245 		aiop->ai_acline = info.ai_acline;
246 		aiop->ai_batt_stat = info.ai_batt_stat;
247 		aiop->ai_batt_life = info.ai_batt_life;
248 		aiop->ai_status = info.ai_status;
249 		break;
250 
251 	case APMIO_GETINFO:
252 		if (acpi_capm_get_info((apm_info_t)addr))
253 			error = ENXIO;
254 
255 		break;
256 
257 	case APMIO_GETPWSTATUS:
258 		if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr))
259 			error = ENXIO;
260 		break;
261 
262 	case APMIO_ENABLE:
263 		if (!(flag & FWRITE))
264 			return (EPERM);
265 		apm_softc.active = 1;
266 		break;
267 
268 	case APMIO_DISABLE:
269 		if (!(flag & FWRITE))
270 			return (EPERM);
271 		apm_softc.active = 0;
272 		break;
273 
274 	case APMIO_HALTCPU:
275 		break;
276 
277 	case APMIO_NOTHALTCPU:
278 		break;
279 
280 	case APMIO_DISPLAY:
281 		if (!(flag & FWRITE))
282 			return (EPERM);
283 		break;
284 
285 	case APMIO_BIOS:
286 		if (!(flag & FWRITE))
287 			return (EPERM);
288 		bzero(addr, sizeof(struct apm_bios_arg));
289 		break;
290 
291 	default:
292 		error = EINVAL;
293 		break;
294 	}
295 
296 	return (error);
297 }
298 
299 static int
300 apmwrite(dev_t dev, struct uio *uio, int ioflag)
301 {
302 
303 	return (uio->uio_resid);
304 }
305 
306 static int
307 apmpoll(dev_t dev, int events, struct thread *td)
308 {
309 	return (0);
310 }
311 
312 static void
313 acpi_capm_init(struct acpi_softc *sc)
314 {
315 
316         make_dev(&apm_cdevsw, 0, 0, 5, 0664, "apm");
317 }
318 
319 int
320 acpi_machdep_init(device_t dev)
321 {
322 	struct	acpi_softc *sc;
323 
324 	acpi_dev = dev;
325 	if ((sc = device_get_softc(acpi_dev)) == NULL) {
326 		return (ENXIO);
327 	}
328 
329 	acpi_capm_init(sc);
330 
331 	acpi_install_wakeup_handler(sc);
332 
333 	return (0);
334 }
335 
336