acpi_acad.c revision 91123
1219820Sjeff/*- 2219820Sjeff * Copyright (c) 2000 Takanori Watanabe 3219820Sjeff * All rights reserved. 4219820Sjeff * 5219820Sjeff * Redistribution and use in source and binary forms, with or without 6219820Sjeff * modification, are permitted provided that the following conditions 7219820Sjeff * are met: 8219820Sjeff * 1. Redistributions of source code must retain the above copyright 9219820Sjeff * notice, this list of conditions and the following disclaimer. 10219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 11219820Sjeff * notice, this list of conditions and the following disclaimer in the 12219820Sjeff * documentation and/or other materials provided with the distribution. 13219820Sjeff * 14219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17219820Sjeff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24219820Sjeff * SUCH DAMAGE. 25219820Sjeff * 26219820Sjeff * $FreeBSD: head/sys/dev/acpica/acpi_acad.c 91123 2002-02-23 05:26:45Z msmith $ 27219820Sjeff */ 28219820Sjeff 29219820Sjeff#include "opt_acpi.h" 30219820Sjeff#include <sys/param.h> 31219820Sjeff#include <sys/kernel.h> 32219820Sjeff#include <sys/bus.h> 33219820Sjeff 34219820Sjeff#include <machine/bus.h> 35219820Sjeff#include <machine/resource.h> 36219820Sjeff#include <sys/rman.h> 37219820Sjeff#include <sys/ioccom.h> 38219820Sjeff#include <sys/malloc.h> 39219820Sjeff#include <sys/conf.h> 40219820Sjeff 41219820Sjeff#include "acpi.h" 42219820Sjeff#include <dev/acpica/acpivar.h> 43219820Sjeff#include <dev/acpica/acpiio.h> 44219820Sjeff 45219820Sjeff/* 46219820Sjeff * Hooks for the ACPI CA debugging infrastructure 47219820Sjeff */ 48219820Sjeff#define _COMPONENT ACPI_AC_ADAPTER 49219820SjeffACPI_MODULE_NAME("AC_ADAPTER") 50219820Sjeff 51219820Sjeff#define ACPI_DEVICE_CHECK_PNP 0x00 52219820Sjeff#define ACPI_DEVICE_CHECK_EXISTENCE 0x01 53219820Sjeff#define ACPI_POWERSOURCE_STAT_CHANGE 0x80 54219820Sjeff 55219820Sjeffstatic void acpi_acad_get_status(void * ); 56219820Sjeffstatic void acpi_acad_notify_handler(ACPI_HANDLE , UINT32 ,void *); 57219820Sjeffstatic int acpi_acad_probe(device_t); 58219820Sjeffstatic int acpi_acad_attach(device_t); 59219820Sjeffstatic int acpi_acad_ioctl(u_long, caddr_t, void *); 60219820Sjeffstatic int acpi_acad_sysctl(SYSCTL_HANDLER_ARGS); 61219820Sjeff 62219820Sjeffstruct acpi_acad_softc { 63219820Sjeff int status; 64219820Sjeff}; 65219820Sjeff 66219820Sjeffstatic void 67219820Sjeffacpi_acad_get_status(void *context) 68219820Sjeff{ 69219820Sjeff int newstatus; 70219820Sjeff device_t dev = context; 71219820Sjeff struct acpi_acad_softc *sc = device_get_softc(dev); 72219820Sjeff ACPI_HANDLE h = acpi_get_handle(dev); 73219820Sjeff 74219820Sjeff if (ACPI_FAILURE(acpi_EvaluateInteger(h, "_PSR", &newstatus))) { 75219820Sjeff sc->status = -1; 76219820Sjeff return; 77219820Sjeff } 78219820Sjeff 79219820Sjeff if (sc->status != newstatus) { 80219820Sjeff sc->status = newstatus; 81219820Sjeff /* set system power profile based on AC adapter status */ 82219820Sjeff powerprofile_set_state(sc->status ? POWERPROFILE_PERFORMANCE : POWERPROFILE_ECONOMY); 83219820Sjeff ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 84219820Sjeff "%s Line\n",(sc->status) ? "On" : "Off"); 85219820Sjeff } 86219820Sjeff} 87219820Sjeff 88219820Sjeffstatic void 89219820Sjeffacpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 90219820Sjeff{ 91219820Sjeff device_t dev = context; 92219820Sjeff 93219820Sjeff ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 94219820Sjeff "Notify %d\n", notify); 95219820Sjeff 96219820Sjeff switch (notify) { 97219820Sjeff case ACPI_DEVICE_CHECK_PNP: 98219820Sjeff case ACPI_DEVICE_CHECK_EXISTENCE: 99219820Sjeff case ACPI_POWERSOURCE_STAT_CHANGE: 100219820Sjeff /*Temporally. It is better to notify policy manager*/ 101219820Sjeff AcpiOsQueueForExecution(OSD_PRIORITY_LO, 102219820Sjeff acpi_acad_get_status,context); 103219820Sjeff break; 104219820Sjeff default: 105219820Sjeff break; 106219820Sjeff } 107219820Sjeff} 108219820Sjeff 109219820Sjeffstatic int 110219820Sjeffacpi_acad_probe(device_t dev) 111219820Sjeff{ 112219820Sjeff 113219820Sjeff if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) && 114219820Sjeff acpi_MatchHid(dev, "ACPI0003")) { 115219820Sjeff 116219820Sjeff /* 117219820Sjeff * Set device description 118219820Sjeff */ 119219820Sjeff device_set_desc(dev, "AC adapter"); 120219820Sjeff return(0); 121219820Sjeff } 122219820Sjeff return(ENXIO); 123219820Sjeff} 124219820Sjeff 125219820Sjeffstatic int 126219820Sjeffacpi_acad_attach(device_t dev) 127219820Sjeff{ 128219820Sjeff int error; 129219820Sjeff struct acpi_acad_softc *sc; 130219820Sjeff struct acpi_softc *acpi_sc; 131219820Sjeff 132219820Sjeff ACPI_HANDLE handle = acpi_get_handle(dev); 133219820Sjeff AcpiInstallNotifyHandler(handle, 134219820Sjeff ACPI_DEVICE_NOTIFY, 135219820Sjeff acpi_acad_notify_handler, dev); 136219820Sjeff /*Installing system notify is not so good*/ 137219820Sjeff AcpiInstallNotifyHandler(handle, 138219820Sjeff ACPI_SYSTEM_NOTIFY, 139219820Sjeff acpi_acad_notify_handler, dev); 140219820Sjeff 141219820Sjeff if ((sc = device_get_softc(dev)) == NULL) { 142219820Sjeff return (ENXIO); 143219820Sjeff } 144219820Sjeff if ((error = acpi_register_ioctl(ACPIIO_ACAD_GET_STATUS, 145219820Sjeff acpi_acad_ioctl, dev)) != 0) { 146219820Sjeff return (error); 147219820Sjeff } 148219820Sjeff 149219820Sjeff if (device_get_unit(dev) == 0) { 150219820Sjeff acpi_sc = acpi_device_get_parent_softc(dev); 151219820Sjeff SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx, 152219820Sjeff SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 153219820Sjeff OID_AUTO, "acline", CTLTYPE_INT | CTLFLAG_RD, 154219820Sjeff &sc->status, 0, acpi_acad_sysctl, "I", ""); 155219820Sjeff } 156219820Sjeff 157219820Sjeff /* Get initial status after whole system is up. */ 158219820Sjeff sc->status = -1; 159219820Sjeff AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_acad_get_status, dev); 160219820Sjeff 161219820Sjeff return(0); 162219820Sjeff} 163219820Sjeff 164219820Sjeffstatic device_method_t acpi_acad_methods[] = { 165219820Sjeff /* Device interface */ 166219820Sjeff DEVMETHOD(device_probe, acpi_acad_probe), 167219820Sjeff DEVMETHOD(device_attach, acpi_acad_attach), 168219820Sjeff 169219820Sjeff {0, 0} 170219820Sjeff}; 171219820Sjeff 172219820Sjeffstatic driver_t acpi_acad_driver = { 173219820Sjeff "acpi_acad", 174219820Sjeff acpi_acad_methods, 175219820Sjeff sizeof(struct acpi_acad_softc), 176219820Sjeff}; 177219820Sjeff 178219820Sjeffstatic devclass_t acpi_acad_devclass; 179219820SjeffDRIVER_MODULE(acpi_acad,acpi,acpi_acad_driver,acpi_acad_devclass,0,0); 180219820Sjeff 181219820Sjeffstatic int 182219820Sjeffacpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg) 183219820Sjeff{ 184219820Sjeff device_t dev; 185219820Sjeff struct acpi_acad_softc *sc; 186219820Sjeff 187219820Sjeff dev = (device_t)arg; 188219820Sjeff if ((sc = device_get_softc(dev)) == NULL) { 189219820Sjeff return(ENXIO); 190219820Sjeff } 191219820Sjeff 192219820Sjeff switch (cmd) { 193219820Sjeff case ACPIIO_ACAD_GET_STATUS: 194219820Sjeff acpi_acad_get_status(dev); 195219820Sjeff *(int *)addr = sc->status; 196219820Sjeff break; 197219820Sjeff } 198219820Sjeff 199219820Sjeff return(0); 200219820Sjeff} 201219820Sjeff 202219820Sjeffstatic int 203219820Sjeffacpi_acad_sysctl(SYSCTL_HANDLER_ARGS) 204219820Sjeff{ 205219820Sjeff int val; 206219820Sjeff int error; 207219820Sjeff 208219820Sjeff if (acpi_acad_get_acline(&val)) { 209219820Sjeff return (ENXIO); 210219820Sjeff } 211219820Sjeff 212219820Sjeff val = *(u_int *)oidp->oid_arg1; 213219820Sjeff error = sysctl_handle_int(oidp, &val, 0, req); 214219820Sjeff return (error); 215219820Sjeff} 216219820Sjeff 217219820Sjeff/* 218219820Sjeff * Public interfaces. 219219820Sjeff */ 220219820Sjeff 221219820Sjeffint 222219820Sjeffacpi_acad_get_acline(int *status) 223219820Sjeff{ 224219820Sjeff device_t dev; 225219820Sjeff struct acpi_acad_softc *sc; 226219820Sjeff 227219820Sjeff if ((dev = devclass_get_device(acpi_acad_devclass, 0)) == NULL) { 228219820Sjeff return (ENXIO); 229219820Sjeff } 230219820Sjeff 231219820Sjeff if ((sc = device_get_softc(dev)) == NULL) { 232219820Sjeff return (ENXIO); 233219820Sjeff } 234219820Sjeff 235219820Sjeff acpi_acad_get_status(dev); 236219820Sjeff *status = sc->status; 237219820Sjeff 238219820Sjeff return (0); 239219820Sjeff} 240219820Sjeff 241219820Sjeff