Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Dmitry Torokhov and committed by
Len Brown
c0968f0e 082f2f84

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