acpi_machdep.c revision 115681
150276Speter/*-
250276Speter * Copyright (c) 2001 Mitsuru IWASAKI
350276Speter * All rights reserved.
450276Speter *
550276Speter * Redistribution and use in source and binary forms, with or without
650276Speter * modification, are permitted provided that the following conditions
750276Speter * are met:
850276Speter * 1. Redistributions of source code must retain the above copyright
950276Speter *    notice, this list of conditions and the following disclaimer.
1050276Speter * 2. Redistributions in binary form must reproduce the above copyright
1150276Speter *    notice, this list of conditions and the following disclaimer in the
1250276Speter *    documentation and/or other materials provided with the distribution.
1350276Speter *
1450276Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1550276Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1650276Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1750276Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1850276Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1950276Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2050276Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2150276Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2250276Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2350276Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2450276Speter * SUCH DAMAGE.
2550276Speter */
2650276Speter
2750276Speter#include <sys/cdefs.h>
2850276Speter__FBSDID("$FreeBSD: head/sys/i386/acpica/acpi_machdep.c 115681 2003-06-02 06:16:45Z obrien $");
2950276Speter
3050276Speter#include <sys/param.h>
3150276Speter#include <sys/bus.h>
3250276Speter#include <sys/conf.h>
3350276Speter#include <sys/fcntl.h>
3450276Speter#include <sys/uio.h>
3550276Speter
3650276Speter#include "acpi.h"
3750276Speter
3850276Speter#include <dev/acpica/acpivar.h>
3950276Speter#include <dev/acpica/acpiio.h>
4050276Speter
4150276Speterstatic device_t	acpi_dev;
4250276Speter
4350276Speter/*
4450276Speter * APM driver emulation
4550276Speter */
4650276Speter
4750276Speter#if __FreeBSD_version < 500000
4850276Speter#include <sys/select.h>
4950276Speter#else
5050276Speter#include <sys/selinfo.h>
5150276Speter#endif
5250276Speter
5350276Speter#include <machine/apm_bios.h>
5450276Speter#include <machine/pc/bios.h>
5550276Speter
5650276Speter#if __FreeBSD_version < 500000
5750276Speter#include <i386/apm/apm.h>
5850276Speter#else
5950276Speter#include <i386/bios/apm.h>
6050276Speter#endif
6150276Speter
6250276Speterstatic struct apm_softc	apm_softc;
6350276Speter
6450276Speterstatic d_open_t apmopen;
6550276Speterstatic d_close_t apmclose;
6650276Speterstatic d_write_t apmwrite;
6750276Speterstatic d_ioctl_t apmioctl;
6850276Speterstatic d_poll_t apmpoll;
6950276Speter
7050276Speter#define CDEV_MAJOR 39
7150276Speterstatic struct cdevsw apm_cdevsw = {
7250276Speter	.d_open =	apmopen,
7350276Speter	.d_close =	apmclose,
7450276Speter	.d_write =	apmwrite,
7550276Speter	.d_ioctl =	apmioctl,
7650276Speter	.d_poll =	apmpoll,
7750276Speter	.d_name =	"apm",
7850276Speter	.d_maj =	CDEV_MAJOR,
7950276Speter};
8050276Speter
8150276Speterstatic int
8250276Speteracpi_capm_convert_battstate(struct  acpi_battinfo *battp)
8350276Speter{
8450276Speter	int	state;
8550276Speter
8650276Speter	state = 0xff;	/* XXX unknown */
8750276Speter
8850276Speter	if (battp->state & ACPI_BATT_STAT_DISCHARG) {
8950276Speter		if (battp->cap >= 50) {
9050276Speter			state = 0;	/* high */
9150276Speter		} else {
9250276Speter			state = 1;	/* low */
9350276Speter		}
9450276Speter	}
9550276Speter	if (battp->state & ACPI_BATT_STAT_CRITICAL) {
9650276Speter		state = 2;		/* critical */
9750276Speter	}
9850276Speter	if (battp->state & ACPI_BATT_STAT_CHARGING) {
9950276Speter		state = 3;		/* charging */
10050276Speter	}
10150276Speter	return (state);
10250276Speter}
10350276Speter
10450276Speterstatic int
10550276Speteracpi_capm_convert_battflags(struct  acpi_battinfo *battp)
10650276Speter{
10750276Speter	int	flags;
10850276Speter
10950276Speter	flags = 0;
11050276Speter
11150276Speter	if (battp->cap >= 50) {
11250276Speter		flags |= APM_BATT_HIGH;
11350276Speter	} else {
11450276Speter		if (battp->state & ACPI_BATT_STAT_CRITICAL) {
11550276Speter			flags |= APM_BATT_CRITICAL;
11650276Speter		} else {
11750276Speter			flags |= APM_BATT_LOW;
11850276Speter		}
11950276Speter	}
12050276Speter	if (battp->state & ACPI_BATT_STAT_CHARGING) {
12150276Speter		flags |= APM_BATT_CHARGING;
12250276Speter	}
12350276Speter	if (battp->state == ACPI_BATT_STAT_NOT_PRESENT) {
12450276Speter		flags = APM_BATT_NOT_PRESENT;
12550276Speter	}
12650276Speter
12750276Speter	return (flags);
12850276Speter}
12950276Speter
13050276Speterstatic int
13150276Speteracpi_capm_get_info(apm_info_t aip)
13250276Speter{
13350276Speter	int	acline;
13450276Speter	struct	acpi_battinfo batt;
13550276Speter
13650276Speter	aip->ai_infoversion = 1;
13750276Speter	aip->ai_major       = 1;
13850276Speter	aip->ai_minor       = 2;
13950276Speter	aip->ai_status      = apm_softc.active;
14050276Speter	aip->ai_capabilities= 0xff00;	/* XXX unknown */
14150276Speter
14250276Speter	if (acpi_acad_get_acline(&acline)) {
14350276Speter		aip->ai_acline = 0xff;		/* unknown */
14450276Speter	} else {
14550276Speter		aip->ai_acline = acline;	/* on/off */
14650276Speter	}
14750276Speter
14850276Speter	if (acpi_battery_get_battinfo(-1, &batt)) {
14950276Speter		aip->ai_batt_stat = 0xff;	/* unknown */
15050276Speter		aip->ai_batt_life = 0xff;	/* unknown */
15150276Speter		aip->ai_batt_time = -1;		/* unknown */
15250276Speter		aip->ai_batteries = 0;
15350276Speter	} else {
15450276Speter		aip->ai_batt_stat = acpi_capm_convert_battstate(&batt);
15550276Speter		aip->ai_batt_life = batt.cap;
15650276Speter		aip->ai_batt_time = (batt.min == -1) ? -1 : batt.min * 60;
15750276Speter		aip->ai_batteries = acpi_battery_get_units();
15850276Speter	}
15950276Speter
16050276Speter	return (0);
16150276Speter}
16250276Speter
16350276Speterstatic int
16450276Speteracpi_capm_get_pwstatus(apm_pwstatus_t app)
16550276Speter{
16650276Speter	int	batt_unit;
16750276Speter	int	acline;
16850276Speter	struct	acpi_battinfo batt;
16950276Speter
17050276Speter	if (app->ap_device != PMDV_ALLDEV &&
17150276Speter	    (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) {
17250276Speter		return (1);
17350276Speter	}
17450276Speter
17550276Speter	if (app->ap_device == PMDV_ALLDEV) {
17650276Speter		batt_unit = -1;			/* all units */
17750276Speter	} else {
17850276Speter		batt_unit = app->ap_device - PMDV_BATT0;
17950276Speter	}
18050276Speter
18150276Speter	if (acpi_battery_get_battinfo(batt_unit, &batt)) {
18250276Speter		return (1);
18350276Speter	}
18450276Speter
18550276Speter	app->ap_batt_stat = acpi_capm_convert_battstate(&batt);
18650276Speter	app->ap_batt_flag = acpi_capm_convert_battflags(&batt);
18750276Speter	app->ap_batt_life = batt.cap;
18850276Speter	app->ap_batt_time = (batt.min == -1) ? -1 : batt.min * 60;
18950276Speter
19050276Speter	if (acpi_acad_get_acline(&acline)) {
19150276Speter		app->ap_acline = 0xff;		/* unknown */
19250276Speter	} else {
19350276Speter		app->ap_acline = acline;	/* on/off */
19450276Speter	}
19550276Speter
19650276Speter	return (0);
19750276Speter}
19850276Speter
19950276Speterstatic int
20050276Speterapmopen(dev_t dev, int flag, int fmt, d_thread_t *td)
20150276Speter{
20250276Speter	return (0);
20350276Speter}
20450276Speter
20550276Speterstatic int
20650276Speterapmclose(dev_t dev, int flag, int fmt, d_thread_t *td)
20750276Speter{
20850276Speter	return (0);
20950276Speter}
21050276Speter
21150276Speterstatic int
21250276Speterapmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td)
21350276Speter{
21450276Speter	int	error = 0;
21550276Speter	struct	acpi_softc *acpi_sc;
21650276Speter	struct apm_info info;
21750276Speter	apm_info_old_t aiop;
21850276Speter
21950276Speter	if ((acpi_sc = device_get_softc(acpi_dev)) == NULL) {
22050276Speter		return (ENXIO);
22150276Speter	}
22250276Speter
22350276Speter	switch (cmd) {
22450276Speter	case APMIO_SUSPEND:
22550276Speter		if (!(flag & FWRITE))
22650276Speter			return (EPERM);
22750276Speter		if (apm_softc.active)
22850276Speter			acpi_SetSleepState(acpi_sc, acpi_sc->acpi_suspend_sx);
22950276Speter		else
23050276Speter			error = EINVAL;
23150276Speter		break;
23250276Speter
23350276Speter	case APMIO_STANDBY:
23450276Speter		if (!(flag & FWRITE))
23550276Speter			return (EPERM);
23650276Speter		if (apm_softc.active)
23750276Speter			acpi_SetSleepState(acpi_sc, acpi_sc->acpi_standby_sx);
23850276Speter		else
23950276Speter			error = EINVAL;
24050276Speter		break;
24150276Speter
24250276Speter	case APMIO_GETINFO_OLD:
24350276Speter		if (acpi_capm_get_info(&info))
24450276Speter			error = ENXIO;
24550276Speter		aiop = (apm_info_old_t)addr;
24650276Speter		aiop->ai_major = info.ai_major;
24750276Speter		aiop->ai_minor = info.ai_minor;
24850276Speter		aiop->ai_acline = info.ai_acline;
24950276Speter		aiop->ai_batt_stat = info.ai_batt_stat;
25050276Speter		aiop->ai_batt_life = info.ai_batt_life;
25150276Speter		aiop->ai_status = info.ai_status;
25250276Speter		break;
25350276Speter
25450276Speter	case APMIO_GETINFO:
25550276Speter		if (acpi_capm_get_info((apm_info_t)addr))
25650276Speter			error = ENXIO;
25750276Speter
25850276Speter		break;
25950276Speter
26050276Speter	case APMIO_GETPWSTATUS:
26150276Speter		if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr))
26250276Speter			error = ENXIO;
26350276Speter		break;
26450276Speter
26550276Speter	case APMIO_ENABLE:
26650276Speter		if (!(flag & FWRITE))
26750276Speter			return (EPERM);
26850276Speter		apm_softc.active = 1;
26950276Speter		break;
27050276Speter
27150276Speter	case APMIO_DISABLE:
27250276Speter		if (!(flag & FWRITE))
27350276Speter			return (EPERM);
27450276Speter		apm_softc.active = 0;
27550276Speter		break;
27650276Speter
27750276Speter	case APMIO_HALTCPU:
27850276Speter		break;
27950276Speter
28050276Speter	case APMIO_NOTHALTCPU:
28150276Speter		break;
28250276Speter
28350276Speter	case APMIO_DISPLAY:
28450276Speter		if (!(flag & FWRITE))
28550276Speter			return (EPERM);
28650276Speter		break;
28750276Speter
28850276Speter	case APMIO_BIOS:
28950276Speter		if (!(flag & FWRITE))
29050276Speter			return (EPERM);
29150276Speter		bzero(addr, sizeof(struct apm_bios_arg));
29250276Speter		break;
29350276Speter
29450276Speter	default:
29550276Speter		error = EINVAL;
29650276Speter		break;
29750276Speter	}
29850276Speter
29950276Speter	return (error);
30050276Speter}
30150276Speter
30250276Speterstatic int
30350276Speterapmwrite(dev_t dev, struct uio *uio, int ioflag)
30450276Speter{
30550276Speter
30650276Speter	return (uio->uio_resid);
30750276Speter}
30850276Speter
30950276Speterstatic int
31050276Speterapmpoll(dev_t dev, int events, d_thread_t *td)
31150276Speter{
31250276Speter	return (0);
31350276Speter}
31450276Speter
31550276Speterstatic void
31650276Speteracpi_capm_init(struct acpi_softc *sc)
31750276Speter{
31850276Speter
31950276Speter        make_dev(&apm_cdevsw, 0, 0, 5, 0664, "apm");
32050276Speter}
32150276Speter
32250276Speterint
32350276Speteracpi_machdep_init(device_t dev)
32450276Speter{
32550276Speter	struct	acpi_softc *sc;
32650276Speter
32750276Speter	acpi_dev = dev;
32850276Speter	if ((sc = device_get_softc(acpi_dev)) == NULL) {
32950276Speter		return (ENXIO);
33050276Speter	}
33150276Speter
33250276Speter	/*
33350276Speter	 * XXX: Prevent the PnP BIOS code from interfering with
33450276Speter	 * our own scan of ISA devices.
33550276Speter	 */
33650276Speter	PnPBIOStable = NULL;
33750276Speter
33850276Speter	acpi_capm_init(sc);
33950276Speter
34050276Speter	acpi_install_wakeup_handler(sc);
34150276Speter
34250276Speter#ifdef SMP
34350276Speter	acpi_SetIntrModel(ACPI_INTR_APIC);
34450276Speter#endif
34550276Speter	return (0);
34650276Speter}
34750276Speter
34850276Speter