aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/button.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@insightbb.com>2006-11-09 00:40:13 -0500
committerLen Brown <len.brown@intel.com>2006-11-09 03:20:19 -0500
commitc0968f0ea21d10b6720246e1e96bd6a7a161964d (patch)
tree8c2320d5d3c579cb66381aab34b1be27ceff41e9 /drivers/acpi/button.c
parent082f2f84be5db164280483efa7eb1549d867353d (diff)
ACPI: button: register with input layer
In addition to signalling button/lid events through /proc/acpi/event, create separate input devices and report KEY_POWER, KEY_SLEEP and SW_LID through input layer. Also remove unnecessary casts and variable initializations, clean up formatting. Sleep button may autorepeat but userspace will have to filter duplicate sleep requests anyway (and discard unprocessed events right after wakeup). Unlike /proc/acpi/event interface input device corresponding to LID switch reports true lid state instead of just a counter. SW_LID is active when lid is closed. The driver now depends on CONFIG_INPUT. Signed-off-by: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: Len Brown <len.brown@intel.com>
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);