Bring in the FreeBSD-5 ACPICA code as a module. Note: not hooked up yet,
[dragonfly.git] / sys / dev / acpica5 / acpi_button.c
1 /*-
2  * Copyright (c) 2000 Mitsaru IWASAKI <iwasaki@jp.freebsd.org>
3  * Copyright (c) 2000 Michael Smith <msmith@freebsd.org>
4  * Copyright (c) 2000 BSDi
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/dev/acpica/acpi_button.c,v 1.20 2004/02/19 18:16:34 njl Exp $
29  * $DragonFly: src/sys/dev/acpica5/acpi_button.c,v 1.1 2004/02/21 06:48:08 dillon Exp $
30  */
31
32 #include "opt_acpi.h"
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/bus.h>
36
37 #include "acpi.h"
38 #include <dev/acpica5/acpivar.h>
39
40 /* Hooks for the ACPI CA debugging infrastructure */
41 #define _COMPONENT      ACPI_BUTTON
42 ACPI_MODULE_NAME("BUTTON")
43
44 struct acpi_button_softc {
45     device_t    button_dev;
46     ACPI_HANDLE button_handle;
47     boolean_t   button_type;
48 #define         ACPI_POWER_BUTTON       0
49 #define         ACPI_SLEEP_BUTTON       1
50     boolean_t   fixed;
51 };
52
53 #define         ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP    0x80
54 #define         ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP   0x02
55
56 static int      acpi_button_probe(device_t dev);
57 static int      acpi_button_attach(device_t dev);
58 static int      acpi_button_suspend(device_t dev);
59 static int      acpi_button_resume(device_t dev);
60 static void     acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify,
61                                            void *context);
62 static ACPI_STATUS
63                 acpi_button_fixed_handler(void *context);
64 static void     acpi_button_notify_sleep(void *arg);
65 static void     acpi_button_notify_wakeup(void *arg);
66
67 static device_method_t acpi_button_methods[] = {
68     /* Device interface */
69     DEVMETHOD(device_probe,     acpi_button_probe),
70     DEVMETHOD(device_attach,    acpi_button_attach),
71     DEVMETHOD(device_suspend,   acpi_button_suspend),
72     DEVMETHOD(device_shutdown,  acpi_button_suspend),
73     DEVMETHOD(device_resume,    acpi_button_resume),
74
75     {0, 0}
76 };
77
78 static driver_t acpi_button_driver = {
79     "acpi_button",
80     acpi_button_methods,
81     sizeof(struct acpi_button_softc),
82 };
83
84 static devclass_t acpi_button_devclass;
85 DRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass,
86               0, 0);
87
88 static int
89 acpi_button_probe(device_t dev)
90 {
91     struct acpi_button_softc    *sc;
92     int ret = ENXIO;
93
94     sc = device_get_softc(dev);
95     if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("button")) {
96         if (acpi_MatchHid(dev, "PNP0C0C")) {
97             device_set_desc(dev, "Power Button");
98             sc->button_type = ACPI_POWER_BUTTON;
99             ret = 0;
100         } else if (acpi_MatchHid(dev, "ACPI_FPB")) {
101             device_set_desc(dev, "Power Button (fixed)");
102             sc->button_type = ACPI_POWER_BUTTON;
103             sc->fixed = 1;
104             ret = 0;
105         } else if (acpi_MatchHid(dev, "PNP0C0E")) {
106             device_set_desc(dev, "Sleep Button");
107             sc->button_type = ACPI_SLEEP_BUTTON;
108             ret = 0;
109         } else if (acpi_MatchHid(dev, "ACPI_FSB")) {
110             device_set_desc(dev, "Sleep Button (fixed)");
111             sc->button_type = ACPI_SLEEP_BUTTON;
112             sc->fixed = 1;
113             ret = 0;
114         }
115     }
116     return (ret);
117 }
118
119 static int
120 acpi_button_attach(device_t dev)
121 {
122     struct acpi_button_softc    *sc;
123     ACPI_STATUS                 status;
124     int event;
125
126     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
127
128     sc = device_get_softc(dev);
129     sc->button_dev = dev;
130     sc->button_handle = acpi_get_handle(dev);
131     event = (sc->button_type == ACPI_SLEEP_BUTTON) ?
132             ACPI_EVENT_SLEEP_BUTTON : ACPI_EVENT_POWER_BUTTON;
133
134     /* 
135      * Install the new handler.  We could remove any fixed handlers added
136      * from the FADT once we have a duplicate from the AML but some systems
137      * only return events on one or the other so we have to keep both.
138      */
139     if (sc->fixed) {
140         AcpiClearEvent(event);
141         status = AcpiInstallFixedEventHandler(event,
142                         acpi_button_fixed_handler, sc);
143     } else {
144         status = AcpiInstallNotifyHandler(sc->button_handle,
145                         ACPI_DEVICE_NOTIFY, acpi_button_notify_handler, sc);
146     }
147     if (ACPI_FAILURE(status)) {
148         device_printf(sc->button_dev, "couldn't install notify handler - %s\n",
149                       AcpiFormatException(status));
150         return_VALUE (ENXIO);
151     }
152     acpi_device_enable_wake_capability(sc->button_handle, 1);
153
154     return_VALUE (0);
155 }
156
157 static int
158 acpi_button_suspend(device_t dev)
159 {
160     struct acpi_button_softc    *sc;
161
162     sc = device_get_softc(dev);
163     acpi_device_enable_wake_event(sc->button_handle);
164     return (0);
165 }
166
167 static int
168 acpi_button_resume(device_t dev)
169 {
170     return (0);
171 }
172
173 static void
174 acpi_button_notify_sleep(void *arg)
175 {
176     struct acpi_button_softc    *sc;
177     struct acpi_softc           *acpi_sc;
178
179     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
180
181     sc = (struct acpi_button_softc *)arg;
182     acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
183     if (acpi_sc == NULL)
184         return_VOID;
185
186     acpi_UserNotify("Button", sc->button_handle, sc->button_type);
187
188     switch (sc->button_type) {
189     case ACPI_POWER_BUTTON:
190         ACPI_VPRINT(sc->button_dev, acpi_sc, "power button pressed\n");
191         acpi_event_power_button_sleep(acpi_sc);
192         break;
193     case ACPI_SLEEP_BUTTON:
194         ACPI_VPRINT(sc->button_dev, acpi_sc, "sleep button pressed\n");
195         acpi_event_sleep_button_sleep(acpi_sc);
196         break;
197     default:
198         break;          /* unknown button type */
199     }
200 }
201
202 static void
203 acpi_button_notify_wakeup(void *arg)
204 {
205     struct acpi_button_softc    *sc;
206     struct acpi_softc           *acpi_sc;
207
208     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
209
210     sc = (struct acpi_button_softc *)arg;
211     acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
212     if (acpi_sc == NULL)
213         return_VOID;
214
215     acpi_UserNotify("Button", sc->button_handle, sc->button_type);
216
217     switch (sc->button_type) {
218     case ACPI_POWER_BUTTON:
219         ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by power button\n");
220         acpi_event_power_button_wake(acpi_sc);
221         break;
222     case ACPI_SLEEP_BUTTON:
223         ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by sleep button\n");
224         acpi_event_sleep_button_wake(acpi_sc);
225         break;
226     default:
227         break;          /* unknown button type */
228     }
229 }
230
231 static void 
232 acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
233 {
234     struct acpi_button_softc    *sc = (struct acpi_button_softc *)context;
235
236     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify);
237
238     switch (notify) {
239     case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP:
240         AcpiOsQueueForExecution(OSD_PRIORITY_LO,
241                                 acpi_button_notify_sleep, sc);
242         break;   
243     case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP:
244         AcpiOsQueueForExecution(OSD_PRIORITY_LO,
245                                 acpi_button_notify_wakeup, sc);
246         break;   
247     default:
248         break;          /* unknown notification value */
249     }
250 }
251
252 static ACPI_STATUS 
253 acpi_button_fixed_handler(void *context)
254 {
255     struct acpi_button_softc    *sc = (struct acpi_button_softc *)context;
256
257     ACPI_FUNCTION_TRACE_PTR((char *)(uintptr_t)__func__, context);
258
259     if (context == NULL)
260         return_ACPI_STATUS (AE_BAD_PARAMETER);
261
262     acpi_button_notify_handler(sc->button_handle,
263                                ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP, sc);
264     return_ACPI_STATUS (AE_OK);
265 }