xref: /freebsd/sys/dev/acpica/acpi_button.c (revision 0fddbf874719b9bd50cf66ac26d1140bb3f2be69)
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$
29  */
30 
31 #include "opt_acpi.h"
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/bus.h>
35 
36 #include "acpi.h"
37 
38 #include <dev/acpica/acpivar.h>
39 
40 /*
41  * Hooks for the ACPI CA debugging infrastructure
42  */
43 #define _COMPONENT	ACPI_BUTTON
44 MODULE_NAME("BUTTON")
45 
46 struct acpi_button_softc {
47     device_t	button_dev;
48     ACPI_HANDLE	button_handle;
49 #define ACPI_POWER_BUTTON	0
50 #define ACPI_SLEEP_BUTTON	1
51     boolean_t	button_type;	/* Power or Sleep Button */
52 };
53 
54 static int	acpi_button_probe(device_t dev);
55 static int	acpi_button_attach(device_t dev);
56 static void 	acpi_button_notify_handler(ACPI_HANDLE h,UINT32 notify, void *context);
57 static void	acpi_button_notify_pressed_for_sleep(void *arg);
58 static void	acpi_button_notify_pressed_for_wakeup(void *arg);
59 
60 static device_method_t acpi_button_methods[] = {
61     /* Device interface */
62     DEVMETHOD(device_probe,	acpi_button_probe),
63     DEVMETHOD(device_attach,	acpi_button_attach),
64 
65     {0, 0}
66 };
67 
68 static driver_t acpi_button_driver = {
69     "acpi_button",
70     acpi_button_methods,
71     sizeof(struct acpi_button_softc),
72 };
73 
74 devclass_t acpi_button_devclass;
75 DRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass, 0, 0);
76 
77 static int
78 acpi_button_probe(device_t dev)
79 {
80     struct acpi_button_softc	*sc;
81 
82     sc = device_get_softc(dev);
83     if (acpi_get_type(dev) == ACPI_TYPE_DEVICE) {
84 	if (!acpi_disabled("button")) {
85 	    if (acpi_MatchHid(dev, "PNP0C0C")) {
86 		device_set_desc(dev, "Power Button");
87 		sc->button_type = ACPI_POWER_BUTTON;
88 		return(0);
89 	    }
90 	    if (acpi_MatchHid(dev, "PNP0C0E")) {
91 		device_set_desc(dev, "Sleep Button");
92 		sc->button_type = ACPI_SLEEP_BUTTON;
93 		return(0);
94 	    }
95 	}
96     }
97     return(ENXIO);
98 }
99 
100 static int
101 acpi_button_attach(device_t dev)
102 {
103     struct acpi_button_softc	*sc;
104     ACPI_STATUS			status;
105 
106     FUNCTION_TRACE(__func__);
107 
108     sc = device_get_softc(dev);
109     sc->button_dev = dev;
110     sc->button_handle = acpi_get_handle(dev);
111 
112     if ((status = AcpiInstallNotifyHandler(sc->button_handle, ACPI_DEVICE_NOTIFY,
113 					   acpi_button_notify_handler, sc)) != AE_OK) {
114 	device_printf(sc->button_dev, "couldn't install Notify handler - %s\n", AcpiFormatException(status));
115 	return_VALUE(ENXIO);
116     }
117     return_VALUE(0);
118 }
119 
120 static void
121 acpi_button_notify_pressed_for_sleep(void *arg)
122 {
123     struct acpi_button_softc	*sc;
124     struct acpi_softc		*acpi_sc;
125 
126     FUNCTION_TRACE(__func__);
127 
128     sc = (struct acpi_button_softc *)arg;
129     acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
130     if (acpi_sc == NULL) {
131 	return_VOID;
132     }
133 
134     switch (sc->button_type) {
135     case ACPI_POWER_BUTTON:
136 	device_printf(sc->button_dev, "power button pressed\n", sc->button_type);
137 	acpi_eventhandler_power_button_for_sleep((void *)acpi_sc);
138 	break;
139     case ACPI_SLEEP_BUTTON:
140 	device_printf(sc->button_dev, "sleep button pressed\n", sc->button_type);
141 	acpi_eventhandler_sleep_button_for_sleep((void *)acpi_sc);
142 	break;
143     default:
144 	break;		/* unknown button type */
145     }
146     return_VOID;
147 }
148 
149 static void
150 acpi_button_notify_pressed_for_wakeup(void *arg)
151 {
152     struct acpi_button_softc	*sc;
153     struct acpi_softc		*acpi_sc;
154 
155     FUNCTION_TRACE(__func__);
156 
157     sc = (struct acpi_button_softc *)arg;
158     acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
159     if (acpi_sc == NULL) {
160 	return_VOID;
161     }
162 
163     switch (sc->button_type) {
164     case ACPI_POWER_BUTTON:
165 	device_printf(sc->button_dev, "wakeup by power button\n", sc->button_type);
166 	acpi_eventhandler_power_button_for_wakeup((void *)acpi_sc);
167 	break;
168     case ACPI_SLEEP_BUTTON:
169 	device_printf(sc->button_dev, "wakeup by sleep button\n", sc->button_type);
170 	acpi_eventhandler_sleep_button_for_wakeup((void *)acpi_sc);
171 	break;
172     default:
173 	break;		/* unknown button type */
174     }
175     return_VOID;
176 }
177 
178 /* XXX maybe not here */
179 #define ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP	0x80
180 #define ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP	0x02
181 
182 static void
183 acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
184 {
185     struct acpi_button_softc	*sc = (struct acpi_button_softc *)context;
186 
187     FUNCTION_TRACE_U32(__func__, notify);
188 
189     switch (notify) {
190     case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP:
191 	AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_button_notify_pressed_for_sleep, sc);
192 	break;
193     case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP:
194 	AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_button_notify_pressed_for_wakeup, sc);
195 	break;
196     default:
197 	break;		/* unknown notification value */
198     }
199     return_VOID;
200 }
201 
202 
203