aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/button.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/button.c')
-rw-r--r--drivers/acpi/button.c223
1 files changed, 138 insertions, 85 deletions
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 5ef885e82c78..ac860583c203 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -29,6 +29,7 @@
29#include <linux/types.h> 29#include <linux/types.h>
30#include <linux/proc_fs.h> 30#include <linux/proc_fs.h>
31#include <linux/seq_file.h> 31#include <linux/seq_file.h>
32#include <linux/input.h>
32#include <acpi/acpi_bus.h> 33#include <acpi/acpi_bus.h>
33#include <acpi/acpi_drivers.h> 34#include <acpi/acpi_drivers.h>
34 35
@@ -62,7 +63,7 @@
62#define _COMPONENT ACPI_BUTTON_COMPONENT 63#define _COMPONENT ACPI_BUTTON_COMPONENT
63ACPI_MODULE_NAME("acpi_button") 64ACPI_MODULE_NAME("acpi_button")
64 65
65 MODULE_AUTHOR("Paul Diefenbaugh"); 66MODULE_AUTHOR("Paul Diefenbaugh");
66MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME); 67MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
67MODULE_LICENSE("GPL"); 68MODULE_LICENSE("GPL");
68 69
@@ -78,12 +79,14 @@ static struct acpi_driver acpi_button_driver = {
78 .ops = { 79 .ops = {
79 .add = acpi_button_add, 80 .add = acpi_button_add,
80 .remove = acpi_button_remove, 81 .remove = acpi_button_remove,
81 }, 82 },
82}; 83};
83 84
84struct acpi_button { 85struct acpi_button {
85 struct acpi_device *device; /* Fixed button kludge */ 86 struct acpi_device *device; /* Fixed button kludge */
86 u8 type; 87 unsigned int type;
88 struct input_dev *input;
89 char phys[32]; /* for input device */
87 unsigned long pushed; 90 unsigned long pushed;
88}; 91};
89 92
@@ -109,8 +112,7 @@ static struct proc_dir_entry *acpi_button_dir;
109 112
110static int acpi_button_info_seq_show(struct seq_file *seq, void *offset) 113static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
111{ 114{
112 struct acpi_button *button = (struct acpi_button *)seq->private; 115 struct acpi_button *button = seq->private;
113
114 116
115 if (!button || !button->device) 117 if (!button || !button->device)
116 return 0; 118 return 0;
@@ -128,22 +130,17 @@ static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
128 130
129static int acpi_button_state_seq_show(struct seq_file *seq, void *offset) 131static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
130{ 132{
131 struct acpi_button *button = (struct acpi_button *)seq->private; 133 struct acpi_button *button = seq->private;
132 acpi_status status; 134 acpi_status status;
133 unsigned long state; 135 unsigned long state;
134 136
135
136 if (!button || !button->device) 137 if (!button || !button->device)
137 return 0; 138 return 0;
138 139
139 status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state); 140 status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state);
140 if (ACPI_FAILURE(status)) { 141 seq_printf(seq, "state: %s\n",
141 seq_printf(seq, "state: unsupported\n"); 142 ACPI_FAILURE(status) ? "unsupported" :
142 } else { 143 (state ? "open" : "closed"));
143 seq_printf(seq, "state: %s\n",
144 (state ? "open" : "closed"));
145 }
146
147 return 0; 144 return 0;
148} 145}
149 146
@@ -159,8 +156,7 @@ static struct proc_dir_entry *acpi_lid_dir;
159static int acpi_button_add_fs(struct acpi_device *device) 156static int acpi_button_add_fs(struct acpi_device *device)
160{ 157{
161 struct proc_dir_entry *entry = NULL; 158 struct proc_dir_entry *entry = NULL;
162 struct acpi_button *button = NULL; 159 struct acpi_button *button;
163
164 160
165 if (!device || !acpi_driver_data(device)) 161 if (!device || !acpi_driver_data(device))
166 return -EINVAL; 162 return -EINVAL;
@@ -228,10 +224,8 @@ static int acpi_button_add_fs(struct acpi_device *device)
228 224
229static int acpi_button_remove_fs(struct acpi_device *device) 225static int acpi_button_remove_fs(struct acpi_device *device)
230{ 226{
231 struct acpi_button *button = NULL; 227 struct acpi_button *button = acpi_driver_data(device);
232
233 228
234 button = acpi_driver_data(device);
235 if (acpi_device_dir(device)) { 229 if (acpi_device_dir(device)) {
236 if (button->type == ACPI_BUTTON_TYPE_LID) 230 if (button->type == ACPI_BUTTON_TYPE_LID)
237 remove_proc_entry(ACPI_BUTTON_FILE_STATE, 231 remove_proc_entry(ACPI_BUTTON_FILE_STATE,
@@ -253,14 +247,34 @@ static int acpi_button_remove_fs(struct acpi_device *device)
253 247
254static void acpi_button_notify(acpi_handle handle, u32 event, void *data) 248static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
255{ 249{
256 struct acpi_button *button = (struct acpi_button *)data; 250 struct acpi_button *button = data;
257 251 struct input_dev *input;
258 252
259 if (!button || !button->device) 253 if (!button || !button->device)
260 return; 254 return;
261 255
262 switch (event) { 256 switch (event) {
263 case ACPI_BUTTON_NOTIFY_STATUS: 257 case ACPI_BUTTON_NOTIFY_STATUS:
258 input = button->input;
259
260 if (button->type == ACPI_BUTTON_TYPE_LID) {
261 struct acpi_handle *handle = button->device->handle;
262 unsigned long state;
263
264 if (!ACPI_FAILURE(acpi_evaluate_integer(handle, "_LID",
265 NULL, &state)))
266 input_report_switch(input, SW_LID, !state);
267
268 } else {
269 int keycode = test_bit(KEY_SLEEP, input->keybit) ?
270 KEY_SLEEP : KEY_POWER;
271
272 input_report_key(input, keycode, 1);
273 input_sync(input);
274 input_report_key(input, keycode, 0);
275 }
276 input_sync(input);
277
264 acpi_bus_generate_event(button->device, event, 278 acpi_bus_generate_event(button->device, event,
265 ++button->pushed); 279 ++button->pushed);
266 break; 280 break;
@@ -275,8 +289,7 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
275 289
276static acpi_status acpi_button_notify_fixed(void *data) 290static acpi_status acpi_button_notify_fixed(void *data)
277{ 291{
278 struct acpi_button *button = (struct acpi_button *)data; 292 struct acpi_button *button = data;
279
280 293
281 if (!button) 294 if (!button)
282 return AE_BAD_PARAMETER; 295 return AE_BAD_PARAMETER;
@@ -286,24 +299,75 @@ static acpi_status acpi_button_notify_fixed(void *data)
286 return AE_OK; 299 return AE_OK;
287} 300}
288 301
289static int acpi_button_add(struct acpi_device *device) 302static int acpi_button_install_notify_handlers(struct acpi_button *button)
290{ 303{
291 int result = 0; 304 acpi_status status;
292 acpi_status status = AE_OK;
293 struct acpi_button *button = NULL;
294 305
306 switch (button->type) {
307 case ACPI_BUTTON_TYPE_POWERF:
308 status =
309 acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
310 acpi_button_notify_fixed,
311 button);
312 break;
313 case ACPI_BUTTON_TYPE_SLEEPF:
314 status =
315 acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
316 acpi_button_notify_fixed,
317 button);
318 break;
319 default:
320 status = acpi_install_notify_handler(button->device->handle,
321 ACPI_DEVICE_NOTIFY,
322 acpi_button_notify,
323 button);
324 break;
325 }
326
327 return ACPI_FAILURE(status) ? -ENODEV : 0;
328}
329
330static void acpi_button_remove_notify_handlers(struct acpi_button *button)
331{
332 switch (button->type) {
333 case ACPI_BUTTON_TYPE_POWERF:
334 acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
335 acpi_button_notify_fixed);
336 break;
337 case ACPI_BUTTON_TYPE_SLEEPF:
338 acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
339 acpi_button_notify_fixed);
340 break;
341 default:
342 acpi_remove_notify_handler(button->device->handle,
343 ACPI_DEVICE_NOTIFY,
344 acpi_button_notify);
345 break;
346 }
347}
348
349static int acpi_button_add(struct acpi_device *device)
350{
351 int error;
352 struct acpi_button *button;
353 struct input_dev *input;
295 354
296 if (!device) 355 if (!device)
297 return -EINVAL; 356 return -EINVAL;
298 357
299 button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL); 358 button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
300 if (!button) 359 if (!button)
301 return -ENOMEM; 360 return -ENOMEM;
302 memset(button, 0, sizeof(struct acpi_button));
303 361
304 button->device = device; 362 button->device = device;
305 acpi_driver_data(device) = button; 363 acpi_driver_data(device) = button;
306 364
365 button->input = input = input_allocate_device();
366 if (!input) {
367 error = -ENOMEM;
368 goto err_free_button;
369 }
370
307 /* 371 /*
308 * Determine the button type (via hid), as fixed-feature buttons 372 * Determine the button type (via hid), as fixed-feature buttons
309 * need to be handled a bit differently than generic-space. 373 * need to be handled a bit differently than generic-space.
@@ -338,39 +402,48 @@ static int acpi_button_add(struct acpi_device *device)
338 } else { 402 } else {
339 printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", 403 printk(KERN_ERR PREFIX "Unsupported hid [%s]\n",
340 acpi_device_hid(device)); 404 acpi_device_hid(device));
341 result = -ENODEV; 405 error = -ENODEV;
342 goto end; 406 goto err_free_input;
343 } 407 }
344 408
345 result = acpi_button_add_fs(device); 409 error = acpi_button_add_fs(device);
346 if (result) 410 if (error)
347 goto end; 411 goto err_free_input;
412
413 error = acpi_button_install_notify_handlers(button);
414 if (error)
415 goto err_remove_fs;
416
417 snprintf(button->phys, sizeof(button->phys),
418 "%s/button/input0", acpi_device_hid(device));
419
420 input->name = acpi_device_name(device);
421 input->phys = button->phys;
422 input->id.bustype = BUS_HOST;
423 input->id.product = button->type;
348 424
349 switch (button->type) { 425 switch (button->type) {
426 case ACPI_BUTTON_TYPE_POWER:
350 case ACPI_BUTTON_TYPE_POWERF: 427 case ACPI_BUTTON_TYPE_POWERF:
351 status = 428 input->evbit[0] = BIT(EV_KEY);
352 acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, 429 set_bit(KEY_POWER, input->keybit);
353 acpi_button_notify_fixed,
354 button);
355 break; 430 break;
431
432 case ACPI_BUTTON_TYPE_SLEEP:
356 case ACPI_BUTTON_TYPE_SLEEPF: 433 case ACPI_BUTTON_TYPE_SLEEPF:
357 status = 434 input->evbit[0] = BIT(EV_KEY);
358 acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, 435 set_bit(KEY_SLEEP, input->keybit);
359 acpi_button_notify_fixed,
360 button);
361 break; 436 break;
362 default: 437
363 status = acpi_install_notify_handler(device->handle, 438 case ACPI_BUTTON_TYPE_LID:
364 ACPI_DEVICE_NOTIFY, 439 input->evbit[0] = BIT(EV_SW);
365 acpi_button_notify, 440 set_bit(SW_LID, input->swbit);
366 button);
367 break; 441 break;
368 } 442 }
369 443
370 if (ACPI_FAILURE(status)) { 444 error = input_register_device(input);
371 result = -ENODEV; 445 if (error)
372 goto end; 446 goto err_remove_handlers;
373 }
374 447
375 if (device->wakeup.flags.valid) { 448 if (device->wakeup.flags.valid) {
376 /* Button's GPE is run-wake GPE */ 449 /* Button's GPE is run-wake GPE */
@@ -385,47 +458,31 @@ static int acpi_button_add(struct acpi_device *device)
385 printk(KERN_INFO PREFIX "%s [%s]\n", 458 printk(KERN_INFO PREFIX "%s [%s]\n",
386 acpi_device_name(device), acpi_device_bid(device)); 459 acpi_device_name(device), acpi_device_bid(device));
387 460
388 end: 461 return 0;
389 if (result) {
390 acpi_button_remove_fs(device);
391 kfree(button);
392 }
393 462
394 return result; 463 err_remove_handlers:
464 acpi_button_remove_notify_handlers(button);
465 err_remove_fs:
466 acpi_button_remove_fs(device);
467 err_free_input:
468 input_free_device(input);
469 err_free_button:
470 kfree(button);
471 return error;
395} 472}
396 473
397static int acpi_button_remove(struct acpi_device *device, int type) 474static int acpi_button_remove(struct acpi_device *device, int type)
398{ 475{
399 acpi_status status = 0; 476 struct acpi_button *button;
400 struct acpi_button *button = NULL;
401
402 477
403 if (!device || !acpi_driver_data(device)) 478 if (!device || !acpi_driver_data(device))
404 return -EINVAL; 479 return -EINVAL;
405 480
406 button = acpi_driver_data(device); 481 button = acpi_driver_data(device);
407 482
408 /* Unregister for device notifications. */ 483 acpi_button_remove_notify_handlers(button);
409 switch (button->type) {
410 case ACPI_BUTTON_TYPE_POWERF:
411 status =
412 acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
413 acpi_button_notify_fixed);
414 break;
415 case ACPI_BUTTON_TYPE_SLEEPF:
416 status =
417 acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
418 acpi_button_notify_fixed);
419 break;
420 default:
421 status = acpi_remove_notify_handler(device->handle,
422 ACPI_DEVICE_NOTIFY,
423 acpi_button_notify);
424 break;
425 }
426
427 acpi_button_remove_fs(device); 484 acpi_button_remove_fs(device);
428 485 input_unregister_device(button->input);
429 kfree(button); 486 kfree(button);
430 487
431 return 0; 488 return 0;
@@ -433,8 +490,7 @@ static int acpi_button_remove(struct acpi_device *device, int type)
433 490
434static int __init acpi_button_init(void) 491static int __init acpi_button_init(void)
435{ 492{
436 int result = 0; 493 int result;
437
438 494
439 acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); 495 acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
440 if (!acpi_button_dir) 496 if (!acpi_button_dir)
@@ -451,7 +507,6 @@ static int __init acpi_button_init(void)
451 507
452static void __exit acpi_button_exit(void) 508static void __exit acpi_button_exit(void)
453{ 509{
454
455 acpi_bus_unregister_driver(&acpi_button_driver); 510 acpi_bus_unregister_driver(&acpi_button_driver);
456 511
457 if (acpi_power_dir) 512 if (acpi_power_dir)
@@ -461,8 +516,6 @@ static void __exit acpi_button_exit(void)
461 if (acpi_lid_dir) 516 if (acpi_lid_dir)
462 remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); 517 remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
463 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); 518 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
464
465 return;
466} 519}
467 520
468module_init(acpi_button_init); 521module_init(acpi_button_init);