acpi_acad.c revision 83173
1/*-
2 * Copyright (c) 2000 Takanori Watanabe
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/dev/acpica/acpi_acad.c 83173 2001-09-06 23:33:22Z msmith $
27 */
28
29#include "opt_acpi.h"
30#include <sys/param.h>
31#include <sys/kernel.h>
32#include <sys/bus.h>
33
34#include <machine/bus.h>
35#include <machine/resource.h>
36#include <sys/rman.h>
37#include <sys/ioccom.h>
38#include <sys/malloc.h>
39#include <sys/conf.h>
40
41#include  "acpi.h"
42#include <dev/acpica/acpivar.h>
43#include <dev/acpica/acpiio.h>
44
45/*
46 * Hooks for the ACPI CA debugging infrastructure
47 */
48#define _COMPONENT	ACPI_AC_ADAPTER
49MODULE_NAME("AC_ADAPTER")
50
51#define ACPI_DEVICE_CHECK_PNP		0x00
52#define ACPI_DEVICE_CHECK_EXISTENCE	0x01
53#define ACPI_POWERSOURCE_STAT_CHANGE	0x80
54
55static void acpi_acad_get_status(void * );
56static void acpi_acad_notify_handler(ACPI_HANDLE , UINT32 ,void *);
57static int acpi_acad_probe(device_t);
58static int acpi_acad_attach(device_t);
59static int acpi_acad_ioctl(u_long, caddr_t, void *);
60static int acpi_acad_sysctl(SYSCTL_HANDLER_ARGS);
61
62struct  acpi_acad_softc {
63	int status;
64};
65
66static void
67acpi_acad_get_status(void *context)
68{
69	int newstatus;
70	device_t dev = context;
71	struct acpi_acad_softc *sc = device_get_softc(dev);
72	ACPI_HANDLE h = acpi_get_handle(dev);
73
74	if (acpi_EvaluateInteger(h, "_PSR", &newstatus) != AE_OK) {
75		sc->status = -1;
76		return;
77	}
78
79	if (sc->status != newstatus) {
80		sc->status = newstatus;
81		/* set system power profile based on AC adapter status */
82		powerprofile_set_state(sc->status ? POWERPROFILE_PERFORMANCE : POWERPROFILE_ECONOMY);
83	}
84
85	if (bootverbose) {
86		device_printf(dev,"%s\n",(sc->status) ? "On Line" : "Off Line");
87	}
88}
89
90static void
91acpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
92{
93	device_t dev = context;
94
95	if (bootverbose) {
96		device_printf(dev, "Notify %d\n", notify);
97	}
98
99	switch (notify) {
100	case ACPI_DEVICE_CHECK_PNP:
101	case ACPI_DEVICE_CHECK_EXISTENCE:
102	case ACPI_POWERSOURCE_STAT_CHANGE:
103		/*Temporally. It is better to notify policy manager*/
104		AcpiOsQueueForExecution(OSD_PRIORITY_LO,
105		    acpi_acad_get_status,context);
106		break;
107	default:
108		break;
109	}
110}
111
112static int
113acpi_acad_probe(device_t dev)
114{
115
116    if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
117	acpi_MatchHid(dev, "ACPI0003")) {
118
119      /*
120       * Set device description
121       */
122	device_set_desc(dev, "AC adapter");
123	return(0);
124    }
125    return(ENXIO);
126}
127
128static int
129acpi_acad_attach(device_t dev)
130{
131	int	 error;
132	struct acpi_acad_softc	*sc;
133	struct acpi_softc	*acpi_sc;
134
135	ACPI_HANDLE handle = acpi_get_handle(dev);
136	AcpiInstallNotifyHandler(handle,
137				 ACPI_DEVICE_NOTIFY,
138				 acpi_acad_notify_handler, dev);
139	/*Installing system notify is not so good*/
140	AcpiInstallNotifyHandler(handle,
141				 ACPI_SYSTEM_NOTIFY,
142				 acpi_acad_notify_handler, dev);
143
144	if ((sc = device_get_softc(dev)) == NULL) {
145		return (ENXIO);
146	}
147	if ((error = acpi_register_ioctl(ACPIIO_ACAD_GET_STATUS,
148			acpi_acad_ioctl, dev)) != 0) {
149		return (error);
150	}
151
152	if (device_get_unit(dev) == 0) {
153		acpi_sc = acpi_device_get_parent_softc(dev);
154		SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx,
155			SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
156			OID_AUTO, "acline", CTLTYPE_INT | CTLFLAG_RD,
157			&sc->status, 0, acpi_acad_sysctl, "I", "");
158	}
159
160	/* Get initial status after whole system is up. */
161	sc->status = -1;
162	AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_acad_get_status, dev);
163
164	return(0);
165}
166
167static device_method_t acpi_acad_methods[] = {
168    /* Device interface */
169    DEVMETHOD(device_probe,	acpi_acad_probe),
170    DEVMETHOD(device_attach,	acpi_acad_attach),
171
172    {0, 0}
173};
174
175static driver_t acpi_acad_driver = {
176    "acpi_acad",
177    acpi_acad_methods,
178    sizeof(struct acpi_acad_softc),
179};
180
181static devclass_t acpi_acad_devclass;
182DRIVER_MODULE(acpi_acad,acpi,acpi_acad_driver,acpi_acad_devclass,0,0);
183
184static int
185acpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg)
186{
187	device_t		 dev;
188	struct acpi_acad_softc	*sc;
189
190	dev = (device_t)arg;
191	if ((sc = device_get_softc(dev)) == NULL) {
192		return(ENXIO);
193	}
194
195	switch (cmd) {
196	case ACPIIO_ACAD_GET_STATUS:
197		acpi_acad_get_status(dev);
198		*(int *)addr = sc->status;
199		break;
200	}
201
202	return(0);
203}
204
205static int
206acpi_acad_sysctl(SYSCTL_HANDLER_ARGS)
207{
208	int     val;
209	int     error;
210	device_t	dev;
211	struct acpi_acad_softc	*sc;
212
213	if ((dev = devclass_get_device(acpi_acad_devclass, 0)) == NULL) {
214		return (ENXIO);
215	}
216	if ((sc = device_get_softc(dev)) == NULL) {
217		return (ENXIO);
218	}
219	acpi_acad_get_status(dev);
220	val = *(u_int *)oidp->oid_arg1;
221	error = sysctl_handle_int(oidp, &val, 0, req);
222	return (error);
223}
224
225