2 * acpi_button.c - ACPI Button Driver ($Revision: 29 $)
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
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.
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.
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
29 #include <acpi_drivers.h>
37 #define _COMPONENT ACPI_BUTTON_COMPONENT
38 ACPI_MODULE_NAME ("acpi_button")
41 static int acpi_button_add (struct acpi_device
*device
);
42 static int acpi_button_remove (struct acpi_device
*device
, int type
);
44 static struct acpi_driver acpi_button_driver
= {
46 ACPI_BUTTON_DRIVER_NAME
,
50 "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
51 {acpi_button_add
,acpi_button_remove
}
56 struct acpi_device
*device
; /* Fixed button kludge */
61 struct acpi_device
*power_button
;
62 struct acpi_device
*sleep_button
;
63 struct acpi_device
*lid_button
;
65 /* --------------------------------------------------------------------------
67 -------------------------------------------------------------------------- */
75 struct acpi_button
*button
= (struct acpi_button
*) data
;
77 ACPI_FUNCTION_TRACE("acpi_button_notify");
79 if (!button
|| !button
->device
)
83 case ACPI_BUTTON_NOTIFY_STATUS
:
84 acpi_bus_generate_event(button
->device
, event
, ++button
->pushed
);
87 ACPI_DEBUG_PRINT((ACPI_DB_INFO
,
88 "Unsupported event [0x%x]\n", event
));
97 acpi_button_notify_fixed (
100 struct acpi_button
*button
= (struct acpi_button
*) data
;
102 ACPI_FUNCTION_TRACE("acpi_button_notify_fixed");
105 return_ACPI_STATUS(AE_BAD_PARAMETER
);
107 acpi_button_notify(button
->handle
, ACPI_BUTTON_NOTIFY_STATUS
, button
);
109 return_ACPI_STATUS(AE_OK
);
115 struct acpi_device
*device
)
118 ACPI_STATUS status
= AE_OK
;
119 struct acpi_button
*button
= NULL
;
121 ACPI_FUNCTION_TRACE("acpi_button_add");
126 button
= ExAllocatePoolWithTag(NonPagedPool
,sizeof(struct acpi_button
), 'IPCA');
129 memset(button
, 0, sizeof(struct acpi_button
));
131 button
->device
= device
;
132 button
->handle
= device
->handle
;
133 acpi_driver_data(device
) = button
;
136 * Determine the button type (via hid), as fixed-feature buttons
137 * need to be handled a bit differently than generic-space.
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
);
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
);
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
);
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
);
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
);
175 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
, "Unsupported hid [%s]\n",
176 acpi_device_hid(device
)));
182 * Ensure only one button of each type is used.
184 switch (button
->type
) {
185 case ACPI_BUTTON_TYPE_POWER
:
186 case ACPI_BUTTON_TYPE_POWERF
:
188 power_button
= device
;
190 ExFreePoolWithTag(button
, 'IPCA');
194 case ACPI_BUTTON_TYPE_SLEEP
:
195 case ACPI_BUTTON_TYPE_SLEEPF
:
197 sleep_button
= device
;
199 ExFreePoolWithTag(button
, 'IPCA');
203 case ACPI_BUTTON_TYPE_LID
:
207 ExFreePoolWithTag(button
, 'IPCA');
213 switch (button
->type
) {
214 case ACPI_BUTTON_TYPE_POWERF
:
215 status
= AcpiInstallFixedEventHandler (
216 ACPI_EVENT_POWER_BUTTON
,
217 acpi_button_notify_fixed
,
220 case ACPI_BUTTON_TYPE_SLEEPF
:
221 status
= AcpiInstallFixedEventHandler (
222 ACPI_EVENT_SLEEP_BUTTON
,
223 acpi_button_notify_fixed
,
226 case ACPI_BUTTON_TYPE_LID
:
227 status
= AcpiInstallFixedEventHandler (
228 ACPI_BUTTON_TYPE_LID
,
229 acpi_button_notify_fixed
,
233 status
= AcpiInstallNotifyHandler (
241 if (ACPI_FAILURE(status
)) {
242 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
243 "Error installing notify handler\n"));
249 acpi_device_name(device
), acpi_device_bid(device
));
253 ExFreePoolWithTag(button
, 'IPCA');
256 return_VALUE(result
);
261 acpi_button_remove (struct acpi_device
*device
, int type
)
263 ACPI_STATUS status
= 0;
264 struct acpi_button
*button
= NULL
;
266 ACPI_FUNCTION_TRACE("acpi_button_remove");
268 if (!device
|| !acpi_driver_data(device
))
271 button
= acpi_driver_data(device
);
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
);
279 case ACPI_BUTTON_TYPE_SLEEPF
:
280 status
= AcpiRemoveFixedEventHandler(
281 ACPI_EVENT_SLEEP_BUTTON
, acpi_button_notify_fixed
);
283 case ACPI_BUTTON_TYPE_LID
:
284 status
= AcpiRemoveFixedEventHandler(
285 ACPI_BUTTON_TYPE_LID
, acpi_button_notify_fixed
);
288 status
= AcpiRemoveNotifyHandler(button
->handle
,
289 ACPI_DEVICE_NOTIFY
, acpi_button_notify
);
293 if (ACPI_FAILURE(status
))
294 ACPI_DEBUG_PRINT((ACPI_DB_ERROR
,
295 "Error removing notify handler\n"));
297 ExFreePoolWithTag(button
, 'IPCA');
304 acpi_button_init (void)
308 ACPI_FUNCTION_TRACE("acpi_button_init");
310 result
= acpi_bus_register_driver(&acpi_button_driver
);
320 acpi_button_exit (void)
322 ACPI_FUNCTION_TRACE("acpi_button_exit");
324 acpi_bus_unregister_driver(&acpi_button_driver
);