acpi_apm.c revision 120156
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 120156 2003-09-17 08:47:39Z iwasaki $"); 29115681Sobrien 3085556Siwasaki#include <sys/param.h> 3185556Siwasaki#include <sys/bus.h> 3285556Siwasaki#include <sys/conf.h> 3385556Siwasaki#include <sys/fcntl.h> 3485556Siwasaki#include <sys/uio.h> 3585556Siwasaki 3685556Siwasaki#include "acpi.h" 3785556Siwasaki 3885556Siwasaki#include <dev/acpica/acpivar.h> 3985556Siwasaki#include <dev/acpica/acpiio.h> 4085556Siwasaki 4185556Siwasakistatic device_t acpi_dev; 4285556Siwasaki 4385556Siwasaki/* 4485556Siwasaki * APM driver emulation 4585556Siwasaki */ 4685556Siwasaki 47105276Sjhb#if __FreeBSD_version < 500000 48105276Sjhb#include <sys/select.h> 49105276Sjhb#else 5085556Siwasaki#include <sys/selinfo.h> 51105276Sjhb#endif 5285556Siwasaki 5385556Siwasaki#include <machine/apm_bios.h> 5485556Siwasaki#include <machine/pc/bios.h> 5585556Siwasaki 56114977Sjhb#if __FreeBSD_version < 500000 57114977Sjhb#include <i386/apm/apm.h> 58114977Sjhb#else 59112551Smdodd#include <i386/bios/apm.h> 60114977Sjhb#endif 6185556Siwasaki 6285556Siwasakistatic struct apm_softc apm_softc; 6385556Siwasaki 6485556Siwasakistatic d_open_t apmopen; 6585556Siwasakistatic d_close_t apmclose; 6685556Siwasakistatic d_write_t apmwrite; 6785556Siwasakistatic d_ioctl_t apmioctl; 6885556Siwasakistatic d_poll_t apmpoll; 6985556Siwasaki 7085556Siwasaki#define CDEV_MAJOR 39 7185556Siwasakistatic struct cdevsw apm_cdevsw = { 72111815Sphk .d_open = apmopen, 73111815Sphk .d_close = apmclose, 74111815Sphk .d_write = apmwrite, 75111815Sphk .d_ioctl = apmioctl, 76111815Sphk .d_poll = apmpoll, 77111815Sphk .d_name = "apm", 78111815Sphk .d_maj = CDEV_MAJOR, 7985556Siwasaki}; 8085556Siwasaki 81119944Sjhbstatic int intr_model = ACPI_INTR_PIC; 82119944Sjhb 8385556Siwasakistatic int 8485556Siwasakiacpi_capm_convert_battstate(struct acpi_battinfo *battp) 8585556Siwasaki{ 8685556Siwasaki int state; 8785556Siwasaki 8885556Siwasaki state = 0xff; /* XXX unknown */ 8985556Siwasaki 9085556Siwasaki if (battp->state & ACPI_BATT_STAT_DISCHARG) { 91119530Snjl if (battp->cap >= 50) 9285556Siwasaki state = 0; /* high */ 93119530Snjl else 9485556Siwasaki state = 1; /* low */ 9585556Siwasaki } 96119530Snjl if (battp->state & ACPI_BATT_STAT_CRITICAL) 9785556Siwasaki state = 2; /* critical */ 98119530Snjl if (battp->state & ACPI_BATT_STAT_CHARGING) 9985556Siwasaki state = 3; /* charging */ 100119530Snjl 101120156Siwasaki /* If still unknown, determine it based on the battery capacity. */ 102120156Siwasaki if (state == 0xff) { 103120156Siwasaki if (battp->cap >= 50) { 104120156Siwasaki state = 0; /* high */ 105120156Siwasaki } else { 106120156Siwasaki state = 1; /* low */ 107120156Siwasaki } 108120156Siwasaki } 109120156Siwasaki 11085556Siwasaki return (state); 11185556Siwasaki} 11285556Siwasaki 11385556Siwasakistatic int 11485556Siwasakiacpi_capm_convert_battflags(struct acpi_battinfo *battp) 11585556Siwasaki{ 11685556Siwasaki int flags; 11785556Siwasaki 11885556Siwasaki flags = 0; 11985556Siwasaki 12085556Siwasaki if (battp->cap >= 50) { 12185556Siwasaki flags |= APM_BATT_HIGH; 12285556Siwasaki } else { 123119530Snjl if (battp->state & ACPI_BATT_STAT_CRITICAL) 12485556Siwasaki flags |= APM_BATT_CRITICAL; 125119530Snjl else 12685556Siwasaki flags |= APM_BATT_LOW; 12785556Siwasaki } 128119530Snjl if (battp->state & ACPI_BATT_STAT_CHARGING) 12985556Siwasaki flags |= APM_BATT_CHARGING; 130119530Snjl if (battp->state == ACPI_BATT_STAT_NOT_PRESENT) 13185556Siwasaki flags = APM_BATT_NOT_PRESENT; 13285556Siwasaki 13385556Siwasaki return (flags); 13485556Siwasaki} 13585556Siwasaki 13685556Siwasakistatic int 13785556Siwasakiacpi_capm_get_info(apm_info_t aip) 13885556Siwasaki{ 13985556Siwasaki int acline; 14085556Siwasaki struct acpi_battinfo batt; 14185556Siwasaki 14285556Siwasaki aip->ai_infoversion = 1; 14385556Siwasaki aip->ai_major = 1; 14485556Siwasaki aip->ai_minor = 2; 14585556Siwasaki aip->ai_status = apm_softc.active; 14685556Siwasaki aip->ai_capabilities= 0xff00; /* XXX unknown */ 14785556Siwasaki 148119530Snjl if (acpi_acad_get_acline(&acline)) 14985556Siwasaki aip->ai_acline = 0xff; /* unknown */ 150119530Snjl else 15185556Siwasaki aip->ai_acline = acline; /* on/off */ 15285556Siwasaki 15385556Siwasaki if (acpi_battery_get_battinfo(-1, &batt)) { 15485556Siwasaki aip->ai_batt_stat = 0xff; /* unknown */ 15585556Siwasaki aip->ai_batt_life = 0xff; /* unknown */ 15685556Siwasaki aip->ai_batt_time = -1; /* unknown */ 15785556Siwasaki aip->ai_batteries = 0; 15885556Siwasaki } else { 15985556Siwasaki aip->ai_batt_stat = acpi_capm_convert_battstate(&batt); 16085556Siwasaki aip->ai_batt_life = batt.cap; 16185556Siwasaki aip->ai_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 16285556Siwasaki aip->ai_batteries = acpi_battery_get_units(); 16385556Siwasaki } 16485556Siwasaki 16585556Siwasaki return (0); 16685556Siwasaki} 16785556Siwasaki 16885556Siwasakistatic int 16985556Siwasakiacpi_capm_get_pwstatus(apm_pwstatus_t app) 17085556Siwasaki{ 17185556Siwasaki int batt_unit; 17285556Siwasaki int acline; 17385556Siwasaki struct acpi_battinfo batt; 17485556Siwasaki 17585556Siwasaki if (app->ap_device != PMDV_ALLDEV && 17685556Siwasaki (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) { 17785556Siwasaki return (1); 17885556Siwasaki } 17985556Siwasaki 180119530Snjl if (app->ap_device == PMDV_ALLDEV) 18185556Siwasaki batt_unit = -1; /* all units */ 182119530Snjl else 18385556Siwasaki batt_unit = app->ap_device - PMDV_BATT0; 18485556Siwasaki 185119530Snjl if (acpi_battery_get_battinfo(batt_unit, &batt)) 18685556Siwasaki return (1); 18785556Siwasaki 18885556Siwasaki app->ap_batt_stat = acpi_capm_convert_battstate(&batt); 18985556Siwasaki app->ap_batt_flag = acpi_capm_convert_battflags(&batt); 19085556Siwasaki app->ap_batt_life = batt.cap; 19185556Siwasaki app->ap_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 19285556Siwasaki 193119530Snjl if (acpi_acad_get_acline(&acline)) 19485556Siwasaki app->ap_acline = 0xff; /* unknown */ 195119530Snjl else 19685556Siwasaki app->ap_acline = acline; /* on/off */ 19785556Siwasaki 19885556Siwasaki return (0); 19985556Siwasaki} 20085556Siwasaki 20185556Siwasakistatic int 202104727Sjhbapmopen(dev_t dev, int flag, int fmt, d_thread_t *td) 20385556Siwasaki{ 20485556Siwasaki return (0); 20585556Siwasaki} 20685556Siwasaki 20785556Siwasakistatic int 208104727Sjhbapmclose(dev_t dev, int flag, int fmt, d_thread_t *td) 20985556Siwasaki{ 21085556Siwasaki return (0); 21185556Siwasaki} 21285556Siwasaki 21385556Siwasakistatic int 214104727Sjhbapmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td) 21585556Siwasaki{ 21685556Siwasaki int error = 0; 21785556Siwasaki struct acpi_softc *acpi_sc; 21885556Siwasaki struct apm_info info; 21985556Siwasaki apm_info_old_t aiop; 22085556Siwasaki 221119530Snjl if ((acpi_sc = device_get_softc(acpi_dev)) == NULL) 22285556Siwasaki return (ENXIO); 22385556Siwasaki 22485556Siwasaki switch (cmd) { 22585556Siwasaki case APMIO_SUSPEND: 226119530Snjl if ((flag & FWRITE) == 0) 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 case APMIO_STANDBY: 234119530Snjl if ((flag & FWRITE) == 0) 23585556Siwasaki return (EPERM); 23685556Siwasaki if (apm_softc.active) 23785556Siwasaki acpi_SetSleepState(acpi_sc, acpi_sc->acpi_standby_sx); 23885556Siwasaki else 23985556Siwasaki error = EINVAL; 24085556Siwasaki break; 24185556Siwasaki case APMIO_GETINFO_OLD: 24285556Siwasaki if (acpi_capm_get_info(&info)) 24385556Siwasaki error = ENXIO; 24485556Siwasaki aiop = (apm_info_old_t)addr; 24585556Siwasaki aiop->ai_major = info.ai_major; 24685556Siwasaki aiop->ai_minor = info.ai_minor; 24785556Siwasaki aiop->ai_acline = info.ai_acline; 24885556Siwasaki aiop->ai_batt_stat = info.ai_batt_stat; 24985556Siwasaki aiop->ai_batt_life = info.ai_batt_life; 25085556Siwasaki aiop->ai_status = info.ai_status; 25185556Siwasaki break; 25285556Siwasaki case APMIO_GETINFO: 25385556Siwasaki if (acpi_capm_get_info((apm_info_t)addr)) 25485556Siwasaki error = ENXIO; 25585556Siwasaki break; 25685556Siwasaki case APMIO_GETPWSTATUS: 25785556Siwasaki if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr)) 25885556Siwasaki error = ENXIO; 25985556Siwasaki break; 26085556Siwasaki case APMIO_ENABLE: 261119530Snjl if ((flag & FWRITE) == 0) 26285556Siwasaki return (EPERM); 26385556Siwasaki apm_softc.active = 1; 26485556Siwasaki break; 26585556Siwasaki case APMIO_DISABLE: 266119530Snjl if ((flag & FWRITE) == 0) 26785556Siwasaki return (EPERM); 26885556Siwasaki apm_softc.active = 0; 26985556Siwasaki break; 27085556Siwasaki case APMIO_HALTCPU: 27185556Siwasaki break; 27285556Siwasaki case APMIO_NOTHALTCPU: 27385556Siwasaki break; 27485556Siwasaki case APMIO_DISPLAY: 275119530Snjl if ((flag & FWRITE) == 0) 27685556Siwasaki return (EPERM); 27785556Siwasaki break; 27885556Siwasaki case APMIO_BIOS: 279119530Snjl if ((flag & FWRITE) == 0) 28085556Siwasaki return (EPERM); 28185556Siwasaki bzero(addr, sizeof(struct apm_bios_arg)); 28285556Siwasaki break; 28385556Siwasaki default: 28485556Siwasaki error = EINVAL; 28585556Siwasaki break; 28685556Siwasaki } 28785556Siwasaki 28885556Siwasaki return (error); 28985556Siwasaki} 29085556Siwasaki 29185556Siwasakistatic int 29285556Siwasakiapmwrite(dev_t dev, struct uio *uio, int ioflag) 29385556Siwasaki{ 29485556Siwasaki return (uio->uio_resid); 29585556Siwasaki} 29685556Siwasaki 29785556Siwasakistatic int 298104727Sjhbapmpoll(dev_t dev, int events, d_thread_t *td) 29985556Siwasaki{ 30085556Siwasaki return (0); 30185556Siwasaki} 30285556Siwasaki 30385556Siwasakistatic void 30485556Siwasakiacpi_capm_init(struct acpi_softc *sc) 30585556Siwasaki{ 30685556Siwasaki make_dev(&apm_cdevsw, 0, 0, 5, 0664, "apm"); 30785556Siwasaki} 30885556Siwasaki 30985556Siwasakiint 31085556Siwasakiacpi_machdep_init(device_t dev) 31185556Siwasaki{ 31285556Siwasaki struct acpi_softc *sc; 31385556Siwasaki 31485556Siwasaki acpi_dev = dev; 315119530Snjl if ((sc = device_get_softc(acpi_dev)) == NULL) 31685556Siwasaki return (ENXIO); 31785556Siwasaki 318104223Sjhb /* 319104223Sjhb * XXX: Prevent the PnP BIOS code from interfering with 320104223Sjhb * our own scan of ISA devices. 321104223Sjhb */ 322104223Sjhb PnPBIOStable = NULL; 323104223Sjhb 32485556Siwasaki acpi_capm_init(sc); 32585556Siwasaki 32685556Siwasaki acpi_install_wakeup_handler(sc); 32785556Siwasaki 328119944Sjhb if (intr_model != ACPI_INTR_PIC) 329119944Sjhb acpi_SetIntrModel(intr_model); 33085556Siwasaki return (0); 33185556Siwasaki} 332119944Sjhb 333119944Sjhbvoid 334119944Sjhbacpi_SetDefaultIntrModel(int model) 335119944Sjhb{ 336119944Sjhb 337119944Sjhb intr_model = model; 338119944Sjhb} 339