acpi_apm.c revision 168191
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 168191 2007-03-31 23:23:42Z jhb $"); 29115681Sobrien 3085556Siwasaki#include <sys/param.h> 3185556Siwasaki#include <sys/bus.h> 32168191Sjhb#include <sys/condvar.h> 3385556Siwasaki#include <sys/conf.h> 3485556Siwasaki#include <sys/fcntl.h> 35121743Siwasaki#include <sys/kernel.h> 36121743Siwasaki#include <sys/sysctl.h> 3785556Siwasaki#include <sys/uio.h> 38131312Snjl#include <vm/vm.h> 39131312Snjl#include <vm/pmap.h> 4085556Siwasaki 41150003Sobrien#include <contrib/dev/acpica/acpi.h> 4285556Siwasaki#include <dev/acpica/acpivar.h> 4385556Siwasaki#include <dev/acpica/acpiio.h> 4485556Siwasaki 4585556Siwasaki/* 4685556Siwasaki * APM driver emulation 4785556Siwasaki */ 4885556Siwasaki 4985556Siwasaki#include <sys/selinfo.h> 5085556Siwasaki 5185556Siwasaki#include <machine/apm_bios.h> 5285556Siwasaki#include <machine/pc/bios.h> 5385556Siwasaki 54112551Smdodd#include <i386/bios/apm.h> 5585556Siwasaki 56159477SnjlSYSCTL_DECL(_debug_acpi); 57159477Snjl 58159409Snjluint32_t acpi_resume_beep; 59159477SnjlTUNABLE_INT("debug.acpi.resume_beep", &acpi_resume_beep); 60159477SnjlSYSCTL_UINT(_debug_acpi, OID_AUTO, resume_beep, CTLFLAG_RW, &acpi_resume_beep, 61159477Snjl 0, "Beep the PC speaker when resuming"); 62159409Snjluint32_t acpi_reset_video; 63121830SnjlTUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video); 64121743Siwasaki 65128975Snjlstatic int intr_model = ACPI_INTR_PIC; 66132619Snjlstatic int apm_active; 6785556Siwasaki 6885556Siwasakistatic d_open_t apmopen; 6985556Siwasakistatic d_close_t apmclose; 7085556Siwasakistatic d_write_t apmwrite; 7185556Siwasakistatic d_ioctl_t apmioctl; 7285556Siwasakistatic d_poll_t apmpoll; 7385556Siwasaki 7485556Siwasakistatic struct cdevsw apm_cdevsw = { 75126080Sphk .d_version = D_VERSION, 76111815Sphk .d_open = apmopen, 77111815Sphk .d_close = apmclose, 78111815Sphk .d_write = apmwrite, 79111815Sphk .d_ioctl = apmioctl, 80111815Sphk .d_poll = apmpoll, 81111815Sphk .d_name = "apm", 8285556Siwasaki}; 8385556Siwasaki 8485556Siwasakistatic int 8585556Siwasakiacpi_capm_convert_battstate(struct acpi_battinfo *battp) 8685556Siwasaki{ 8785556Siwasaki int state; 8885556Siwasaki 89131218Simp state = APM_UNKNOWN; 9085556Siwasaki 9185556Siwasaki if (battp->state & ACPI_BATT_STAT_DISCHARG) { 92119530Snjl if (battp->cap >= 50) 9385556Siwasaki state = 0; /* high */ 94119530Snjl else 9585556Siwasaki state = 1; /* low */ 9685556Siwasaki } 97119530Snjl if (battp->state & ACPI_BATT_STAT_CRITICAL) 9885556Siwasaki state = 2; /* critical */ 99119530Snjl if (battp->state & ACPI_BATT_STAT_CHARGING) 10085556Siwasaki state = 3; /* charging */ 101119530Snjl 102120156Siwasaki /* If still unknown, determine it based on the battery capacity. */ 103131218Simp if (state == APM_UNKNOWN) { 104128975Snjl if (battp->cap >= 50) 105120156Siwasaki state = 0; /* high */ 106128975Snjl else 107120156Siwasaki state = 1; /* low */ 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 120128975Snjl if (battp->cap >= 50) 12185556Siwasaki flags |= APM_BATT_HIGH; 122128975Snjl 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; 145132619Snjl aip->ai_status = apm_active; 146131218Simp aip->ai_capabilities= 0xff00; /* unknown */ 14785556Siwasaki 148119530Snjl if (acpi_acad_get_acline(&acline)) 149131218Simp aip->ai_acline = APM_UNKNOWN; /* unknown */ 150119530Snjl else 15185556Siwasaki aip->ai_acline = acline; /* on/off */ 15285556Siwasaki 153148352Snjl if (acpi_battery_get_battinfo(NULL, &batt) != 0) { 154131218Simp aip->ai_batt_stat = APM_UNKNOWN; 155131218Simp aip->ai_batt_life = APM_UNKNOWN; 156131218Simp aip->ai_batt_time = -1; /* unknown */ 157131218Simp aip->ai_batteries = ~0U; /* unknown */ 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{ 171148352Snjl device_t dev; 172148352Snjl int acline, unit, error; 17385556Siwasaki struct acpi_battinfo batt; 17485556Siwasaki 17585556Siwasaki if (app->ap_device != PMDV_ALLDEV && 176128975Snjl (app->ap_device < PMDV_BATT0 || app->ap_device > PMDV_BATT_ALL)) 17785556Siwasaki return (1); 17885556Siwasaki 179119530Snjl if (app->ap_device == PMDV_ALLDEV) 180148352Snjl error = acpi_battery_get_battinfo(NULL, &batt); 181148352Snjl else { 182148352Snjl unit = app->ap_device - PMDV_BATT0; 183148352Snjl dev = devclass_get_device(devclass_find("battery"), unit); 184148352Snjl if (dev != NULL) 185148352Snjl error = acpi_battery_get_battinfo(dev, &batt); 186148352Snjl else 187148352Snjl error = ENXIO; 188148352Snjl } 189148352Snjl if (error) 19085556Siwasaki return (1); 19185556Siwasaki 19285556Siwasaki app->ap_batt_stat = acpi_capm_convert_battstate(&batt); 19385556Siwasaki app->ap_batt_flag = acpi_capm_convert_battflags(&batt); 19485556Siwasaki app->ap_batt_life = batt.cap; 19585556Siwasaki app->ap_batt_time = (batt.min == -1) ? -1 : batt.min * 60; 19685556Siwasaki 197119530Snjl if (acpi_acad_get_acline(&acline)) 198131218Simp app->ap_acline = APM_UNKNOWN; 199119530Snjl else 20085556Siwasaki app->ap_acline = acline; /* on/off */ 20185556Siwasaki 20285556Siwasaki return (0); 20385556Siwasaki} 20485556Siwasaki 20585556Siwasakistatic int 206130585Sphkapmopen(struct cdev *dev, int flag, int fmt, d_thread_t *td) 20785556Siwasaki{ 20885556Siwasaki return (0); 20985556Siwasaki} 21085556Siwasaki 21185556Siwasakistatic int 212130585Sphkapmclose(struct cdev *dev, int flag, int fmt, d_thread_t *td) 21385556Siwasaki{ 21485556Siwasaki return (0); 21585556Siwasaki} 21685556Siwasaki 21785556Siwasakistatic int 218130585Sphkapmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td) 21985556Siwasaki{ 22085556Siwasaki int error = 0; 22185556Siwasaki struct acpi_softc *acpi_sc; 22285556Siwasaki struct apm_info info; 22385556Siwasaki apm_info_old_t aiop; 22485556Siwasaki 225132619Snjl acpi_sc = devclass_get_softc(devclass_find("acpi"), 0); 22685556Siwasaki 22785556Siwasaki switch (cmd) { 22885556Siwasaki case APMIO_SUSPEND: 229119530Snjl if ((flag & FWRITE) == 0) 23085556Siwasaki return (EPERM); 231132619Snjl if (apm_active) 23285556Siwasaki acpi_SetSleepState(acpi_sc, acpi_sc->acpi_suspend_sx); 23385556Siwasaki else 23485556Siwasaki error = EINVAL; 23585556Siwasaki break; 23685556Siwasaki case APMIO_STANDBY: 237119530Snjl if ((flag & FWRITE) == 0) 23885556Siwasaki return (EPERM); 239132619Snjl if (apm_active) 24085556Siwasaki acpi_SetSleepState(acpi_sc, acpi_sc->acpi_standby_sx); 24185556Siwasaki else 24285556Siwasaki error = EINVAL; 24385556Siwasaki break; 24485556Siwasaki case APMIO_GETINFO_OLD: 24585556Siwasaki if (acpi_capm_get_info(&info)) 24685556Siwasaki error = ENXIO; 24785556Siwasaki aiop = (apm_info_old_t)addr; 24885556Siwasaki aiop->ai_major = info.ai_major; 24985556Siwasaki aiop->ai_minor = info.ai_minor; 25085556Siwasaki aiop->ai_acline = info.ai_acline; 25185556Siwasaki aiop->ai_batt_stat = info.ai_batt_stat; 25285556Siwasaki aiop->ai_batt_life = info.ai_batt_life; 25385556Siwasaki aiop->ai_status = info.ai_status; 25485556Siwasaki break; 25585556Siwasaki case APMIO_GETINFO: 25685556Siwasaki if (acpi_capm_get_info((apm_info_t)addr)) 25785556Siwasaki error = ENXIO; 25885556Siwasaki break; 25985556Siwasaki case APMIO_GETPWSTATUS: 26085556Siwasaki if (acpi_capm_get_pwstatus((apm_pwstatus_t)addr)) 26185556Siwasaki error = ENXIO; 26285556Siwasaki break; 26385556Siwasaki case APMIO_ENABLE: 264119530Snjl if ((flag & FWRITE) == 0) 26585556Siwasaki return (EPERM); 266132619Snjl apm_active = 1; 26785556Siwasaki break; 26885556Siwasaki case APMIO_DISABLE: 269119530Snjl if ((flag & FWRITE) == 0) 27085556Siwasaki return (EPERM); 271132619Snjl apm_active = 0; 27285556Siwasaki break; 27385556Siwasaki case APMIO_HALTCPU: 27485556Siwasaki break; 27585556Siwasaki case APMIO_NOTHALTCPU: 27685556Siwasaki break; 27785556Siwasaki case APMIO_DISPLAY: 278119530Snjl if ((flag & FWRITE) == 0) 27985556Siwasaki return (EPERM); 28085556Siwasaki break; 28185556Siwasaki case APMIO_BIOS: 282119530Snjl if ((flag & FWRITE) == 0) 28385556Siwasaki return (EPERM); 28485556Siwasaki bzero(addr, sizeof(struct apm_bios_arg)); 28585556Siwasaki break; 28685556Siwasaki default: 28785556Siwasaki error = EINVAL; 28885556Siwasaki break; 28985556Siwasaki } 29085556Siwasaki 29185556Siwasaki return (error); 29285556Siwasaki} 29385556Siwasaki 29485556Siwasakistatic int 295130585Sphkapmwrite(struct cdev *dev, struct uio *uio, int ioflag) 29685556Siwasaki{ 29785556Siwasaki return (uio->uio_resid); 29885556Siwasaki} 29985556Siwasaki 30085556Siwasakistatic int 301130585Sphkapmpoll(struct cdev *dev, int events, d_thread_t *td) 30285556Siwasaki{ 30385556Siwasaki return (0); 30485556Siwasaki} 30585556Siwasaki 30685556Siwasakistatic void 30785556Siwasakiacpi_capm_init(struct acpi_softc *sc) 30885556Siwasaki{ 30985556Siwasaki make_dev(&apm_cdevsw, 0, 0, 5, 0664, "apm"); 31085556Siwasaki} 31185556Siwasaki 31285556Siwasakiint 31385556Siwasakiacpi_machdep_init(device_t dev) 31485556Siwasaki{ 31585556Siwasaki struct acpi_softc *sc; 31685556Siwasaki 317132619Snjl sc = devclass_get_softc(devclass_find("acpi"), 0); 31885556Siwasaki acpi_capm_init(sc); 31985556Siwasaki 32085556Siwasaki acpi_install_wakeup_handler(sc); 32185556Siwasaki 322128932Sjhb if (intr_model == ACPI_INTR_PIC) 323167814Sjkim BUS_CONFIG_INTR(dev, AcpiGbl_FADT.SciInterrupt, 324167814Sjkim INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW); 325128932Sjhb else 326119944Sjhb acpi_SetIntrModel(intr_model); 327121743Siwasaki 328121830Snjl SYSCTL_ADD_UINT(&sc->acpi_sysctl_ctx, 329121830Snjl SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO, 330159477Snjl "reset_video", CTLFLAG_RW, &acpi_reset_video, 0, 331121830Snjl "Call the VESA reset BIOS vector on the resume path"); 332121743Siwasaki 33385556Siwasaki return (0); 33485556Siwasaki} 335119944Sjhb 336119944Sjhbvoid 337119944Sjhbacpi_SetDefaultIntrModel(int model) 338119944Sjhb{ 339119944Sjhb 340119944Sjhb intr_model = model; 341119944Sjhb} 342131312Snjl 343131312Snjl/* Check BIOS date. If 1998 or older, disable ACPI. */ 344131312Snjlint 345131312Snjlacpi_machdep_quirks(int *quirks) 346131312Snjl{ 347136367Snjl char *va; 348136367Snjl int year; 349131312Snjl 350136367Snjl /* BIOS address 0xffff5 contains the date in the format mm/dd/yy. */ 351161223Sjhb va = pmap_mapbios(0xffff0, 16); 352136367Snjl sscanf(va + 11, "%2d", &year); 353161223Sjhb pmap_unmapbios((vm_offset_t)va, 16); 354131312Snjl 355136367Snjl /* 356136367Snjl * Date must be >= 1/1/1999 or we don't trust ACPI. Note that this 357136367Snjl * check must be changed by my 114th birthday. 358136367Snjl */ 359136367Snjl if (year > 90 && year < 99) 360136367Snjl *quirks = ACPI_Q_BROKEN; 361131312Snjl 362136367Snjl return (0); 363131312Snjl} 364136366Snjl 365136366Snjlvoid 366136366Snjlacpi_cpu_c1() 367136366Snjl{ 368136366Snjl __asm __volatile("sti; hlt"); 369136366Snjl} 370