sync with trunk r46493
[reactos.git] / drivers / bus / acpi / busmgr / button.c
1 /*
2 * acpi_button.c - ACPI Button Driver ($Revision: 29 $)
3 *
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
6 *
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 */
25 #include <ntddk.h>
26
27 #include <acpi.h>
28 #include <acpi_bus.h>
29 #include <acpi_drivers.h>
30 #include <glue.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35
36
37 #define _COMPONENT ACPI_BUTTON_COMPONENT
38 ACPI_MODULE_NAME ("acpi_button")
39
40
41 static int acpi_button_add (struct acpi_device *device);
42 static int acpi_button_remove (struct acpi_device *device, int type);
43
44 static struct acpi_driver acpi_button_driver = {
45 .name = ACPI_BUTTON_DRIVER_NAME,
46 .class = ACPI_BUTTON_CLASS,
47 .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
48 .ops = {
49 .add = acpi_button_add,
50 .remove = acpi_button_remove,
51 },
52 };
53
54 struct acpi_button {
55 ACPI_HANDLE handle;
56 struct acpi_device *device; /* Fixed button kludge */
57 UINT8 type;
58 unsigned long pushed;
59 };
60
61 struct acpi_device *power_button;
62 struct acpi_device *sleep_button;
63 struct acpi_device *lid_button;
64
65 /* --------------------------------------------------------------------------
66 Driver Interface
67 -------------------------------------------------------------------------- */
68
69 void
70 acpi_button_notify (
71 ACPI_HANDLE handle,
72 UINT32 event,
73 void *data)
74 {
75 struct acpi_button *button = (struct acpi_button *) data;
76
77 ACPI_FUNCTION_TRACE("acpi_button_notify");
78
79 if (!button || !button->device)
80 return_VOID;
81
82 switch (event) {
83 case ACPI_BUTTON_NOTIFY_STATUS:
84 acpi_bus_generate_event(button->device, event, ++button->pushed);
85 break;
86 default:
87 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
88 "Unsupported event [0x%x]\n", event));
89 break;
90 }
91
92 return_VOID;
93 }
94
95
96 ACPI_STATUS
97 acpi_button_notify_fixed (
98 void *data)
99 {
100 struct acpi_button *button = (struct acpi_button *) data;
101
102 ACPI_FUNCTION_TRACE("acpi_button_notify_fixed");
103
104 if (!button)
105 return_ACPI_STATUS(AE_BAD_PARAMETER);
106
107 acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
108
109 return_ACPI_STATUS(AE_OK);
110 }
111
112
113 static int
114 acpi_button_add (
115 struct acpi_device *device)
116 {
117 int result = 0;
118 ACPI_STATUS status = AE_OK;
119 struct acpi_button *button = NULL;
120
121 ACPI_FUNCTION_TRACE("acpi_button_add");
122
123 if (!device)
124 return_VALUE(-1);
125
126 button = ExAllocatePool(NonPagedPool,sizeof(struct acpi_button));
127 if (!button)
128 return_VALUE(-4);
129 memset(button, 0, sizeof(struct acpi_button));
130
131 button->device = device;
132 button->handle = device->handle;
133 acpi_driver_data(device) = button;
134
135 /*
136 * Determine the button type (via hid), as fixed-feature buttons
137 * need to be handled a bit differently than generic-space.
138 */
139 if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
140 button->type = ACPI_BUTTON_TYPE_POWER;
141 sprintf(acpi_device_name(device), "%s",
142 ACPI_BUTTON_DEVICE_NAME_POWER);
143 sprintf(acpi_device_class(device), "%s/%s",
144 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
145 }
146 else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
147 button->type = ACPI_BUTTON_TYPE_POWERF;
148 sprintf(acpi_device_name(device), "%s",
149 ACPI_BUTTON_DEVICE_NAME_POWERF);
150 sprintf(acpi_device_class(device), "%s/%s",
151 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
152 }
153 else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) {
154 button->type = ACPI_BUTTON_TYPE_SLEEP;
155 sprintf(acpi_device_name(device), "%s",
156 ACPI_BUTTON_DEVICE_NAME_SLEEP);
157 sprintf(acpi_device_class(device), "%s/%s",
158 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
159 }
160 else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
161 button->type = ACPI_BUTTON_TYPE_SLEEPF;
162 sprintf(acpi_device_name(device), "%s",
163 ACPI_BUTTON_DEVICE_NAME_SLEEPF);
164 sprintf(acpi_device_class(device), "%s/%s",
165 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
166 }
167 else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) {
168 button->type = ACPI_BUTTON_TYPE_LID;
169 sprintf(acpi_device_name(device), "%s",
170 ACPI_BUTTON_DEVICE_NAME_LID);
171 sprintf(acpi_device_class(device), "%s/%s",
172 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
173 }
174 else {
175 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n",
176 acpi_device_hid(device)));
177 result = -15;
178 goto end;
179 }
180
181 /*
182 * Ensure only one button of each type is used.
183 */
184 switch (button->type) {
185 case ACPI_BUTTON_TYPE_POWER:
186 case ACPI_BUTTON_TYPE_POWERF:
187 if (!power_button)
188 power_button = device;
189 else {
190 ExFreePool(button);
191 return_VALUE(-15);
192 }
193 break;
194 case ACPI_BUTTON_TYPE_SLEEP:
195 case ACPI_BUTTON_TYPE_SLEEPF:
196 if (!sleep_button)
197 sleep_button = device;
198 else {
199 ExFreePool(button);
200 return_VALUE(-15);
201 }
202 break;
203 case ACPI_BUTTON_TYPE_LID:
204 if (!lid_button)
205 lid_button = device;
206 else {
207 ExFreePool(button);
208 return_VALUE(-15);
209 }
210 break;
211 }
212
213 switch (button->type) {
214 case ACPI_BUTTON_TYPE_POWERF:
215 status = AcpiInstallFixedEventHandler (
216 ACPI_EVENT_POWER_BUTTON,
217 acpi_button_notify_fixed,
218 button);
219 break;
220 case ACPI_BUTTON_TYPE_SLEEPF:
221 status = AcpiInstallFixedEventHandler (
222 ACPI_EVENT_SLEEP_BUTTON,
223 acpi_button_notify_fixed,
224 button);
225 break;
226 case ACPI_BUTTON_TYPE_LID:
227 status = AcpiInstallFixedEventHandler (
228 ACPI_BUTTON_TYPE_LID,
229 acpi_button_notify_fixed,
230 button);
231 break;
232 default:
233 status = AcpiInstallNotifyHandler (
234 button->handle,
235 ACPI_DEVICE_NOTIFY,
236 acpi_button_notify,
237 button);
238 break;
239 }
240
241 if (ACPI_FAILURE(status)) {
242 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
243 "Error installing notify handler\n"));
244 result = -15;
245 goto end;
246 }
247
248 DPRINT("%s [%s]\n",
249 acpi_device_name(device), acpi_device_bid(device));
250
251 end:
252 if (result) {
253 ExFreePool(button);
254 }
255
256 return_VALUE(result);
257 }
258
259
260 static int
261 acpi_button_remove (struct acpi_device *device, int type)
262 {
263 ACPI_STATUS status = 0;
264 struct acpi_button *button = NULL;
265
266 ACPI_FUNCTION_TRACE("acpi_button_remove");
267
268 if (!device || !acpi_driver_data(device))
269 return_VALUE(-1);
270
271 button = acpi_driver_data(device);
272
273 /* Unregister for device notifications. */
274 switch (button->type) {
275 case ACPI_BUTTON_TYPE_POWERF:
276 status = AcpiRemoveFixedEventHandler(
277 ACPI_EVENT_POWER_BUTTON, acpi_button_notify_fixed);
278 break;
279 case ACPI_BUTTON_TYPE_SLEEPF:
280 status = AcpiRemoveFixedEventHandler(
281 ACPI_EVENT_SLEEP_BUTTON, acpi_button_notify_fixed);
282 break;
283 case ACPI_BUTTON_TYPE_LID:
284 status = AcpiRemoveFixedEventHandler(
285 ACPI_BUTTON_TYPE_LID, acpi_button_notify_fixed);
286 break;
287 default:
288 status = AcpiRemoveNotifyHandler(button->handle,
289 ACPI_DEVICE_NOTIFY, acpi_button_notify);
290 break;
291 }
292
293 if (ACPI_FAILURE(status))
294 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
295 "Error removing notify handler\n"));
296
297 ExFreePool(button);
298
299 return_VALUE(0);
300 }
301
302
303 int
304 acpi_button_init (void)
305 {
306 int result = 0;
307
308 ACPI_FUNCTION_TRACE("acpi_button_init");
309
310 result = acpi_bus_register_driver(&acpi_button_driver);
311 if (result < 0) {
312 return_VALUE(-15);
313 }
314
315 return_VALUE(0);
316 }
317
318
319 void
320 acpi_button_exit (void)
321 {
322 ACPI_FUNCTION_TRACE("acpi_button_exit");
323
324 acpi_bus_unregister_driver(&acpi_button_driver);
325
326 return_VOID;
327 }
328
329