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