acpi_acad.c revision 80334
1193323Sed/*-
2193323Sed * Copyright (c) 2000 Takanori Watanabe
3193323Sed * All rights reserved.
4193323Sed *
5193323Sed * Redistribution and use in source and binary forms, with or without
6193323Sed * modification, are permitted provided that the following conditions
7193323Sed * are met:
8193323Sed * 1. Redistributions of source code must retain the above copyright
9193323Sed *    notice, this list of conditions and the following disclaimer.
10193323Sed * 2. Redistributions in binary form must reproduce the above copyright
11193323Sed *    notice, this list of conditions and the following disclaimer in the
12193323Sed *    documentation and/or other materials provided with the distribution.
13193323Sed *
14193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17193323Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18218893Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19249423Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20249423Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24234353Sdim * SUCH DAMAGE.
25193323Sed *
26193323Sed * $FreeBSD: head/sys/dev/acpica/acpi_acad.c 80334 2001-07-25 16:08:58Z iwasaki $
27193323Sed */
28193323Sed
29226633Sdim#include "opt_acpi.h"
30226633Sdim#include <sys/param.h>
31226633Sdim#include <sys/kernel.h>
32226633Sdim#include <sys/bus.h>
33226633Sdim
34226633Sdim#include <machine/bus.h>
35234353Sdim#include <machine/resource.h>
36234353Sdim#include <sys/rman.h>
37234353Sdim#include <sys/ioccom.h>
38234353Sdim#include <sys/malloc.h>
39234353Sdim#include <sys/conf.h>
40218893Sdim
41193323Sed#include  "acpi.h"
42193323Sed#include <dev/acpica/acpivar.h>
43193323Sed#include <dev/acpica/acpiio.h>
44218893Sdim
45218893Sdim/*
46193323Sed * Hooks for the ACPI CA debugging infrastructure
47194612Sed */
48194612Sed#define _COMPONENT	ACPI_AC_ADAPTER
49194612SedMODULE_NAME("AC_ADAPTER")
50194612Sed
51194612Sed#define ACPI_DEVICE_CHECK_PNP		0x00
52194612Sed#define ACPI_DEVICE_CHECK_EXISTENCE	0x01
53194612Sed#define ACPI_POWERSOURCE_STAT_CHANGE	0x80
54218893Sdim
55234353Sdimstatic void acpi_acad_get_status(void * );
56193323Sedstatic void acpi_acad_notify_handler(ACPI_HANDLE , UINT32 ,void *);
57193323Sedstatic int acpi_acad_probe(device_t);
58234353Sdimstatic int acpi_acad_attach(device_t);
59234353Sdimstatic int acpi_acad_ioctl(u_long, caddr_t, void *);
60239462Sdimstatic int acpi_acad_sysctl(SYSCTL_HANDLER_ARGS);
61239462Sdim
62239462Sdimstruct  acpi_acad_softc {
63239462Sdim	int status;
64239462Sdim};
65239462Sdim
66239462Sdimstatic void
67239462Sdimacpi_acad_get_status(void *context)
68239462Sdim{
69239462Sdim	int newstatus;
70239462Sdim	device_t dev = context;
71239462Sdim	struct acpi_acad_softc *sc = device_get_softc(dev);
72239462Sdim	ACPI_HANDLE h = acpi_get_handle(dev);
73239462Sdim
74239462Sdim	if (acpi_EvaluateInteger(h, "_PSR", &newstatus) != AE_OK) {
75239462Sdim		sc->status = -1;
76239462Sdim		return;
77239462Sdim	}
78239462Sdim
79239462Sdim	if (sc->status != newstatus) {
80243830Sdim		sc->status = newstatus;
81193323Sed		/* set system power profile based on AC adapter status */
82193323Sed		powerprofile_set_state(sc->status ? POWERPROFILE_PERFORMANCE : POWERPROFILE_ECONOMY);
83193323Sed	}
84193323Sed
85243830Sdim	if (bootverbose) {
86243830Sdim		device_printf(dev,"%s\n",(sc->status) ? "On Line" : "Off Line");
87243830Sdim	}
88243830Sdim}
89234353Sdim
90243830Sdimstatic void
91243830Sdimacpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
92243830Sdim{
93243830Sdim	device_t dev = context;
94234353Sdim
95234353Sdim	if (bootverbose) {
96234353Sdim		device_printf(dev, "Notify %d\n", notify);
97234353Sdim	}
98234353Sdim
99234353Sdim	switch (notify) {
100234353Sdim	case ACPI_DEVICE_CHECK_PNP:
101234353Sdim	case ACPI_DEVICE_CHECK_EXISTENCE:
102249423Sdim	case ACPI_POWERSOURCE_STAT_CHANGE:
103249423Sdim		/*Temporally. It is better to notify policy manager*/
104249423Sdim		AcpiOsQueueForExecution(OSD_PRIORITY_LO,
105249423Sdim		    acpi_acad_get_status,context);
106193323Sed		break;
107234353Sdim	default:
108243830Sdim		break;
109243830Sdim	}
110193323Sed}
111193323Sed
112193323Sedstatic int
113226633Sdimacpi_acad_probe(device_t dev)
114193323Sed{
115226633Sdim
116226633Sdim    if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
117226633Sdim	acpi_MatchHid(dev, "ACPI0003")) {
118226633Sdim
119226633Sdim      /*
120226633Sdim       * Set device description
121226633Sdim       */
122226633Sdim	device_set_desc(dev, "AC adapter");
123226633Sdim	return(0);
124226633Sdim    }
125226633Sdim    return(ENXIO);
126226633Sdim}
127226633Sdim
128226633Sdimstatic int
129226633Sdimacpi_acad_attach(device_t dev)
130234353Sdim{
131234353Sdim	int	 error;
132234353Sdim	struct acpi_acad_softc	*sc;
133234353Sdim	struct acpi_softc	*acpi_sc;
134234353Sdim
135234353Sdim	ACPI_HANDLE handle = acpi_get_handle(dev);
136234353Sdim	AcpiInstallNotifyHandler(handle,
137234353Sdim				 ACPI_DEVICE_NOTIFY,
138234353Sdim				 acpi_acad_notify_handler, dev);
139234353Sdim	/*Installing system notify is not so good*/
140234353Sdim	AcpiInstallNotifyHandler(handle,
141234353Sdim				 ACPI_SYSTEM_NOTIFY,
142234353Sdim				 acpi_acad_notify_handler, dev);
143234353Sdim
144234353Sdim	if ((sc = device_get_softc(dev)) == NULL) {
145234353Sdim		return (ENXIO);
146234353Sdim	}
147226633Sdim	if ((error = acpi_register_ioctl(ACPIIO_ACAD_GET_STATUS,
148193323Sed			acpi_acad_ioctl, dev)) != 0) {
149193323Sed		return (error);
150193323Sed	}
151239462Sdim
152239462Sdim	if (device_get_unit(dev) == 0) {
153239462Sdim		acpi_sc = acpi_device_get_parent_softc(dev);
154239462Sdim		SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx,
155239462Sdim			SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
156239462Sdim			OID_AUTO, "acline", CTLTYPE_INT | CTLFLAG_RD,
157249423Sdim			&sc->status, 0, acpi_acad_sysctl, "I", "");
158249423Sdim	}
159249423Sdim
160251662Sdim	/* Get initial status after whole system is up. */
161251662Sdim	AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_acad_get_status, dev);
162251662Sdim
163251662Sdim	return(0);
164251662Sdim}
165251662Sdim
166193323Sedstatic device_method_t acpi_acad_methods[] = {
167193323Sed    /* Device interface */
168193323Sed    DEVMETHOD(device_probe,	acpi_acad_probe),
169203954Srdivacky    DEVMETHOD(device_attach,	acpi_acad_attach),
170193323Sed
171193323Sed    {0, 0}
172239462Sdim};
173239462Sdim
174239462Sdimstatic driver_t acpi_acad_driver = {
175193323Sed    "acpi_acad",
176193323Sed    acpi_acad_methods,
177203954Srdivacky    sizeof(struct acpi_acad_softc),
178193323Sed};
179193323Sed
180193323Sedstatic devclass_t acpi_acad_devclass;
181193323SedDRIVER_MODULE(acpi_acad,acpi,acpi_acad_driver,acpi_acad_devclass,0,0);
182193323Sed
183193323Sedstatic int
184193323Sedacpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg)
185193323Sed{
186193323Sed	device_t		 dev;
187208599Srdivacky	struct acpi_acad_softc	*sc;
188208599Srdivacky
189208599Srdivacky	dev = (device_t)arg;
190208599Srdivacky	if ((sc = device_get_softc(dev)) == NULL) {
191208599Srdivacky		return(ENXIO);
192208599Srdivacky	}
193208599Srdivacky
194208599Srdivacky	switch (cmd) {
195208599Srdivacky	case ACPIIO_ACAD_GET_STATUS:
196208599Srdivacky		acpi_acad_get_status(dev);
197208599Srdivacky		*(int *)addr = sc->status;
198208599Srdivacky		break;
199208599Srdivacky	}
200208599Srdivacky
201193323Sed	return(0);
202203954Srdivacky}
203193323Sed
204193323Sedstatic int
205193323Sedacpi_acad_sysctl(SYSCTL_HANDLER_ARGS)
206193323Sed{
207193323Sed	int     val;
208193323Sed	int     error;
209193323Sed	device_t	dev;
210193323Sed	struct acpi_acad_softc	*sc;
211193323Sed
212239462Sdim	if ((dev = devclass_get_device(acpi_acad_devclass, 0)) == NULL) {
213239462Sdim		return (ENXIO);
214239462Sdim	}
215239462Sdim	if ((sc = device_get_softc(dev)) == NULL) {
216239462Sdim		return (ENXIO);
217239462Sdim	}
218239462Sdim	acpi_acad_get_status(dev);
219239462Sdim	val = *(u_int *)oidp->oid_arg1;
220239462Sdim	error = sysctl_handle_int(oidp, &val, 0, req);
221193323Sed	return (error);
222203954Srdivacky}
223193323Sed
224193323Sed