acpi_apm.c revision 121830
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 27115681Sobrien#include <sys/cdefs.h> 28115681Sobrien__FBSDID("$FreeBSD: head/sys/i386/acpica/acpi_machdep.c 121830 2003-11-01 00:18:29Z njl $"); 29115681Sobrien 3085556Siwasaki#include <sys/param.h> 3185556Siwasaki#include <sys/bus.h> 3285556Siwasaki#include <sys/conf.h> 3385556Siwasaki#include <sys/fcntl.h> 34121743Siwasaki#include <sys/kernel.h> 35121743Siwasaki#include <sys/sysctl.h> 3685556Siwasaki#include <sys/uio.h> 3785556Siwasaki 3885556Siwasaki#include "acpi.h" 3985556Siwasaki 4085556Siwasaki#include <dev/acpica/acpivar.h> 4185556Siwasaki#include <dev/acpica/acpiio.h> 4285556Siwasaki 4385556Siwasakistatic device_t acpi_dev; 4485556Siwasaki 4585556Siwasaki/* 4685556Siwasaki * APM driver emulation 4785556Siwasaki */ 4885556Siwasaki 49105276Sjhb#if __FreeBSD_version < 500000 50105276Sjhb#include <sys/select.h> 51105276Sjhb#else 5285556Siwasaki#include <sys/selinfo.h> 53105276Sjhb#endif 5485556Siwasaki 5585556Siwasaki#include <machine/apm_bios.h> 5685556Siwasaki#include <machine/pc/bios.h> 5785556Siwasaki 58114977Sjhb#if __FreeBSD_version < 500000 59114977Sjhb#include <i386/apm/apm.h> 60114977Sjhb#else 61112551Smdodd#include <i386/bios/apm.h> 62114977Sjhb#endif 6385556Siwasaki 64121830Snjlu_int32_t acpi_reset_video = 1; 65121830SnjlTUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video); 66121743Siwasaki 6785556Siwasakistatic struct apm_softc apm_softc; 6885556Siwasaki 6985556Siwasakistatic d_open_t apmopen; 7085556Siwasakistatic d_close_t apmclose; 7185556Siwasakistatic d_write_t apmwrite; 7285556Siwasakistatic d_ioctl_t apmioctl; 7385556Siwasakistatic d_poll_t apmpoll; 7485556Siwasaki 7585556Siwasaki#define CDEV_MAJOR 39 7685556Siwasakistatic struct cdevsw apm_cdevsw = { 77111815Sphk .d_open = apmopen, 78111815Sphk .d_close = apmclose, 79111815Sphk .d_write = apmwrite, 80111815Sphk .d_ioctl = apmioctl, 81111815Sphk .d_poll = apmpoll, 82111815Sphk .d_name = "apm", 83111815Sphk .d_maj = CDEV_MAJOR, 8485556Siwasaki}; 8585556Siwasaki 86119944Sjhbstatic int intr_model = ACPI_INTR_PIC; 87119944Sjhb 8885556Siwasakistatic int 8985556Siwasakiacpi_capm_convert_battstate(struct acpi_battinfo *battp) 9085556Siwasaki{ 9185556Siwasaki int state; 9285556Siwasaki 9385556Siwasaki state = 0xff; /* XXX unknown */ 9485556Siwasaki 9585556Siwasaki if (battp->state & ACPI_BATT_STAT_DISCHARG) { 96119530Snjl if (battp->cap >= 50) 9785556Siwasaki state = 0; /* high */ 98119530Snjl else 9985556Siwasaki state = 1; /* low */ 10085556Siwasaki } 101119530Snjl if (battp->state & ACPI_BATT_STAT_CRITICAL) 10285556Siwasaki state = 2; /* critical */ 103119530Snjl if (battp->state & ACPI_BATT_STAT_CHARGING) 10485556Siwasaki state = 3; /* charging */ 105119530Snjl 106120156Siwasaki /* If still unknown, determine it based on the battery capacity. */ 107120156Siwasaki if (state == 0xff) { 108120156Siwasaki if (battp->cap >= 50) { 109120156Siwasaki state = 0; /* high */ 110120156Siwasaki } else { 111120156Siwasaki state = 1; /* low */ 112120156Siwasaki } 113120156Siwasaki } 114120156Siwasaki 11585556Siwasaki return (state); 11685556Siwasaki} 11785556Siwasaki 11885556Siwasakistatic int 11985556Siwasakiacpi_capm_convert_battflags(struct acpi_battinfo *battp) 12085556Siwasaki{ 12185556Siwasaki int flags; 12285556Siwasaki 12385556Siwasaki flags = 0; 12485556Siwasaki 12585556Siwasaki if (battp->cap >= 50) { 12685556Siwasaki flags |= APM_BATT_HIGH; 12785556Siwasaki } else { 128119530Snjl if (battp->state & ACPI_BATT_STAT_CRITICAL) 12985556Siwasaki flags |= APM_BATT_CRITICAL; 130119530Snjl else 13185556Siwasaki flags |= APM_BATT_LOW; 13285556Siwasaki } 133119530Snjl if (battp->state & ACPI_BATT_STAT_CHARGING) 13485556Siwasaki flags |= APM_BATT_CHARGING; 135119530Snjl if (battp->state == ACPI_BATT_STAT_NOT_PRESENT) 13685556Siwasaki flags = APM_BATT_NOT_PRESENT; 13785556Siwasaki 13885556Siwasaki return (flags); 13985556Siwasaki} 14085556Siwasaki 14185556Siwasakistatic int 14285556Siwasakiacpi_capm_get_info(apm_info_t aip) 14385556Siwasaki{ 14485556Siwasaki int acline; 14585556Siwasaki struct acpi_battinfo batt; 14685556Siwasaki 14785556Siwasaki aip->ai_infoversion = 1; 14885556Siwasaki aip->ai_major = 1; 14985556Siwasaki aip->ai_minor = 2; 15085556Siwasaki aip->ai_status = apm_softc.active; 15185556Siwasaki aip->ai_capabilities= 0xff00; /* XXX unknown */ 15285556Siwasaki 153119530Snjl if (acpi_acad_get_acline(&acline)) 15485556Siwasaki aip->ai_acline = 0xff; /* unknown */ 155119530Snjl else 15685556Siwasaki aip->ai_acline = acline; /* on/off */ 15785556Siwasaki 15885556Siwasaki if (acpi_battery_get_battinfo(-1, &batt)) { 15985556Siwasaki aip->ai_batt_stat = 0xff; /* unknown */ 16085556Siwasaki aip->ai_batt_life = 0xff; /* unknown */ 16185556Siwasaki aip->ai_batt_time = -1; /* unknown */ 16285556Siwasaki aip->ai_batteries = 0; 16385556Siwasaki } else { 16485556Siwasaki aip->ai_batt_stat = acpi_capm_convert_battstate(&batt); 16585556Siwasaki aip->ai_batt_life = batt.cap; 16685556Siwasaki aip->ai_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 16785556Siwasaki aip->ai_batteries = acpi_battery_get_units(); 16885556Siwasaki } 16985556Siwasaki 17085556Siwasaki return (0); 17185556Siwasaki} 17285556Siwasaki 17385556Siwasakistatic int 17485556Siwasakiacpi_capm_get_pwstatus(apm_pwstatus_t app) 17585556Siwasaki{ 17685556Siwasaki int batt_unit; 17785556Siwasaki int acline; 17885556Siwasaki struct acpi_battinfo batt; 17985556Siwasaki 18085556Siwasaki if (app->ap_device != PMDV_ALLDEV && 18185556Siwasaki (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) { 18285556Siwasaki return (1); 18385556Siwasaki } 18485556Siwasaki 185119530Snjl if (app->ap_device == PMDV_ALLDEV) 18685556Siwasaki batt_unit = -1; /* all units */ 187119530Snjl else 18885556Siwasaki batt_unit = app->ap_device - PMDV_BATT0; 18985556Siwasaki 190119530Snjl if (acpi_battery_get_battinfo(batt_unit, &batt)) 19185556Siwasaki return (1); 19285556Siwasaki 19385556Siwasaki app->ap_batt_stat = acpi_capm_convert_battstate(&batt); 19485556Siwasaki app->ap_batt_flag = acpi_capm_convert_battflags(&batt); 19585556Siwasaki app->ap_batt_life = batt.cap; 19685556Siwasaki app->ap_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 19785556Siwasaki 198119530Snjl if (acpi_acad_get_acline(&acline)) 19985556Siwasaki app->ap_acline = 0xff; /* unknown */ 200119530Snjl else 20185556Siwasaki app->ap_acline = acline; /* on/off */ 20285556Siwasaki 20385556Siwasaki return (0); 20485556Siwasaki} 20585556Siwasaki 20685556Siwasakistatic int 207104727Sjhbapmopen(dev_t dev, int flag, int fmt, d_thread_t *td) 20885556Siwasaki{ 20985556Siwasaki return (0); 21085556Siwasaki} 21185556Siwasaki 21285556Siwasakistatic int 213104727Sjhbapmclose(dev_t dev, int flag, int fmt, d_thread_t *td) 21485556Siwasaki{ 21585556Siwasaki return (0); 21685556Siwasaki} 21785556Siwasaki 21885556Siwasakistatic int 219104727Sjhbapmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td) 22085556Siwasaki{ 22185556Siwasaki int error = 0; 22285556Siwasaki struct acpi_softc *acpi_sc; 22385556Siwasaki struct apm_info info; 22485556Siwasaki apm_info_old_t aiop; 22585556Siwasaki 226119530Snjl if ((acpi_sc = device_get_softc(acpi_dev)) == NULL) 22785556Siwasaki return (ENXIO); 22885556Siwasaki 22985556Siwasaki switch (cmd) { 23085556Siwasaki case APMIO_SUSPEND: 231119530Snjl if ((flag & FWRITE) == 0) 23285556Siwasaki return (EPERM); 23385556Siwasaki if (apm_softc.active) 23485556Siwasaki acpi_SetSleepState(acpi_sc, acpi_sc->acpi_suspend_sx); 23585556Siwasaki else 23685556Siwasaki error = EINVAL; 23785556Siwasaki break; 23885556Siwasaki case APMIO_STANDBY: 239119530Snjl if ((flag & FWRITE) == 0) 24085556Siwasaki return (EPERM); 24185556Siwasaki if (apm_softc.active) 24285556Siwasaki acpi_SetSleepState(acpi_sc, acpi_sc->acpi_standby_sx); 24385556Siwasaki else 24485556Siwasaki error = EINVAL; 24585556Siwasaki break; 24685556Siwasaki case APMIO_GETINFO_OLD: 24785556Siwasaki if (acpi_capm_get_info(&info)) 24885556Siwasaki error = ENXIO; 24985556Siwasaki aiop = (apm_info_old_t)addr; 25085556Siwasaki aiop->ai_major = info.ai_major; 25185556Siwasaki aiop->ai_minor = info.ai_minor; 25285556Siwasaki aiop->ai_acline = info.ai_acline; 25385556Siwasaki aiop->ai_batt_stat = info.ai_batt_stat; 25485556Siwasaki aiop->ai_batt_life = info.ai_batt_life; 25585556Siwasaki aiop->ai_status = info.ai_status; 25685556Siwasaki break; 25785556Siwasaki case APMIO_GETINFO: 25885556Siwasaki if (acpi_capm_get_info((apm_info_t)addr)) 25985556Siwasaki error = ENXIO; 26085556Siwasaki break; 26185556Siwasaki case APMIO_GETPWSTATUS: 26285556Siwasaki if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr)) 26385556Siwasaki error = ENXIO; 26485556Siwasaki break; 26585556Siwasaki case APMIO_ENABLE: 266119530Snjl if ((flag & FWRITE) == 0) 26785556Siwasaki return (EPERM); 26885556Siwasaki apm_softc.active = 1; 26985556Siwasaki break; 27085556Siwasaki case APMIO_DISABLE: 271119530Snjl if ((flag & FWRITE) == 0) 27285556Siwasaki return (EPERM); 27385556Siwasaki apm_softc.active = 0; 27485556Siwasaki break; 27585556Siwasaki case APMIO_HALTCPU: 27685556Siwasaki break; 27785556Siwasaki case APMIO_NOTHALTCPU: 27885556Siwasaki break; 27985556Siwasaki case APMIO_DISPLAY: 280119530Snjl if ((flag & FWRITE) == 0) 28185556Siwasaki return (EPERM); 28285556Siwasaki break; 28385556Siwasaki case APMIO_BIOS: 284119530Snjl if ((flag & FWRITE) == 0) 28585556Siwasaki return (EPERM); 28685556Siwasaki bzero(addr, sizeof(struct apm_bios_arg)); 28785556Siwasaki break; 28885556Siwasaki default: 28985556Siwasaki error = EINVAL; 29085556Siwasaki break; 29185556Siwasaki } 29285556Siwasaki 29385556Siwasaki return (error); 29485556Siwasaki} 29585556Siwasaki 29685556Siwasakistatic int 29785556Siwasakiapmwrite(dev_t dev, struct uio *uio, int ioflag) 29885556Siwasaki{ 29985556Siwasaki return (uio->uio_resid); 30085556Siwasaki} 30185556Siwasaki 30285556Siwasakistatic int 303104727Sjhbapmpoll(dev_t dev, int events, d_thread_t *td) 30485556Siwasaki{ 30585556Siwasaki return (0); 30685556Siwasaki} 30785556Siwasaki 30885556Siwasakistatic void 30985556Siwasakiacpi_capm_init(struct acpi_softc *sc) 31085556Siwasaki{ 31185556Siwasaki make_dev(&apm_cdevsw, 0, 0, 5, 0664, "apm"); 31285556Siwasaki} 31385556Siwasaki 31485556Siwasakiint 31585556Siwasakiacpi_machdep_init(device_t dev) 31685556Siwasaki{ 31785556Siwasaki struct acpi_softc *sc; 31885556Siwasaki 31985556Siwasaki acpi_dev = dev; 320119530Snjl if ((sc = device_get_softc(acpi_dev)) == NULL) 32185556Siwasaki return (ENXIO); 32285556Siwasaki 323104223Sjhb /* 324104223Sjhb * XXX: Prevent the PnP BIOS code from interfering with 325104223Sjhb * our own scan of ISA devices. 326104223Sjhb */ 327104223Sjhb PnPBIOStable = NULL; 328104223Sjhb 32985556Siwasaki acpi_capm_init(sc); 33085556Siwasaki 33185556Siwasaki acpi_install_wakeup_handler(sc); 33285556Siwasaki 333119944Sjhb if (intr_model != ACPI_INTR_PIC) 334119944Sjhb acpi_SetIntrModel(intr_model); 335121743Siwasaki 336121830Snjl SYSCTL_ADD_UINT(&sc->acpi_sysctl_ctx, 337121830Snjl SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, 338121830Snjl "reset_video", CTLFLAG_RD | CTLFLAG_RW, &acpi_reset_video, 0, 339121830Snjl "Call the VESA reset BIOS vector on the resume path"); 340121743Siwasaki 34185556Siwasaki return (0); 34285556Siwasaki} 343119944Sjhb 344119944Sjhbvoid 345119944Sjhbacpi_SetDefaultIntrModel(int model) 346119944Sjhb{ 347119944Sjhb 348119944Sjhb intr_model = model; 349119944Sjhb} 350