acpi_acad.c revision 129879
119304Speter/*- 219304Speter * Copyright (c) 2000 Takanori Watanabe 319304Speter * All rights reserved. 419304Speter * 519304Speter * Redistribution and use in source and binary forms, with or without 619304Speter * modification, are permitted provided that the following conditions 719304Speter * are met: 819304Speter * 1. Redistributions of source code must retain the above copyright 919304Speter * notice, this list of conditions and the following disclaimer. 1019304Speter * 2. Redistributions in binary form must reproduce the above copyright 1119304Speter * notice, this list of conditions and the following disclaimer in the 1219304Speter * documentation and/or other materials provided with the distribution. 13254225Speter * 1419304Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1519304Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1619304Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1719304Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1819304Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1919304Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2019304Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2119304Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2219304Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2319304Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2419304Speter * SUCH DAMAGE. 2519304Speter * 26254225Speter * $FreeBSD: head/sys/dev/acpica/acpi_acad.c 129879 2004-05-30 20:08:47Z phk $ 27254225Speter */ 28254225Speter 2919304Speter#include "opt_acpi.h" 3019304Speter#include <sys/param.h> 3119304Speter#include <sys/kernel.h> 3219304Speter#include <sys/bus.h> 3319304Speter 3419304Speter#include <machine/bus.h> 3519304Speter#include <sys/rman.h> 3619304Speter#include <sys/ioccom.h> 3719304Speter#include <sys/malloc.h> 3819304Speter#include <sys/module.h> 3919304Speter#include <sys/conf.h> 4019304Speter#include <sys/power.h> 4119304Speter 4219304Speter#include "acpi.h" 4319304Speter#include <dev/acpica/acpivar.h> 4419304Speter#include <dev/acpica/acpiio.h> 4519304Speter 4619304Speter/* Hooks for the ACPI CA debugging infrastructure */ 4719304Speter#define _COMPONENT ACPI_AC_ADAPTER 4819304SpeterACPI_MODULE_NAME("AC_ADAPTER") 4919304Speter 5019304Speter/* Number of times to retry initialization before giving up. */ 5119304Speter#define ACPI_ACAD_RETRY_MAX 6 52254225Speter 5319304Speter#define ACPI_DEVICE_CHECK_PNP 0x00 5419304Speter#define ACPI_DEVICE_CHECK_EXISTENCE 0x01 5519304Speter#define ACPI_POWERSOURCE_STAT_CHANGE 0x80 5619304Speter 5719304Speterstruct acpi_acad_softc { 5819304Speter int status; 59254225Speter int initializing; 6019304Speter}; 6119304Speter 6219304Speterstatic void acpi_acad_get_status(void *); 6319304Speterstatic void acpi_acad_notify_handler(ACPI_HANDLE, UINT32, void *); 6419304Speterstatic int acpi_acad_probe(device_t); 6519304Speterstatic int acpi_acad_attach(device_t); 6619304Speterstatic int acpi_acad_ioctl(u_long, caddr_t, void *); 6719304Speterstatic int acpi_acad_sysctl(SYSCTL_HANDLER_ARGS); 6819304Speterstatic void acpi_acad_init_acline(void *arg); 6919304Speter 7019304Speterstatic device_method_t acpi_acad_methods[] = { 7119304Speter /* Device interface */ 7219304Speter DEVMETHOD(device_probe, acpi_acad_probe), 7319304Speter DEVMETHOD(device_attach, acpi_acad_attach), 7419304Speter 7519304Speter {0, 0} 7619304Speter}; 7719304Speter 7819304Speterstatic driver_t acpi_acad_driver = { 7919304Speter "acpi_acad", 8019304Speter acpi_acad_methods, 8119304Speter sizeof(struct acpi_acad_softc), 8219304Speter}; 8319304Speter 8419304Speterstatic devclass_t acpi_acad_devclass; 8519304SpeterDRIVER_MODULE(acpi_acad, acpi, acpi_acad_driver, acpi_acad_devclass, 0, 0); 8619304SpeterMODULE_DEPEND(acpi_acad, acpi, 1, 1, 1); 8719304Speter 8819304Speterstatic void 8919304Speteracpi_acad_get_status(void *context) 9019304Speter{ 9119304Speter struct acpi_acad_softc *sc; 9219304Speter device_t dev; 9319304Speter ACPI_HANDLE h; 9419304Speter int newstatus; 9519304Speter 9619304Speter dev = context; 9719304Speter sc = device_get_softc(dev); 9819304Speter h = acpi_get_handle(dev); 9919304Speter if (ACPI_FAILURE(acpi_GetInteger(h, "_PSR", &newstatus))) { 10019304Speter sc->status = -1; 10119304Speter return; 10219304Speter } 10319304Speter 10419304Speter if (sc->status != newstatus) { 10519304Speter sc->status = newstatus; 10619304Speter 10719304Speter /* Set system power profile based on AC adapter status */ 10819304Speter power_profile_set_state(sc->status ? POWER_PROFILE_PERFORMANCE : 10919304Speter POWER_PROFILE_ECONOMY); 11019304Speter ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 11119304Speter "%s Line\n", sc->status ? "On" : "Off"); 11219304Speter 11319304Speter acpi_UserNotify("ACAD", h, sc->status); 11419304Speter } 11519304Speter} 11619304Speter 11719304Speterstatic void 11819304Speteracpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 11919304Speter{ 12019304Speter device_t dev; 12119304Speter 12219304Speter dev = (device_t)context; 12319304Speter switch (notify) { 12419304Speter case ACPI_DEVICE_CHECK_PNP: 12519304Speter case ACPI_DEVICE_CHECK_EXISTENCE: 12619304Speter case ACPI_POWERSOURCE_STAT_CHANGE: 12719304Speter /* Temporarily. It is better to notify policy manager */ 12819304Speter AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_acad_get_status, context); 12919304Speter break; 13019304Speter default: 13119304Speter device_printf(dev, "unknown notify %#x\n", notify); 13219304Speter break; 13319304Speter } 13419304Speter} 13519304Speter 13619304Speterstatic int 13719304Speteracpi_acad_probe(device_t dev) 138254225Speter{ 139254225Speter if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("acad") && 14019304Speter acpi_MatchHid(dev, "ACPI0003")) { 14119304Speter device_set_desc(dev, "AC Adapter"); 14219304Speter return (0); 14319304Speter } 14419304Speter return (ENXIO); 14519304Speter} 14619304Speter 14719304Speterstatic int 14819304Speteracpi_acad_attach(device_t dev) 14919304Speter{ 150254225Speter struct acpi_acad_softc *sc; 151254225Speter struct acpi_softc *acpi_sc; 15219304Speter ACPI_HANDLE handle; 153254225Speter int error; 15419304Speter 15519304Speter sc = device_get_softc(dev); 15619304Speter if (sc == NULL) 15719304Speter return (ENXIO); 15819304Speter handle = acpi_get_handle(dev); 15919304Speter 16019304Speter error = acpi_register_ioctl(ACPIIO_ACAD_GET_STATUS, acpi_acad_ioctl, dev); 16119304Speter if (error != 0) 16219304Speter return (error); 16319304Speter 16419304Speter if (device_get_unit(dev) == 0) { 165254225Speter acpi_sc = acpi_device_get_parent_softc(dev); 16619304Speter SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx, 16719304Speter SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), 16819304Speter OID_AUTO, "acline", CTLTYPE_INT | CTLFLAG_RD, 16919304Speter &sc->status, 0, acpi_acad_sysctl, "I", ""); 17019304Speter } 17119304Speter 17219304Speter /* Get initial status after whole system is up. */ 17319304Speter sc->status = -1; 17419304Speter sc->initializing = 0; 17519304Speter 17619304Speter /* 17719304Speter * Also install a system notify handler even though this is not 17819304Speter * required by the specification. The Casio FIVA needs this. 17919304Speter */ 18019304Speter AcpiInstallNotifyHandler(handle, ACPI_SYSTEM_NOTIFY, 18119304Speter acpi_acad_notify_handler, dev); 18219304Speter AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, 18319304Speter acpi_acad_notify_handler, dev); 18419304Speter AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_acad_init_acline, dev); 18519304Speter 18619304Speter return (0); 18719304Speter} 188254225Speter 18919304Speterstatic int 19019304Speteracpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg) 19119304Speter{ 19219304Speter struct acpi_acad_softc *sc; 19319304Speter device_t dev; 19419304Speter 19519304Speter dev = (device_t)arg; 19619304Speter sc = device_get_softc(dev); 19719304Speter if (sc == NULL) 19819304Speter return (ENXIO); 19919304Speter 20019304Speter /* 20119304Speter * No security check required: information retrieval only. If 20219304Speter * new functions are added here, a check might be required. 20319304Speter */ 20419304Speter switch (cmd) { 20519304Speter case ACPIIO_ACAD_GET_STATUS: 20619304Speter acpi_acad_get_status(dev); 20719304Speter *(int *)addr = sc->status; 20819304Speter break; 20919304Speter default: 21019304Speter break; 21119304Speter } 21219304Speter 21319304Speter return (0); 21419304Speter} 21519304Speter 21619304Speterstatic int 21719304Speteracpi_acad_sysctl(SYSCTL_HANDLER_ARGS) 21819304Speter{ 21919304Speter int val, error; 22019304Speter 22119304Speter if (acpi_acad_get_acline(&val) != 0) 22219304Speter return (ENXIO); 22319304Speter 22419304Speter val = *(u_int *)oidp->oid_arg1; 22519304Speter error = sysctl_handle_int(oidp, &val, 0, req); 22619304Speter return (error); 22719304Speter} 22819304Speter 22919304Speterstatic void 23019304Speteracpi_acad_init_acline(void *arg) 23119304Speter{ 23219304Speter struct acpi_acad_softc *sc; 23319304Speter device_t dev; 23419304Speter int retry, status; 23519304Speter 236254225Speter dev = (device_t)arg; 23719304Speter sc = device_get_softc(dev); 23819304Speter if (sc->initializing) 23919304Speter return; 24019304Speter 24119304Speter sc->initializing = 1; 24219304Speter ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 24319304Speter "acline initialization start\n"); 24419304Speter 24519304Speter status = 0; 24619304Speter for (retry = 0; retry < ACPI_ACAD_RETRY_MAX; retry++) { 24719304Speter acpi_acad_get_status(dev); 24819304Speter if (status != sc->status) 24919304Speter break; 25019304Speter AcpiOsSleep(10, 0); 25119304Speter } 25219304Speter 25319304Speter sc->initializing = 0; 25419304Speter ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 25519304Speter "acline initialization done, tried %d times\n", retry + 1); 25619304Speter} 257254225Speter 25819304Speter/* 25919304Speter * Public interfaces. 26019304Speter */ 26119304Speterint 26219304Speteracpi_acad_get_acline(int *status) 26319304Speter{ 26419304Speter struct acpi_acad_softc *sc; 26519304Speter device_t dev; 266254225Speter 26719304Speter dev = devclass_get_device(acpi_acad_devclass, 0); 26819304Speter if (dev == NULL) 26919304Speter return (ENXIO); 27019304Speter sc = device_get_softc(dev); 27119304Speter if (sc == NULL) 27219304Speter return (ENXIO); 27319304Speter 274254225Speter acpi_acad_get_status(dev); 27519304Speter *status = sc->status; 27619304Speter 27719304Speter return (0); 27819304Speter} 27919304Speter