xref: /freebsd/sys/i386/acpica/acpi_machdep.c (revision 4b2eaea43fec8e8792be611dea204071a10b655a)
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 #if __FreeBSD_version < 500000
47 #include <sys/select.h>
48 #else
49 #include <sys/selinfo.h>
50 #endif
51 
52 #include <machine/apm_bios.h>
53 #include <machine/pc/bios.h>
54 
55 #include <i386/apm/apm.h>
56 
57 static struct apm_softc	apm_softc;
58 
59 static d_open_t apmopen;
60 static d_close_t apmclose;
61 static d_write_t apmwrite;
62 static d_ioctl_t apmioctl;
63 static d_poll_t apmpoll;
64 
65 #define CDEV_MAJOR 39
66 static struct cdevsw apm_cdevsw = {
67 	/* open */	apmopen,
68 	/* close */	apmclose,
69 	/* read */	noread,
70 	/* write */	apmwrite,
71 	/* ioctl */	apmioctl,
72 	/* poll */	apmpoll,
73 	/* mmap */	nommap,
74 	/* strategy */	nostrategy,
75 	/* name */	"apm",
76 	/* maj */	CDEV_MAJOR,
77 	/* dump */	nodump,
78 	/* psize */	nopsize,
79 	/* flags */	0,
80 };
81 
82 static int
83 acpi_capm_convert_battstate(struct  acpi_battinfo *battp)
84 {
85 	int	state;
86 
87 	state = 0xff;	/* XXX unknown */
88 
89 	if (battp->state & ACPI_BATT_STAT_DISCHARG) {
90 		if (battp->cap >= 50) {
91 			state = 0;	/* high */
92 		} else {
93 			state = 1;	/* low */
94 		}
95 	}
96 	if (battp->state & ACPI_BATT_STAT_CRITICAL) {
97 		state = 2;		/* critical */
98 	}
99 	if (battp->state & ACPI_BATT_STAT_CHARGING) {
100 		state = 3;		/* charging */
101 	}
102 	return (state);
103 }
104 
105 static int
106 acpi_capm_convert_battflags(struct  acpi_battinfo *battp)
107 {
108 	int	flags;
109 
110 	flags = 0;
111 
112 	if (battp->cap >= 50) {
113 		flags |= APM_BATT_HIGH;
114 	} else {
115 		if (battp->state & ACPI_BATT_STAT_CRITICAL) {
116 			flags |= APM_BATT_CRITICAL;
117 		} else {
118 			flags |= APM_BATT_LOW;
119 		}
120 	}
121 	if (battp->state & ACPI_BATT_STAT_CHARGING) {
122 		flags |= APM_BATT_CHARGING;
123 	}
124 	if (battp->state == ACPI_BATT_STAT_NOT_PRESENT) {
125 		flags = APM_BATT_NOT_PRESENT;
126 	}
127 
128 	return (flags);
129 }
130 
131 static int
132 acpi_capm_get_info(apm_info_t aip)
133 {
134 	int	acline;
135 	struct	acpi_battinfo batt;
136 
137 	aip->ai_infoversion = 1;
138 	aip->ai_major       = 1;
139 	aip->ai_minor       = 2;
140 	aip->ai_status      = apm_softc.active;
141 	aip->ai_capabilities= 0xff00;	/* XXX unknown */
142 
143 	if (acpi_acad_get_acline(&acline)) {
144 		aip->ai_acline = 0xff;		/* unknown */
145 	} else {
146 		aip->ai_acline = acline;	/* on/off */
147 	}
148 
149 	if (acpi_battery_get_battinfo(-1, &batt)) {
150 		aip->ai_batt_stat = 0xff;	/* unknown */
151 		aip->ai_batt_life = 0xff;	/* unknown */
152 		aip->ai_batt_time = -1;		/* unknown */
153 		aip->ai_batteries = 0;
154 	} else {
155 		aip->ai_batt_stat = acpi_capm_convert_battstate(&batt);
156 		aip->ai_batt_life = batt.cap;
157 		aip->ai_batt_time = (batt.min == -1) ? -1 : batt.min * 60;
158 		aip->ai_batteries = acpi_battery_get_units();
159 	}
160 
161 	return (0);
162 }
163 
164 static int
165 acpi_capm_get_pwstatus(apm_pwstatus_t app)
166 {
167 	int	batt_unit;
168 	int	acline;
169 	struct	acpi_battinfo batt;
170 
171 	if (app->ap_device != PMDV_ALLDEV &&
172 	    (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) {
173 		return (1);
174 	}
175 
176 	if (app->ap_device == PMDV_ALLDEV) {
177 		batt_unit = -1;			/* all units */
178 	} else {
179 		batt_unit = app->ap_device - PMDV_BATT0;
180 	}
181 
182 	if (acpi_battery_get_battinfo(batt_unit, &batt)) {
183 		return (1);
184 	}
185 
186 	app->ap_batt_stat = acpi_capm_convert_battstate(&batt);
187 	app->ap_batt_flag = acpi_capm_convert_battflags(&batt);
188 	app->ap_batt_life = batt.cap;
189 	app->ap_batt_time = (batt.min == -1) ? -1 : batt.min * 60;
190 
191 	if (acpi_acad_get_acline(&acline)) {
192 		app->ap_acline = 0xff;		/* unknown */
193 	} else {
194 		app->ap_acline = acline;	/* on/off */
195 	}
196 
197 	return (0);
198 }
199 
200 static int
201 apmopen(dev_t dev, int flag, int fmt, d_thread_t *td)
202 {
203 	return (0);
204 }
205 
206 static int
207 apmclose(dev_t dev, int flag, int fmt, d_thread_t *td)
208 {
209 	return (0);
210 }
211 
212 static int
213 apmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td)
214 {
215 	int	error = 0;
216 	struct	acpi_softc *acpi_sc;
217 	struct apm_info info;
218 	apm_info_old_t aiop;
219 
220 	if ((acpi_sc = device_get_softc(acpi_dev)) == NULL) {
221 		return (ENXIO);
222 	}
223 
224 	switch (cmd) {
225 	case APMIO_SUSPEND:
226 		if (!(flag & FWRITE))
227 			return (EPERM);
228 		if (apm_softc.active)
229 			acpi_SetSleepState(acpi_sc, acpi_sc->acpi_suspend_sx);
230 		else
231 			error = EINVAL;
232 		break;
233 
234 	case APMIO_STANDBY:
235 		if (!(flag & FWRITE))
236 			return (EPERM);
237 		if (apm_softc.active)
238 			acpi_SetSleepState(acpi_sc, acpi_sc->acpi_standby_sx);
239 		else
240 			error = EINVAL;
241 		break;
242 
243 	case APMIO_GETINFO_OLD:
244 		if (acpi_capm_get_info(&info))
245 			error = ENXIO;
246 		aiop = (apm_info_old_t)addr;
247 		aiop->ai_major = info.ai_major;
248 		aiop->ai_minor = info.ai_minor;
249 		aiop->ai_acline = info.ai_acline;
250 		aiop->ai_batt_stat = info.ai_batt_stat;
251 		aiop->ai_batt_life = info.ai_batt_life;
252 		aiop->ai_status = info.ai_status;
253 		break;
254 
255 	case APMIO_GETINFO:
256 		if (acpi_capm_get_info((apm_info_t)addr))
257 			error = ENXIO;
258 
259 		break;
260 
261 	case APMIO_GETPWSTATUS:
262 		if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr))
263 			error = ENXIO;
264 		break;
265 
266 	case APMIO_ENABLE:
267 		if (!(flag & FWRITE))
268 			return (EPERM);
269 		apm_softc.active = 1;
270 		break;
271 
272 	case APMIO_DISABLE:
273 		if (!(flag & FWRITE))
274 			return (EPERM);
275 		apm_softc.active = 0;
276 		break;
277 
278 	case APMIO_HALTCPU:
279 		break;
280 
281 	case APMIO_NOTHALTCPU:
282 		break;
283 
284 	case APMIO_DISPLAY:
285 		if (!(flag & FWRITE))
286 			return (EPERM);
287 		break;
288 
289 	case APMIO_BIOS:
290 		if (!(flag & FWRITE))
291 			return (EPERM);
292 		bzero(addr, sizeof(struct apm_bios_arg));
293 		break;
294 
295 	default:
296 		error = EINVAL;
297 		break;
298 	}
299 
300 	return (error);
301 }
302 
303 static int
304 apmwrite(dev_t dev, struct uio *uio, int ioflag)
305 {
306 
307 	return (uio->uio_resid);
308 }
309 
310 static int
311 apmpoll(dev_t dev, int events, d_thread_t *td)
312 {
313 	return (0);
314 }
315 
316 static void
317 acpi_capm_init(struct acpi_softc *sc)
318 {
319 
320         make_dev(&apm_cdevsw, 0, 0, 5, 0664, "apm");
321 }
322 
323 int
324 acpi_machdep_init(device_t dev)
325 {
326 	struct	acpi_softc *sc;
327 
328 	acpi_dev = dev;
329 	if ((sc = device_get_softc(acpi_dev)) == NULL) {
330 		return (ENXIO);
331 	}
332 
333 	/*
334 	 * XXX: Prevent the PnP BIOS code from interfering with
335 	 * our own scan of ISA devices.
336 	 */
337 	PnPBIOStable = NULL;
338 
339 	acpi_capm_init(sc);
340 
341 	acpi_install_wakeup_handler(sc);
342 
343 #ifdef SMP
344 	acpi_SetIntrModel(ACPI_INTR_APIC);
345 #endif
346 	return (0);
347 }
348 
349