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