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