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 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28 #include <linux/init.h>
29 #include <linux/types.h>
30 #include <linux/compatmac.h>
31 #include <linux/proc_fs.h>
32 #include <acpi/acpi_bus.h>
33 #include <acpi/acpi_drivers.h>
36 #define _COMPONENT ACPI_BUTTON_COMPONENT
37 ACPI_MODULE_NAME ("acpi_button")
39 MODULE_AUTHOR("Paul Diefenbaugh");
40 MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
41 MODULE_LICENSE("GPL");
43 #define PREFIX "ACPI: "
46 static int acpi_button_add (struct acpi_device *device);
47 static int acpi_button_remove (struct acpi_device *device, int type);
49 static struct acpi_driver acpi_button_driver = {
50 .name = ACPI_BUTTON_DRIVER_NAME,
51 .class = ACPI_BUTTON_CLASS,
52 .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
54 .add = acpi_button_add,
55 .remove = acpi_button_remove,
61 struct acpi_device *device; /* Fixed button kludge */
67 /* --------------------------------------------------------------------------
69 -------------------------------------------------------------------------- */
71 static struct proc_dir_entry *acpi_button_dir;
74 acpi_button_read_info (
82 struct acpi_button *button = (struct acpi_button *) data;
86 ACPI_FUNCTION_TRACE("acpi_button_read_info");
88 if (!button || !button->device || (off != 0))
91 p += sprintf(p, "type: %s\n",
92 acpi_device_name(button->device));
96 if (len <= off+count) *eof = 1;
99 if (len>count) len = count;
106 acpi_button_lid_read_state(
114 struct acpi_button *button = (struct acpi_button *) data;
117 acpi_status status=AE_OK;
120 ACPI_FUNCTION_TRACE("acpi_button_lid_read_state");
122 if (!button || !button->device || (off != 0))
125 status=acpi_evaluate_integer(button->handle,"_LID",NULL,&state);
126 if (ACPI_FAILURE(status)){
127 p += sprintf(p, "state: unsupported\n");
130 p += sprintf(p, "state: %s\n", (state ? "open" : "closed"));
135 if (len <= off+count) *eof = 1;
138 if (len>count) len = count;
146 struct acpi_device *device)
148 struct proc_dir_entry *entry = NULL;
149 struct acpi_button *button = NULL;
151 ACPI_FUNCTION_TRACE("acpi_button_add_fs");
153 if (!device || !acpi_driver_data(device))
154 return_VALUE(-EINVAL);
156 button = acpi_driver_data(device);
158 switch (button->type) {
159 case ACPI_BUTTON_TYPE_POWER:
160 case ACPI_BUTTON_TYPE_POWERF:
161 entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
164 case ACPI_BUTTON_TYPE_SLEEP:
165 case ACPI_BUTTON_TYPE_SLEEPF:
166 entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
169 case ACPI_BUTTON_TYPE_LID:
170 entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
176 return_VALUE(-ENODEV);
177 entry->owner = THIS_MODULE;
179 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
180 if (!acpi_device_dir(device))
181 return_VALUE(-ENODEV);
182 acpi_device_dir(device)->owner = THIS_MODULE;
185 entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
186 S_IRUGO, acpi_device_dir(device));
188 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
189 "Unable to create '%s' fs entry\n",
190 ACPI_BUTTON_FILE_INFO));
192 entry->read_proc = acpi_button_read_info;
193 entry->data = acpi_driver_data(device);
194 entry->owner = THIS_MODULE;
197 if (button->type==ACPI_BUTTON_TYPE_LID){
199 entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
200 S_IRUGO, acpi_device_dir(device));
202 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
203 "Unable to create '%s' fs entry\n",
204 ACPI_BUTTON_FILE_STATE));
206 entry->read_proc = acpi_button_lid_read_state;
207 entry->data = acpi_driver_data(device);
208 entry->owner = THIS_MODULE;
217 acpi_button_remove_fs (
218 struct acpi_device *device)
220 struct acpi_button *button = NULL;
222 ACPI_FUNCTION_TRACE("acpi_button_remove_fs");
224 button = acpi_driver_data(device);
225 if (acpi_device_dir(device)) {
226 if (button->type == ACPI_BUTTON_TYPE_LID)
227 remove_proc_entry(ACPI_BUTTON_FILE_STATE,
228 acpi_device_dir(device));
229 remove_proc_entry(ACPI_BUTTON_FILE_INFO,
230 acpi_device_dir(device));
232 remove_proc_entry(acpi_device_bid(device),
233 acpi_device_dir(device)->parent);
235 switch (button->type) {
236 case ACPI_BUTTON_TYPE_POWER:
237 case ACPI_BUTTON_TYPE_POWERF:
238 remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER,
241 case ACPI_BUTTON_TYPE_SLEEP:
242 case ACPI_BUTTON_TYPE_SLEEPF:
243 remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP,
246 case ACPI_BUTTON_TYPE_LID:
247 remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID,
251 acpi_device_dir(device) = NULL;
258 /* --------------------------------------------------------------------------
260 -------------------------------------------------------------------------- */
268 struct acpi_button *button = (struct acpi_button *) data;
270 ACPI_FUNCTION_TRACE("acpi_button_notify");
272 if (!button || !button->device)
276 case ACPI_BUTTON_NOTIFY_STATUS:
277 acpi_bus_generate_event(button->device, event, ++button->pushed);
280 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
281 "Unsupported event [0x%x]\n", event));
290 acpi_button_notify_fixed (
293 struct acpi_button *button = (struct acpi_button *) data;
295 ACPI_FUNCTION_TRACE("acpi_button_notify_fixed");
298 return_ACPI_STATUS(AE_BAD_PARAMETER);
300 acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
302 return_ACPI_STATUS(AE_OK);
308 struct acpi_device *device)
311 acpi_status status = AE_OK;
312 struct acpi_button *button = NULL;
314 static struct acpi_device *power_button;
315 static struct acpi_device *sleep_button;
316 static struct acpi_device *lid_button;
318 ACPI_FUNCTION_TRACE("acpi_button_add");
321 return_VALUE(-EINVAL);
323 button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL);
325 return_VALUE(-ENOMEM);
326 memset(button, 0, sizeof(struct acpi_button));
328 button->device = device;
329 button->handle = device->handle;
330 acpi_driver_data(device) = button;
333 * Determine the button type (via hid), as fixed-feature buttons
334 * need to be handled a bit differently than generic-space.
336 if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
337 button->type = ACPI_BUTTON_TYPE_POWER;
338 sprintf(acpi_device_name(device), "%s",
339 ACPI_BUTTON_DEVICE_NAME_POWER);
340 sprintf(acpi_device_class(device), "%s/%s",
341 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
343 else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
344 button->type = ACPI_BUTTON_TYPE_POWERF;
345 sprintf(acpi_device_name(device), "%s",
346 ACPI_BUTTON_DEVICE_NAME_POWERF);
347 sprintf(acpi_device_class(device), "%s/%s",
348 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
350 else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) {
351 button->type = ACPI_BUTTON_TYPE_SLEEP;
352 sprintf(acpi_device_name(device), "%s",
353 ACPI_BUTTON_DEVICE_NAME_SLEEP);
354 sprintf(acpi_device_class(device), "%s/%s",
355 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
357 else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
358 button->type = ACPI_BUTTON_TYPE_SLEEPF;
359 sprintf(acpi_device_name(device), "%s",
360 ACPI_BUTTON_DEVICE_NAME_SLEEPF);
361 sprintf(acpi_device_class(device), "%s/%s",
362 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
364 else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) {
365 button->type = ACPI_BUTTON_TYPE_LID;
366 sprintf(acpi_device_name(device), "%s",
367 ACPI_BUTTON_DEVICE_NAME_LID);
368 sprintf(acpi_device_class(device), "%s/%s",
369 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
372 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n",
373 acpi_device_hid(device)));
379 * Ensure only one button of each type is used.
381 switch (button->type) {
382 case ACPI_BUTTON_TYPE_POWER:
383 case ACPI_BUTTON_TYPE_POWERF:
385 power_button = device;
388 return_VALUE(-ENODEV);
391 case ACPI_BUTTON_TYPE_SLEEP:
392 case ACPI_BUTTON_TYPE_SLEEPF:
394 sleep_button = device;
397 return_VALUE(-ENODEV);
400 case ACPI_BUTTON_TYPE_LID:
405 return_VALUE(-ENODEV);
410 result = acpi_button_add_fs(device);
414 switch (button->type) {
415 case ACPI_BUTTON_TYPE_POWERF:
416 status = acpi_install_fixed_event_handler (
417 ACPI_EVENT_POWER_BUTTON,
418 acpi_button_notify_fixed,
421 case ACPI_BUTTON_TYPE_SLEEPF:
422 status = acpi_install_fixed_event_handler (
423 ACPI_EVENT_SLEEP_BUTTON,
424 acpi_button_notify_fixed,
428 status = acpi_install_notify_handler (
436 if (ACPI_FAILURE(status)) {
437 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
438 "Error installing notify handler\n"));
443 printk(KERN_INFO PREFIX "%s [%s]\n",
444 acpi_device_name(device), acpi_device_bid(device));
448 acpi_button_remove_fs(device);
452 return_VALUE(result);
457 acpi_button_remove (struct acpi_device *device, int type)
459 acpi_status status = 0;
460 struct acpi_button *button = NULL;
462 ACPI_FUNCTION_TRACE("acpi_button_remove");
464 if (!device || !acpi_driver_data(device))
465 return_VALUE(-EINVAL);
467 button = acpi_driver_data(device);
469 /* Unregister for device notifications. */
470 switch (button->type) {
471 case ACPI_BUTTON_TYPE_POWERF:
472 status = acpi_remove_fixed_event_handler(
473 ACPI_EVENT_POWER_BUTTON, acpi_button_notify_fixed);
475 case ACPI_BUTTON_TYPE_SLEEPF:
476 status = acpi_remove_fixed_event_handler(
477 ACPI_EVENT_SLEEP_BUTTON, acpi_button_notify_fixed);
480 status = acpi_remove_notify_handler(button->handle,
481 ACPI_DEVICE_NOTIFY, acpi_button_notify);
485 if (ACPI_FAILURE(status))
486 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
487 "Error removing notify handler\n"));
489 acpi_button_remove_fs(device);
498 acpi_button_init (void)
502 ACPI_FUNCTION_TRACE("acpi_button_init");
504 acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
505 if (!acpi_button_dir)
506 return_VALUE(-ENODEV);
507 acpi_button_dir->owner = THIS_MODULE;
509 result = acpi_bus_register_driver(&acpi_button_driver);
511 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
512 return_VALUE(-ENODEV);
520 acpi_button_exit (void)
522 ACPI_FUNCTION_TRACE("acpi_button_exit");
524 acpi_bus_unregister_driver(&acpi_button_driver);
526 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
532 module_init(acpi_button_init);
533 module_exit(acpi_button_exit);