xref: /freebsd/sys/dev/acpica/acpi_acad.c (revision 8fa113e5fc65fe6abc757f0089f477a87ee4d185)
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$
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
49 MODULE_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 
55 static void acpi_acad_get_status(void * );
56 static void acpi_acad_notify_handler(ACPI_HANDLE , UINT32 ,void *);
57 static int acpi_acad_probe(device_t);
58 static int acpi_acad_attach(device_t);
59 static int acpi_acad_ioctl(u_long, caddr_t, void *);
60 static int acpi_acad_sysctl(SYSCTL_HANDLER_ARGS);
61 
62 struct  acpi_acad_softc {
63 	int status;
64 };
65 
66 static void
67 acpi_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 		ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
84 		    "%s Line\n",(sc->status) ? "On" : "Off");
85 	}
86 }
87 
88 static void
89 acpi_acad_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
90 {
91 	device_t dev = context;
92 
93 	ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev),
94 	    "Notify %d\n", notify);
95 
96 	switch (notify) {
97 	case ACPI_DEVICE_CHECK_PNP:
98 	case ACPI_DEVICE_CHECK_EXISTENCE:
99 	case ACPI_POWERSOURCE_STAT_CHANGE:
100 		/*Temporally. It is better to notify policy manager*/
101 		AcpiOsQueueForExecution(OSD_PRIORITY_LO,
102 		    acpi_acad_get_status,context);
103 		break;
104 	default:
105 		break;
106 	}
107 }
108 
109 static int
110 acpi_acad_probe(device_t dev)
111 {
112 
113     if ((acpi_get_type(dev) == ACPI_TYPE_DEVICE) &&
114 	acpi_MatchHid(dev, "ACPI0003")) {
115 
116       /*
117        * Set device description
118        */
119 	device_set_desc(dev, "AC adapter");
120 	return(0);
121     }
122     return(ENXIO);
123 }
124 
125 static int
126 acpi_acad_attach(device_t dev)
127 {
128 	int	 error;
129 	struct acpi_acad_softc	*sc;
130 	struct acpi_softc	*acpi_sc;
131 
132 	ACPI_HANDLE handle = acpi_get_handle(dev);
133 	AcpiInstallNotifyHandler(handle,
134 				 ACPI_DEVICE_NOTIFY,
135 				 acpi_acad_notify_handler, dev);
136 	/*Installing system notify is not so good*/
137 	AcpiInstallNotifyHandler(handle,
138 				 ACPI_SYSTEM_NOTIFY,
139 				 acpi_acad_notify_handler, dev);
140 
141 	if ((sc = device_get_softc(dev)) == NULL) {
142 		return (ENXIO);
143 	}
144 	if ((error = acpi_register_ioctl(ACPIIO_ACAD_GET_STATUS,
145 			acpi_acad_ioctl, dev)) != 0) {
146 		return (error);
147 	}
148 
149 	if (device_get_unit(dev) == 0) {
150 		acpi_sc = acpi_device_get_parent_softc(dev);
151 		SYSCTL_ADD_PROC(&acpi_sc->acpi_sysctl_ctx,
152 			SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree),
153 			OID_AUTO, "acline", CTLTYPE_INT | CTLFLAG_RD,
154 			&sc->status, 0, acpi_acad_sysctl, "I", "");
155 	}
156 
157 	/* Get initial status after whole system is up. */
158 	sc->status = -1;
159 	AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_acad_get_status, dev);
160 
161 	return(0);
162 }
163 
164 static device_method_t acpi_acad_methods[] = {
165     /* Device interface */
166     DEVMETHOD(device_probe,	acpi_acad_probe),
167     DEVMETHOD(device_attach,	acpi_acad_attach),
168 
169     {0, 0}
170 };
171 
172 static driver_t acpi_acad_driver = {
173     "acpi_acad",
174     acpi_acad_methods,
175     sizeof(struct acpi_acad_softc),
176 };
177 
178 static devclass_t acpi_acad_devclass;
179 DRIVER_MODULE(acpi_acad,acpi,acpi_acad_driver,acpi_acad_devclass,0,0);
180 
181 static int
182 acpi_acad_ioctl(u_long cmd, caddr_t addr, void *arg)
183 {
184 	device_t		 dev;
185 	struct acpi_acad_softc	*sc;
186 
187 	dev = (device_t)arg;
188 	if ((sc = device_get_softc(dev)) == NULL) {
189 		return(ENXIO);
190 	}
191 
192 	switch (cmd) {
193 	case ACPIIO_ACAD_GET_STATUS:
194 		acpi_acad_get_status(dev);
195 		*(int *)addr = sc->status;
196 		break;
197 	}
198 
199 	return(0);
200 }
201 
202 static int
203 acpi_acad_sysctl(SYSCTL_HANDLER_ARGS)
204 {
205 	int     val;
206 	int     error;
207 
208 	if (acpi_acad_get_acline(&val)) {
209 		return (ENXIO);
210 	}
211 
212 	val = *(u_int *)oidp->oid_arg1;
213 	error = sysctl_handle_int(oidp, &val, 0, req);
214 	return (error);
215 }
216 
217 /*
218  * Public interfaces.
219  */
220 
221 int
222 acpi_acad_get_acline(int *status)
223 {
224 	device_t		 dev;
225 	struct acpi_acad_softc	*sc;
226 
227 	if ((dev = devclass_get_device(acpi_acad_devclass, 0)) == NULL) {
228 		return (ENXIO);
229 	}
230 
231 	if ((sc = device_get_softc(dev)) == NULL) {
232 		return (ENXIO);
233 	}
234 
235 	acpi_acad_get_status(dev);
236 	*status = sc->status;
237 
238 	return (0);
239 }
240 
241