acpi_apm.c revision 105276
185556Siwasaki/*- 285556Siwasaki * Copyright (c) 2001 Mitsuru IWASAKI 385556Siwasaki * All rights reserved. 485556Siwasaki * 585556Siwasaki * Redistribution and use in source and binary forms, with or without 685556Siwasaki * modification, are permitted provided that the following conditions 785556Siwasaki * are met: 885556Siwasaki * 1. Redistributions of source code must retain the above copyright 985556Siwasaki * notice, this list of conditions and the following disclaimer. 1085556Siwasaki * 2. Redistributions in binary form must reproduce the above copyright 1185556Siwasaki * notice, this list of conditions and the following disclaimer in the 1285556Siwasaki * documentation and/or other materials provided with the distribution. 1385556Siwasaki * 1485556Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1585556Siwasaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1685556Siwasaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1785556Siwasaki * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1885556Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1985556Siwasaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2085556Siwasaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2185556Siwasaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2285556Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2385556Siwasaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2485556Siwasaki * SUCH DAMAGE. 2585556Siwasaki * 2685556Siwasaki * $FreeBSD: head/sys/i386/acpica/acpi_machdep.c 105276 2002-10-16 17:20:43Z jhb $ 2785556Siwasaki */ 2885556Siwasaki 2985556Siwasaki#include <sys/param.h> 3085556Siwasaki#include <sys/bus.h> 3185556Siwasaki#include <sys/conf.h> 3285556Siwasaki#include <sys/fcntl.h> 3385556Siwasaki#include <sys/uio.h> 3485556Siwasaki 3585556Siwasaki#include "acpi.h" 3685556Siwasaki 3785556Siwasaki#include <dev/acpica/acpivar.h> 3885556Siwasaki#include <dev/acpica/acpiio.h> 3985556Siwasaki 4085556Siwasakistatic device_t acpi_dev; 4185556Siwasaki 4285556Siwasaki/* 4385556Siwasaki * APM driver emulation 4485556Siwasaki */ 4585556Siwasaki 46105276Sjhb#if __FreeBSD_version < 500000 47105276Sjhb#include <sys/select.h> 48105276Sjhb#else 4985556Siwasaki#include <sys/selinfo.h> 50105276Sjhb#endif 5185556Siwasaki 5285556Siwasaki#include <machine/apm_bios.h> 5385556Siwasaki#include <machine/pc/bios.h> 5485556Siwasaki 5585556Siwasaki#include <i386/apm/apm.h> 5685556Siwasaki 5785556Siwasakistatic struct apm_softc apm_softc; 5885556Siwasaki 5985556Siwasakistatic d_open_t apmopen; 6085556Siwasakistatic d_close_t apmclose; 6185556Siwasakistatic d_write_t apmwrite; 6285556Siwasakistatic d_ioctl_t apmioctl; 6385556Siwasakistatic d_poll_t apmpoll; 6485556Siwasaki 6585556Siwasaki#define CDEV_MAJOR 39 6685556Siwasakistatic struct cdevsw apm_cdevsw = { 6785556Siwasaki /* open */ apmopen, 6885556Siwasaki /* close */ apmclose, 6985556Siwasaki /* read */ noread, 7085556Siwasaki /* write */ apmwrite, 7185556Siwasaki /* ioctl */ apmioctl, 7285556Siwasaki /* poll */ apmpoll, 7385556Siwasaki /* mmap */ nommap, 7485556Siwasaki /* strategy */ nostrategy, 7585556Siwasaki /* name */ "apm", 7685556Siwasaki /* maj */ CDEV_MAJOR, 7785556Siwasaki /* dump */ nodump, 7885556Siwasaki /* psize */ nopsize, 7985556Siwasaki /* flags */ 0, 8085556Siwasaki}; 8185556Siwasaki 8285556Siwasakistatic int 8385556Siwasakiacpi_capm_convert_battstate(struct acpi_battinfo *battp) 8485556Siwasaki{ 8585556Siwasaki int state; 8685556Siwasaki 8785556Siwasaki state = 0xff; /* XXX unknown */ 8885556Siwasaki 8985556Siwasaki if (battp->state & ACPI_BATT_STAT_DISCHARG) { 9085556Siwasaki if (battp->cap >= 50) { 9185556Siwasaki state = 0; /* high */ 9285556Siwasaki } else { 9385556Siwasaki state = 1; /* low */ 9485556Siwasaki } 9585556Siwasaki } 9685556Siwasaki if (battp->state & ACPI_BATT_STAT_CRITICAL) { 9785556Siwasaki state = 2; /* critical */ 9885556Siwasaki } 9985556Siwasaki if (battp->state & ACPI_BATT_STAT_CHARGING) { 10085556Siwasaki state = 3; /* charging */ 10185556Siwasaki } 10285556Siwasaki return (state); 10385556Siwasaki} 10485556Siwasaki 10585556Siwasakistatic int 10685556Siwasakiacpi_capm_convert_battflags(struct acpi_battinfo *battp) 10785556Siwasaki{ 10885556Siwasaki int flags; 10985556Siwasaki 11085556Siwasaki flags = 0; 11185556Siwasaki 11285556Siwasaki if (battp->cap >= 50) { 11385556Siwasaki flags |= APM_BATT_HIGH; 11485556Siwasaki } else { 11585556Siwasaki if (battp->state & ACPI_BATT_STAT_CRITICAL) { 11685556Siwasaki flags |= APM_BATT_CRITICAL; 11785556Siwasaki } else { 11885556Siwasaki flags |= APM_BATT_LOW; 11985556Siwasaki } 12085556Siwasaki } 12185556Siwasaki if (battp->state & ACPI_BATT_STAT_CHARGING) { 12285556Siwasaki flags |= APM_BATT_CHARGING; 12385556Siwasaki } 12485556Siwasaki if (battp->state == ACPI_BATT_STAT_NOT_PRESENT) { 12585556Siwasaki flags = APM_BATT_NOT_PRESENT; 12685556Siwasaki } 12785556Siwasaki 12885556Siwasaki return (flags); 12985556Siwasaki} 13085556Siwasaki 13185556Siwasakistatic int 13285556Siwasakiacpi_capm_get_info(apm_info_t aip) 13385556Siwasaki{ 13485556Siwasaki int acline; 13585556Siwasaki struct acpi_battinfo batt; 13685556Siwasaki 13785556Siwasaki aip->ai_infoversion = 1; 13885556Siwasaki aip->ai_major = 1; 13985556Siwasaki aip->ai_minor = 2; 14085556Siwasaki aip->ai_status = apm_softc.active; 14185556Siwasaki aip->ai_capabilities= 0xff00; /* XXX unknown */ 14285556Siwasaki 14385556Siwasaki if (acpi_acad_get_acline(&acline)) { 14485556Siwasaki aip->ai_acline = 0xff; /* unknown */ 14585556Siwasaki } else { 14685556Siwasaki aip->ai_acline = acline; /* on/off */ 14785556Siwasaki } 14885556Siwasaki 14985556Siwasaki if (acpi_battery_get_battinfo(-1, &batt)) { 15085556Siwasaki aip->ai_batt_stat = 0xff; /* unknown */ 15185556Siwasaki aip->ai_batt_life = 0xff; /* unknown */ 15285556Siwasaki aip->ai_batt_time = -1; /* unknown */ 15385556Siwasaki aip->ai_batteries = 0; 15485556Siwasaki } else { 15585556Siwasaki aip->ai_batt_stat = acpi_capm_convert_battstate(&batt); 15685556Siwasaki aip->ai_batt_life = batt.cap; 15785556Siwasaki aip->ai_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 15885556Siwasaki aip->ai_batteries = acpi_battery_get_units(); 15985556Siwasaki } 16085556Siwasaki 16185556Siwasaki return (0); 16285556Siwasaki} 16385556Siwasaki 16485556Siwasakistatic int 16585556Siwasakiacpi_capm_get_pwstatus(apm_pwstatus_t app) 16685556Siwasaki{ 16785556Siwasaki int batt_unit; 16885556Siwasaki int acline; 16985556Siwasaki struct acpi_battinfo batt; 17085556Siwasaki 17185556Siwasaki if (app->ap_device != PMDV_ALLDEV && 17285556Siwasaki (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) { 17385556Siwasaki return (1); 17485556Siwasaki } 17585556Siwasaki 17685556Siwasaki if (app->ap_device == PMDV_ALLDEV) { 17785556Siwasaki batt_unit = -1; /* all units */ 17885556Siwasaki } else { 17985556Siwasaki batt_unit = app->ap_device - PMDV_BATT0; 18085556Siwasaki } 18185556Siwasaki 18285556Siwasaki if (acpi_battery_get_battinfo(batt_unit, &batt)) { 18385556Siwasaki return (1); 18485556Siwasaki } 18585556Siwasaki 18685556Siwasaki app->ap_batt_stat = acpi_capm_convert_battstate(&batt); 18785556Siwasaki app->ap_batt_flag = acpi_capm_convert_battflags(&batt); 18885556Siwasaki app->ap_batt_life = batt.cap; 18985556Siwasaki app->ap_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 19085556Siwasaki 19185556Siwasaki if (acpi_acad_get_acline(&acline)) { 19285556Siwasaki app->ap_acline = 0xff; /* unknown */ 19385556Siwasaki } else { 19485556Siwasaki app->ap_acline = acline; /* on/off */ 19585556Siwasaki } 19685556Siwasaki 19785556Siwasaki return (0); 19885556Siwasaki} 19985556Siwasaki 20085556Siwasakistatic int 201104727Sjhbapmopen(dev_t dev, int flag, int fmt, d_thread_t *td) 20285556Siwasaki{ 20385556Siwasaki return (0); 20485556Siwasaki} 20585556Siwasaki 20685556Siwasakistatic int 207104727Sjhbapmclose(dev_t dev, int flag, int fmt, d_thread_t *td) 20885556Siwasaki{ 20985556Siwasaki return (0); 21085556Siwasaki} 21185556Siwasaki 21285556Siwasakistatic int 213104727Sjhbapmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td) 21485556Siwasaki{ 21585556Siwasaki int error = 0; 21685556Siwasaki struct acpi_softc *acpi_sc; 21785556Siwasaki struct apm_info info; 21885556Siwasaki apm_info_old_t aiop; 21985556Siwasaki 22085556Siwasaki if ((acpi_sc = device_get_softc(acpi_dev)) == NULL) { 22185556Siwasaki return (ENXIO); 22285556Siwasaki } 22385556Siwasaki 22485556Siwasaki switch (cmd) { 22585556Siwasaki case APMIO_SUSPEND: 22685556Siwasaki if (!(flag & FWRITE)) 22785556Siwasaki return (EPERM); 22885556Siwasaki if (apm_softc.active) 22985556Siwasaki acpi_SetSleepState(acpi_sc, acpi_sc->acpi_suspend_sx); 23085556Siwasaki else 23185556Siwasaki error = EINVAL; 23285556Siwasaki break; 23385556Siwasaki 23485556Siwasaki case APMIO_STANDBY: 23585556Siwasaki if (!(flag & FWRITE)) 23685556Siwasaki return (EPERM); 23785556Siwasaki if (apm_softc.active) 23885556Siwasaki acpi_SetSleepState(acpi_sc, acpi_sc->acpi_standby_sx); 23985556Siwasaki else 24085556Siwasaki error = EINVAL; 24185556Siwasaki break; 24285556Siwasaki 24385556Siwasaki case APMIO_GETINFO_OLD: 24485556Siwasaki if (acpi_capm_get_info(&info)) 24585556Siwasaki error = ENXIO; 24685556Siwasaki aiop = (apm_info_old_t)addr; 24785556Siwasaki aiop->ai_major = info.ai_major; 24885556Siwasaki aiop->ai_minor = info.ai_minor; 24985556Siwasaki aiop->ai_acline = info.ai_acline; 25085556Siwasaki aiop->ai_batt_stat = info.ai_batt_stat; 25185556Siwasaki aiop->ai_batt_life = info.ai_batt_life; 25285556Siwasaki aiop->ai_status = info.ai_status; 25385556Siwasaki break; 25485556Siwasaki 25585556Siwasaki case APMIO_GETINFO: 25685556Siwasaki if (acpi_capm_get_info((apm_info_t)addr)) 25785556Siwasaki error = ENXIO; 25885556Siwasaki 25985556Siwasaki break; 26085556Siwasaki 26185556Siwasaki case APMIO_GETPWSTATUS: 26285556Siwasaki if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr)) 26385556Siwasaki error = ENXIO; 26485556Siwasaki break; 26585556Siwasaki 26685556Siwasaki case APMIO_ENABLE: 26785556Siwasaki if (!(flag & FWRITE)) 26885556Siwasaki return (EPERM); 26985556Siwasaki apm_softc.active = 1; 27085556Siwasaki break; 27185556Siwasaki 27285556Siwasaki case APMIO_DISABLE: 27385556Siwasaki if (!(flag & FWRITE)) 27485556Siwasaki return (EPERM); 27585556Siwasaki apm_softc.active = 0; 27685556Siwasaki break; 27785556Siwasaki 27885556Siwasaki case APMIO_HALTCPU: 27985556Siwasaki break; 28085556Siwasaki 28185556Siwasaki case APMIO_NOTHALTCPU: 28285556Siwasaki break; 28385556Siwasaki 28485556Siwasaki case APMIO_DISPLAY: 28585556Siwasaki if (!(flag & FWRITE)) 28685556Siwasaki return (EPERM); 28785556Siwasaki break; 28885556Siwasaki 28985556Siwasaki case APMIO_BIOS: 29085556Siwasaki if (!(flag & FWRITE)) 29185556Siwasaki return (EPERM); 29285556Siwasaki bzero(addr, sizeof(struct apm_bios_arg)); 29385556Siwasaki break; 29485556Siwasaki 29585556Siwasaki default: 29685556Siwasaki error = EINVAL; 29785556Siwasaki break; 29885556Siwasaki } 29985556Siwasaki 30085556Siwasaki return (error); 30185556Siwasaki} 30285556Siwasaki 30385556Siwasakistatic int 30485556Siwasakiapmwrite(dev_t dev, struct uio *uio, int ioflag) 30585556Siwasaki{ 30685556Siwasaki 30785556Siwasaki return (uio->uio_resid); 30885556Siwasaki} 30985556Siwasaki 31085556Siwasakistatic int 311104727Sjhbapmpoll(dev_t dev, int events, d_thread_t *td) 31285556Siwasaki{ 31385556Siwasaki return (0); 31485556Siwasaki} 31585556Siwasaki 31685556Siwasakistatic void 31785556Siwasakiacpi_capm_init(struct acpi_softc *sc) 31885556Siwasaki{ 31985556Siwasaki 32085556Siwasaki make_dev(&apm_cdevsw, 0, 0, 5, 0664, "apm"); 32185556Siwasaki} 32285556Siwasaki 32385556Siwasakiint 32485556Siwasakiacpi_machdep_init(device_t dev) 32585556Siwasaki{ 32685556Siwasaki struct acpi_softc *sc; 32785556Siwasaki 32885556Siwasaki acpi_dev = dev; 32985556Siwasaki if ((sc = device_get_softc(acpi_dev)) == NULL) { 33085556Siwasaki return (ENXIO); 33185556Siwasaki } 33285556Siwasaki 333104223Sjhb /* 334104223Sjhb * XXX: Prevent the PnP BIOS code from interfering with 335104223Sjhb * our own scan of ISA devices. 336104223Sjhb */ 337104223Sjhb PnPBIOStable = NULL; 338104223Sjhb 33985556Siwasaki acpi_capm_init(sc); 34085556Siwasaki 34185556Siwasaki acpi_install_wakeup_handler(sc); 34285556Siwasaki 343103023Sjhb#ifdef APIC_IO 344103023Sjhb acpi_SetIntrModel(ACPI_INTR_APIC); 345103023Sjhb#endif 34685556Siwasaki return (0); 34785556Siwasaki} 34885556Siwasaki 349