acpi_apm.c revision 130585
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 130585 2004-06-16 09:47:26Z phk $"); 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#include <dev/acpica/acpivar.h> 4085556Siwasaki#include <dev/acpica/acpiio.h> 4185556Siwasaki 4285556Siwasakistatic device_t acpi_dev; 4385556Siwasaki 4485556Siwasaki/* 4585556Siwasaki * APM driver emulation 4685556Siwasaki */ 4785556Siwasaki 4885556Siwasaki#include <sys/selinfo.h> 4985556Siwasaki 5085556Siwasaki#include <machine/apm_bios.h> 5185556Siwasaki#include <machine/pc/bios.h> 5285556Siwasaki 53112551Smdodd#include <i386/bios/apm.h> 5485556Siwasaki 55128975Snjluint32_t acpi_reset_video = 1; 56121830SnjlTUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video); 57121743Siwasaki 58128975Snjlstatic int intr_model = ACPI_INTR_PIC; 5985556Siwasakistatic struct apm_softc apm_softc; 6085556Siwasaki 6185556Siwasakistatic d_open_t apmopen; 6285556Siwasakistatic d_close_t apmclose; 6385556Siwasakistatic d_write_t apmwrite; 6485556Siwasakistatic d_ioctl_t apmioctl; 6585556Siwasakistatic d_poll_t apmpoll; 6685556Siwasaki 6785556Siwasakistatic struct cdevsw apm_cdevsw = { 68126080Sphk .d_version = D_VERSION, 69126080Sphk .d_flags = D_NEEDGIANT, 70111815Sphk .d_open = apmopen, 71111815Sphk .d_close = apmclose, 72111815Sphk .d_write = apmwrite, 73111815Sphk .d_ioctl = apmioctl, 74111815Sphk .d_poll = apmpoll, 75111815Sphk .d_name = "apm", 7685556Siwasaki}; 7785556Siwasaki 7885556Siwasakistatic int 7985556Siwasakiacpi_capm_convert_battstate(struct acpi_battinfo *battp) 8085556Siwasaki{ 8185556Siwasaki int state; 8285556Siwasaki 8385556Siwasaki state = 0xff; /* XXX unknown */ 8485556Siwasaki 8585556Siwasaki if (battp->state & ACPI_BATT_STAT_DISCHARG) { 86119530Snjl if (battp->cap >= 50) 8785556Siwasaki state = 0; /* high */ 88119530Snjl else 8985556Siwasaki state = 1; /* low */ 9085556Siwasaki } 91119530Snjl if (battp->state & ACPI_BATT_STAT_CRITICAL) 9285556Siwasaki state = 2; /* critical */ 93119530Snjl if (battp->state & ACPI_BATT_STAT_CHARGING) 9485556Siwasaki state = 3; /* charging */ 95119530Snjl 96120156Siwasaki /* If still unknown, determine it based on the battery capacity. */ 97120156Siwasaki if (state == 0xff) { 98128975Snjl if (battp->cap >= 50) 99120156Siwasaki state = 0; /* high */ 100128975Snjl else 101120156Siwasaki state = 1; /* low */ 102120156Siwasaki } 103120156Siwasaki 10485556Siwasaki return (state); 10585556Siwasaki} 10685556Siwasaki 10785556Siwasakistatic int 10885556Siwasakiacpi_capm_convert_battflags(struct acpi_battinfo *battp) 10985556Siwasaki{ 11085556Siwasaki int flags; 11185556Siwasaki 11285556Siwasaki flags = 0; 11385556Siwasaki 114128975Snjl if (battp->cap >= 50) 11585556Siwasaki flags |= APM_BATT_HIGH; 116128975Snjl else { 117119530Snjl if (battp->state & ACPI_BATT_STAT_CRITICAL) 11885556Siwasaki flags |= APM_BATT_CRITICAL; 119119530Snjl else 12085556Siwasaki flags |= APM_BATT_LOW; 12185556Siwasaki } 122119530Snjl if (battp->state & ACPI_BATT_STAT_CHARGING) 12385556Siwasaki flags |= APM_BATT_CHARGING; 124119530Snjl if (battp->state == ACPI_BATT_STAT_NOT_PRESENT) 12585556Siwasaki flags = APM_BATT_NOT_PRESENT; 12685556Siwasaki 12785556Siwasaki return (flags); 12885556Siwasaki} 12985556Siwasaki 13085556Siwasakistatic int 13185556Siwasakiacpi_capm_get_info(apm_info_t aip) 13285556Siwasaki{ 13385556Siwasaki int acline; 13485556Siwasaki struct acpi_battinfo batt; 13585556Siwasaki 13685556Siwasaki aip->ai_infoversion = 1; 13785556Siwasaki aip->ai_major = 1; 13885556Siwasaki aip->ai_minor = 2; 13985556Siwasaki aip->ai_status = apm_softc.active; 14085556Siwasaki aip->ai_capabilities= 0xff00; /* XXX unknown */ 14185556Siwasaki 142119530Snjl if (acpi_acad_get_acline(&acline)) 14385556Siwasaki aip->ai_acline = 0xff; /* unknown */ 144119530Snjl else 14585556Siwasaki aip->ai_acline = acline; /* on/off */ 14685556Siwasaki 14785556Siwasaki if (acpi_battery_get_battinfo(-1, &batt)) { 14885556Siwasaki aip->ai_batt_stat = 0xff; /* unknown */ 14985556Siwasaki aip->ai_batt_life = 0xff; /* unknown */ 15085556Siwasaki aip->ai_batt_time = -1; /* unknown */ 15185556Siwasaki aip->ai_batteries = 0; 15285556Siwasaki } else { 15385556Siwasaki aip->ai_batt_stat = acpi_capm_convert_battstate(&batt); 15485556Siwasaki aip->ai_batt_life = batt.cap; 15585556Siwasaki aip->ai_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 15685556Siwasaki aip->ai_batteries = acpi_battery_get_units(); 15785556Siwasaki } 15885556Siwasaki 15985556Siwasaki return (0); 16085556Siwasaki} 16185556Siwasaki 16285556Siwasakistatic int 16385556Siwasakiacpi_capm_get_pwstatus(apm_pwstatus_t app) 16485556Siwasaki{ 16585556Siwasaki int batt_unit; 16685556Siwasaki int acline; 16785556Siwasaki struct acpi_battinfo batt; 16885556Siwasaki 16985556Siwasaki if (app->ap_device != PMDV_ALLDEV && 170128975Snjl (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) 17185556Siwasaki return (1); 17285556Siwasaki 173119530Snjl if (app->ap_device == PMDV_ALLDEV) 17485556Siwasaki batt_unit = -1; /* all units */ 175119530Snjl else 17685556Siwasaki batt_unit = app->ap_device - PMDV_BATT0; 17785556Siwasaki 178119530Snjl if (acpi_battery_get_battinfo(batt_unit, &batt)) 17985556Siwasaki return (1); 18085556Siwasaki 18185556Siwasaki app->ap_batt_stat = acpi_capm_convert_battstate(&batt); 18285556Siwasaki app->ap_batt_flag = acpi_capm_convert_battflags(&batt); 18385556Siwasaki app->ap_batt_life = batt.cap; 18485556Siwasaki app->ap_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 18585556Siwasaki 186119530Snjl if (acpi_acad_get_acline(&acline)) 18785556Siwasaki app->ap_acline = 0xff; /* unknown */ 188119530Snjl else 18985556Siwasaki app->ap_acline = acline; /* on/off */ 19085556Siwasaki 19185556Siwasaki return (0); 19285556Siwasaki} 19385556Siwasaki 19485556Siwasakistatic int 195130585Sphkapmopen(struct cdev *dev, int flag, int fmt, d_thread_t *td) 19685556Siwasaki{ 19785556Siwasaki return (0); 19885556Siwasaki} 19985556Siwasaki 20085556Siwasakistatic int 201130585Sphkapmclose(struct cdev *dev, int flag, int fmt, d_thread_t *td) 20285556Siwasaki{ 20385556Siwasaki return (0); 20485556Siwasaki} 20585556Siwasaki 20685556Siwasakistatic int 207130585Sphkapmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td) 20885556Siwasaki{ 20985556Siwasaki int error = 0; 21085556Siwasaki struct acpi_softc *acpi_sc; 21185556Siwasaki struct apm_info info; 21285556Siwasaki apm_info_old_t aiop; 21385556Siwasaki 214128508Snjl acpi_sc = device_get_softc(acpi_dev); 21585556Siwasaki 21685556Siwasaki switch (cmd) { 21785556Siwasaki case APMIO_SUSPEND: 218119530Snjl if ((flag & FWRITE) == 0) 21985556Siwasaki return (EPERM); 22085556Siwasaki if (apm_softc.active) 22185556Siwasaki acpi_SetSleepState(acpi_sc, acpi_sc->acpi_suspend_sx); 22285556Siwasaki else 22385556Siwasaki error = EINVAL; 22485556Siwasaki break; 22585556Siwasaki case APMIO_STANDBY: 226119530Snjl if ((flag & FWRITE) == 0) 22785556Siwasaki return (EPERM); 22885556Siwasaki if (apm_softc.active) 22985556Siwasaki acpi_SetSleepState(acpi_sc, acpi_sc->acpi_standby_sx); 23085556Siwasaki else 23185556Siwasaki error = EINVAL; 23285556Siwasaki break; 23385556Siwasaki case APMIO_GETINFO_OLD: 23485556Siwasaki if (acpi_capm_get_info(&info)) 23585556Siwasaki error = ENXIO; 23685556Siwasaki aiop = (apm_info_old_t)addr; 23785556Siwasaki aiop->ai_major = info.ai_major; 23885556Siwasaki aiop->ai_minor = info.ai_minor; 23985556Siwasaki aiop->ai_acline = info.ai_acline; 24085556Siwasaki aiop->ai_batt_stat = info.ai_batt_stat; 24185556Siwasaki aiop->ai_batt_life = info.ai_batt_life; 24285556Siwasaki aiop->ai_status = info.ai_status; 24385556Siwasaki break; 24485556Siwasaki case APMIO_GETINFO: 24585556Siwasaki if (acpi_capm_get_info((apm_info_t)addr)) 24685556Siwasaki error = ENXIO; 24785556Siwasaki break; 24885556Siwasaki case APMIO_GETPWSTATUS: 24985556Siwasaki if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr)) 25085556Siwasaki error = ENXIO; 25185556Siwasaki break; 25285556Siwasaki case APMIO_ENABLE: 253119530Snjl if ((flag & FWRITE) == 0) 25485556Siwasaki return (EPERM); 25585556Siwasaki apm_softc.active = 1; 25685556Siwasaki break; 25785556Siwasaki case APMIO_DISABLE: 258119530Snjl if ((flag & FWRITE) == 0) 25985556Siwasaki return (EPERM); 26085556Siwasaki apm_softc.active = 0; 26185556Siwasaki break; 26285556Siwasaki case APMIO_HALTCPU: 26385556Siwasaki break; 26485556Siwasaki case APMIO_NOTHALTCPU: 26585556Siwasaki break; 26685556Siwasaki case APMIO_DISPLAY: 267119530Snjl if ((flag & FWRITE) == 0) 26885556Siwasaki return (EPERM); 26985556Siwasaki break; 27085556Siwasaki case APMIO_BIOS: 271119530Snjl if ((flag & FWRITE) == 0) 27285556Siwasaki return (EPERM); 27385556Siwasaki bzero(addr, sizeof(struct apm_bios_arg)); 27485556Siwasaki break; 27585556Siwasaki default: 27685556Siwasaki error = EINVAL; 27785556Siwasaki break; 27885556Siwasaki } 27985556Siwasaki 28085556Siwasaki return (error); 28185556Siwasaki} 28285556Siwasaki 28385556Siwasakistatic int 284130585Sphkapmwrite(struct cdev *dev, struct uio *uio, int ioflag) 28585556Siwasaki{ 28685556Siwasaki return (uio->uio_resid); 28785556Siwasaki} 28885556Siwasaki 28985556Siwasakistatic int 290130585Sphkapmpoll(struct cdev *dev, int events, d_thread_t *td) 29185556Siwasaki{ 29285556Siwasaki return (0); 29385556Siwasaki} 29485556Siwasaki 29585556Siwasakistatic void 29685556Siwasakiacpi_capm_init(struct acpi_softc *sc) 29785556Siwasaki{ 29885556Siwasaki make_dev(&apm_cdevsw, 0, 0, 5, 0664, "apm"); 29985556Siwasaki} 30085556Siwasaki 30185556Siwasakiint 30285556Siwasakiacpi_machdep_init(device_t dev) 30385556Siwasaki{ 30485556Siwasaki struct acpi_softc *sc; 30585556Siwasaki 30685556Siwasaki acpi_dev = dev; 307128508Snjl sc = device_get_softc(acpi_dev); 30885556Siwasaki 30985556Siwasaki acpi_capm_init(sc); 31085556Siwasaki 31185556Siwasaki acpi_install_wakeup_handler(sc); 31285556Siwasaki 313128932Sjhb if (intr_model == ACPI_INTR_PIC) 314128932Sjhb BUS_CONFIG_INTR(dev, AcpiGbl_FADT->SciInt, INTR_TRIGGER_LEVEL, 315128932Sjhb INTR_POLARITY_LOW); 316128932Sjhb else 317119944Sjhb acpi_SetIntrModel(intr_model); 318121743Siwasaki 319121830Snjl SYSCTL_ADD_UINT(&sc->acpi_sysctl_ctx, 320121830Snjl SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, 321121830Snjl "reset_video", CTLFLAG_RD | CTLFLAG_RW, &acpi_reset_video, 0, 322121830Snjl "Call the VESA reset BIOS vector on the resume path"); 323121743Siwasaki 32485556Siwasaki return (0); 32585556Siwasaki} 326119944Sjhb 327119944Sjhbvoid 328119944Sjhbacpi_SetDefaultIntrModel(int model) 329119944Sjhb{ 330119944Sjhb 331119944Sjhb intr_model = model; 332119944Sjhb} 333