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