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