xref: /freebsd/sys/dev/acpica/acpi_button.c (revision eacee0ff7ec955b32e09515246bd97b6edcd2b0f)
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 static 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 	ACPI_VPRINT(sc->button_dev, acpi_sc,
137 	    "power button pressed\n", sc->button_type);
138 	acpi_eventhandler_power_button_for_sleep((void *)acpi_sc);
139 	break;
140     case ACPI_SLEEP_BUTTON:
141 	ACPI_VPRINT(sc->button_dev, acpi_sc,
142 	    "sleep button pressed\n", sc->button_type);
143 	acpi_eventhandler_sleep_button_for_sleep((void *)acpi_sc);
144 	break;
145     default:
146 	break;		/* unknown button type */
147     }
148     return_VOID;
149 }
150 
151 static void
152 acpi_button_notify_pressed_for_wakeup(void *arg)
153 {
154     struct acpi_button_softc	*sc;
155     struct acpi_softc		*acpi_sc;
156 
157     FUNCTION_TRACE(__func__);
158 
159     sc = (struct acpi_button_softc *)arg;
160     acpi_sc = acpi_device_get_parent_softc(sc->button_dev);
161     if (acpi_sc == NULL) {
162 	return_VOID;
163     }
164 
165     switch (sc->button_type) {
166     case ACPI_POWER_BUTTON:
167 	ACPI_VPRINT(sc->button_dev, acpi_sc,
168 	    "wakeup by power button\n", sc->button_type);
169 	acpi_eventhandler_power_button_for_wakeup((void *)acpi_sc);
170 	break;
171     case ACPI_SLEEP_BUTTON:
172 	ACPI_VPRINT(sc->button_dev, acpi_sc,
173 	    "wakeup by sleep button\n", sc->button_type);
174 	acpi_eventhandler_sleep_button_for_wakeup((void *)acpi_sc);
175 	break;
176     default:
177 	break;		/* unknown button type */
178     }
179     return_VOID;
180 }
181 
182 /* XXX maybe not here */
183 #define ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP	0x80
184 #define ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP	0x02
185 
186 static void
187 acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
188 {
189     struct acpi_button_softc	*sc = (struct acpi_button_softc *)context;
190 
191     FUNCTION_TRACE_U32(__func__, notify);
192 
193     switch (notify) {
194     case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP:
195 	AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_button_notify_pressed_for_sleep, sc);
196 	break;
197     case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP:
198 	AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_button_notify_pressed_for_wakeup, sc);
199 	break;
200     default:
201 	break;		/* unknown notification value */
202     }
203     return_VOID;
204 }
205 
206 
207