1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * button.c - ACPI Button Driver 4 * 5 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 6 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 7 */ 8 9 #define pr_fmt(fmt) "ACPI: button: " fmt 10 11 #include <linux/compiler.h> 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/init.h> 15 #include <linux/types.h> 16 #include <linux/proc_fs.h> 17 #include <linux/seq_file.h> 18 #include <linux/input.h> 19 #include <linux/slab.h> 20 #include <linux/acpi.h> 21 #include <linux/dmi.h> 22 #include <acpi/button.h> 23 24 #define ACPI_BUTTON_CLASS "button" 25 #define ACPI_BUTTON_FILE_STATE "state" 26 #define ACPI_BUTTON_TYPE_UNKNOWN 0x00 27 #define ACPI_BUTTON_NOTIFY_WAKE 0x02 28 #define ACPI_BUTTON_NOTIFY_STATUS 0x80 29 30 #define ACPI_BUTTON_SUBCLASS_POWER "power" 31 #define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button" 32 #define ACPI_BUTTON_TYPE_POWER 0x01 33 34 #define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" 35 #define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button" 36 #define ACPI_BUTTON_TYPE_SLEEP 0x03 37 38 #define ACPI_BUTTON_SUBCLASS_LID "lid" 39 #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" 40 #define ACPI_BUTTON_TYPE_LID 0x05 41 42 enum { 43 ACPI_BUTTON_LID_INIT_IGNORE, 44 ACPI_BUTTON_LID_INIT_OPEN, 45 ACPI_BUTTON_LID_INIT_METHOD, 46 ACPI_BUTTON_LID_INIT_DISABLED, 47 }; 48 49 static const char * const lid_init_state_str[] = { 50 [ACPI_BUTTON_LID_INIT_IGNORE] = "ignore", 51 [ACPI_BUTTON_LID_INIT_OPEN] = "open", 52 [ACPI_BUTTON_LID_INIT_METHOD] = "method", 53 [ACPI_BUTTON_LID_INIT_DISABLED] = "disabled", 54 }; 55 56 MODULE_AUTHOR("Paul Diefenbaugh"); 57 MODULE_DESCRIPTION("ACPI Button Driver"); 58 MODULE_LICENSE("GPL"); 59 60 static const struct acpi_device_id button_device_ids[] = { 61 {ACPI_BUTTON_HID_LID, 0}, 62 {ACPI_BUTTON_HID_SLEEP, 0}, 63 {ACPI_BUTTON_HID_SLEEPF, 0}, 64 {ACPI_BUTTON_HID_POWER, 0}, 65 {ACPI_BUTTON_HID_POWERF, 0}, 66 {"", 0}, 67 }; 68 MODULE_DEVICE_TABLE(acpi, button_device_ids); 69 70 /* Please keep this list sorted alphabetically by vendor and model */ 71 static const struct dmi_system_id dmi_lid_quirks[] = { 72 { 73 /* GP-electronic T701, _LID method points to a floating GPIO */ 74 .matches = { 75 DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), 76 DMI_MATCH(DMI_PRODUCT_NAME, "T701"), 77 DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), 78 }, 79 .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED, 80 }, 81 { 82 /* Nextbook Ares 8A tablet, _LID device always reports lid closed */ 83 .matches = { 84 DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), 85 DMI_MATCH(DMI_PRODUCT_NAME, "CherryTrail"), 86 DMI_MATCH(DMI_BIOS_VERSION, "M882"), 87 }, 88 .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED, 89 }, 90 { 91 /* 92 * Lenovo Yoga 9 14ITL5, initial notification of the LID device 93 * never happens. 94 */ 95 .matches = { 96 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 97 DMI_MATCH(DMI_PRODUCT_NAME, "82BG"), 98 }, 99 .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN, 100 }, 101 { 102 /* 103 * Medion Akoya E2215T, notification of the LID device only 104 * happens on close, not on open and _LID always returns closed. 105 */ 106 .matches = { 107 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 108 DMI_MATCH(DMI_PRODUCT_NAME, "E2215T"), 109 }, 110 .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN, 111 }, 112 { 113 /* 114 * Medion Akoya E2228T, notification of the LID device only 115 * happens on close, not on open and _LID always returns closed. 116 */ 117 .matches = { 118 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), 119 DMI_MATCH(DMI_PRODUCT_NAME, "E2228T"), 120 }, 121 .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN, 122 }, 123 { 124 /* 125 * Razer Blade Stealth 13 late 2019, notification of the LID device 126 * only happens on close, not on open and _LID always returns closed. 127 */ 128 .matches = { 129 DMI_MATCH(DMI_SYS_VENDOR, "Razer"), 130 DMI_MATCH(DMI_PRODUCT_NAME, "Razer Blade Stealth 13 Late 2019"), 131 }, 132 .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN, 133 }, 134 { 135 /* 136 * Samsung galaxybook2 ,initial _LID device notification returns 137 * lid closed. 138 */ 139 .matches = { 140 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 141 DMI_MATCH(DMI_PRODUCT_NAME, "750XED"), 142 }, 143 .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN, 144 }, 145 {} 146 }; 147 148 static int acpi_button_add(struct acpi_device *device); 149 static void acpi_button_remove(struct acpi_device *device); 150 151 #ifdef CONFIG_PM_SLEEP 152 static int acpi_button_suspend(struct device *dev); 153 static int acpi_button_resume(struct device *dev); 154 #else 155 #define acpi_button_suspend NULL 156 #define acpi_button_resume NULL 157 #endif 158 static SIMPLE_DEV_PM_OPS(acpi_button_pm, acpi_button_suspend, acpi_button_resume); 159 160 static struct acpi_driver acpi_button_driver = { 161 .name = "button", 162 .class = ACPI_BUTTON_CLASS, 163 .ids = button_device_ids, 164 .ops = { 165 .add = acpi_button_add, 166 .remove = acpi_button_remove, 167 }, 168 .drv.pm = &acpi_button_pm, 169 }; 170 171 struct acpi_button { 172 unsigned int type; 173 struct input_dev *input; 174 char phys[32]; /* for input device */ 175 unsigned long pushed; 176 int last_state; 177 ktime_t last_time; 178 bool suspended; 179 bool lid_state_initialized; 180 }; 181 182 static struct acpi_device *lid_device; 183 static long lid_init_state = -1; 184 185 static unsigned long lid_report_interval __read_mostly = 500; 186 module_param(lid_report_interval, ulong, 0644); 187 MODULE_PARM_DESC(lid_report_interval, "Interval (ms) between lid key events"); 188 189 /* FS Interface (/proc) */ 190 static struct proc_dir_entry *acpi_button_dir; 191 static struct proc_dir_entry *acpi_lid_dir; 192 193 static int acpi_lid_evaluate_state(struct acpi_device *device) 194 { 195 unsigned long long lid_state; 196 acpi_status status; 197 198 status = acpi_evaluate_integer(device->handle, "_LID", NULL, &lid_state); 199 if (ACPI_FAILURE(status)) 200 return -ENODEV; 201 202 return lid_state ? 1 : 0; 203 } 204 205 static int acpi_lid_notify_state(struct acpi_device *device, int state) 206 { 207 struct acpi_button *button = acpi_driver_data(device); 208 ktime_t next_report; 209 bool do_update; 210 211 /* 212 * In lid_init_state=ignore mode, if user opens/closes lid 213 * frequently with "open" missing, and "last_time" is also updated 214 * frequently, "close" cannot be delivered to the userspace. 215 * So "last_time" is only updated after a timeout or an actual 216 * switch. 217 */ 218 if (lid_init_state != ACPI_BUTTON_LID_INIT_IGNORE || 219 button->last_state != !!state) 220 do_update = true; 221 else 222 do_update = false; 223 224 next_report = ktime_add(button->last_time, 225 ms_to_ktime(lid_report_interval)); 226 if (button->last_state == !!state && 227 ktime_after(ktime_get(), next_report)) { 228 /* Complain the buggy firmware */ 229 pr_warn_once("The lid device is not compliant to SW_LID.\n"); 230 231 /* 232 * Send the unreliable complement switch event: 233 * 234 * On most platforms, the lid device is reliable. However 235 * there are exceptions: 236 * 1. Platforms returning initial lid state as "close" by 237 * default after booting/resuming: 238 * https://bugzilla.kernel.org/show_bug.cgi?id=89211 239 * https://bugzilla.kernel.org/show_bug.cgi?id=106151 240 * 2. Platforms never reporting "open" events: 241 * https://bugzilla.kernel.org/show_bug.cgi?id=106941 242 * On these buggy platforms, the usage model of the ACPI 243 * lid device actually is: 244 * 1. The initial returning value of _LID may not be 245 * reliable. 246 * 2. The open event may not be reliable. 247 * 3. The close event is reliable. 248 * 249 * But SW_LID is typed as input switch event, the input 250 * layer checks if the event is redundant. Hence if the 251 * state is not switched, the userspace cannot see this 252 * platform triggered reliable event. By inserting a 253 * complement switch event, it then is guaranteed that the 254 * platform triggered reliable one can always be seen by 255 * the userspace. 256 */ 257 if (lid_init_state == ACPI_BUTTON_LID_INIT_IGNORE) { 258 do_update = true; 259 /* 260 * Do generate complement switch event for "close" 261 * as "close" is reliable and wrong "open" won't 262 * trigger unexpected behaviors. 263 * Do not generate complement switch event for 264 * "open" as "open" is not reliable and wrong 265 * "close" will trigger unexpected behaviors. 266 */ 267 if (!state) { 268 input_report_switch(button->input, 269 SW_LID, state); 270 input_sync(button->input); 271 } 272 } 273 } 274 /* Send the platform triggered reliable event */ 275 if (do_update) { 276 acpi_handle_debug(device->handle, "ACPI LID %s\n", 277 state ? "open" : "closed"); 278 input_report_switch(button->input, SW_LID, !state); 279 input_sync(button->input); 280 button->last_state = !!state; 281 button->last_time = ktime_get(); 282 } 283 284 return 0; 285 } 286 287 static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq, 288 void *offset) 289 { 290 struct acpi_device *device = seq->private; 291 int state; 292 293 state = acpi_lid_evaluate_state(device); 294 seq_printf(seq, "state: %s\n", 295 state < 0 ? "unsupported" : (state ? "open" : "closed")); 296 return 0; 297 } 298 299 static int acpi_button_add_fs(struct acpi_device *device) 300 { 301 struct acpi_button *button = acpi_driver_data(device); 302 struct proc_dir_entry *entry = NULL; 303 int ret = 0; 304 305 /* procfs I/F for ACPI lid device only */ 306 if (button->type != ACPI_BUTTON_TYPE_LID) 307 return 0; 308 309 if (acpi_button_dir || acpi_lid_dir) { 310 pr_info("More than one Lid device found!\n"); 311 return -EEXIST; 312 } 313 314 /* create /proc/acpi/button */ 315 acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); 316 if (!acpi_button_dir) 317 return -ENODEV; 318 319 /* create /proc/acpi/button/lid */ 320 acpi_lid_dir = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); 321 if (!acpi_lid_dir) { 322 ret = -ENODEV; 323 goto remove_button_dir; 324 } 325 326 /* create /proc/acpi/button/lid/LID/ */ 327 acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_lid_dir); 328 if (!acpi_device_dir(device)) { 329 ret = -ENODEV; 330 goto remove_lid_dir; 331 } 332 333 /* create /proc/acpi/button/lid/LID/state */ 334 entry = proc_create_single_data(ACPI_BUTTON_FILE_STATE, S_IRUGO, 335 acpi_device_dir(device), acpi_button_state_seq_show, 336 device); 337 if (!entry) { 338 ret = -ENODEV; 339 goto remove_dev_dir; 340 } 341 342 done: 343 return ret; 344 345 remove_dev_dir: 346 remove_proc_entry(acpi_device_bid(device), 347 acpi_lid_dir); 348 acpi_device_dir(device) = NULL; 349 remove_lid_dir: 350 remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); 351 acpi_lid_dir = NULL; 352 remove_button_dir: 353 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); 354 acpi_button_dir = NULL; 355 goto done; 356 } 357 358 static int acpi_button_remove_fs(struct acpi_device *device) 359 { 360 struct acpi_button *button = acpi_driver_data(device); 361 362 if (button->type != ACPI_BUTTON_TYPE_LID) 363 return 0; 364 365 remove_proc_entry(ACPI_BUTTON_FILE_STATE, 366 acpi_device_dir(device)); 367 remove_proc_entry(acpi_device_bid(device), 368 acpi_lid_dir); 369 acpi_device_dir(device) = NULL; 370 remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir); 371 acpi_lid_dir = NULL; 372 remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); 373 acpi_button_dir = NULL; 374 375 return 0; 376 } 377 378 /* Driver Interface */ 379 int acpi_lid_open(void) 380 { 381 if (!lid_device) 382 return -ENODEV; 383 384 return acpi_lid_evaluate_state(lid_device); 385 } 386 EXPORT_SYMBOL(acpi_lid_open); 387 388 static int acpi_lid_update_state(struct acpi_device *device, 389 bool signal_wakeup) 390 { 391 int state; 392 393 state = acpi_lid_evaluate_state(device); 394 if (state < 0) 395 return state; 396 397 if (state && signal_wakeup) 398 acpi_pm_wakeup_event(&device->dev); 399 400 return acpi_lid_notify_state(device, state); 401 } 402 403 static void acpi_lid_initialize_state(struct acpi_device *device) 404 { 405 struct acpi_button *button = acpi_driver_data(device); 406 407 switch (lid_init_state) { 408 case ACPI_BUTTON_LID_INIT_OPEN: 409 (void)acpi_lid_notify_state(device, 1); 410 break; 411 case ACPI_BUTTON_LID_INIT_METHOD: 412 (void)acpi_lid_update_state(device, false); 413 break; 414 case ACPI_BUTTON_LID_INIT_IGNORE: 415 default: 416 break; 417 } 418 419 button->lid_state_initialized = true; 420 } 421 422 static void acpi_lid_notify(acpi_handle handle, u32 event, void *data) 423 { 424 struct acpi_device *device = data; 425 struct acpi_button *button; 426 427 if (event != ACPI_BUTTON_NOTIFY_STATUS) { 428 acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n", 429 event); 430 return; 431 } 432 433 button = acpi_driver_data(device); 434 if (!button->lid_state_initialized) 435 return; 436 437 acpi_lid_update_state(device, true); 438 } 439 440 static void acpi_button_notify(acpi_handle handle, u32 event, void *data) 441 { 442 struct acpi_device *device = data; 443 struct acpi_button *button; 444 struct input_dev *input; 445 int keycode; 446 447 switch (event) { 448 case ACPI_BUTTON_NOTIFY_STATUS: 449 break; 450 case ACPI_BUTTON_NOTIFY_WAKE: 451 break; 452 default: 453 acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n", 454 event); 455 return; 456 } 457 458 acpi_pm_wakeup_event(&device->dev); 459 460 button = acpi_driver_data(device); 461 if (button->suspended || event == ACPI_BUTTON_NOTIFY_WAKE) 462 return; 463 464 input = button->input; 465 keycode = test_bit(KEY_SLEEP, input->keybit) ? KEY_SLEEP : KEY_POWER; 466 467 input_report_key(input, keycode, 1); 468 input_sync(input); 469 input_report_key(input, keycode, 0); 470 input_sync(input); 471 472 acpi_bus_generate_netlink_event(device->pnp.device_class, 473 dev_name(&device->dev), 474 event, ++button->pushed); 475 } 476 477 static void acpi_button_notify_run(void *data) 478 { 479 acpi_button_notify(NULL, ACPI_BUTTON_NOTIFY_STATUS, data); 480 } 481 482 static u32 acpi_button_event(void *data) 483 { 484 acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_button_notify_run, data); 485 return ACPI_INTERRUPT_HANDLED; 486 } 487 488 #ifdef CONFIG_PM_SLEEP 489 static int acpi_button_suspend(struct device *dev) 490 { 491 struct acpi_device *device = to_acpi_device(dev); 492 struct acpi_button *button = acpi_driver_data(device); 493 494 button->suspended = true; 495 return 0; 496 } 497 498 static int acpi_button_resume(struct device *dev) 499 { 500 struct input_dev *input; 501 struct acpi_device *device = to_acpi_device(dev); 502 struct acpi_button *button = acpi_driver_data(device); 503 504 button->suspended = false; 505 if (button->type == ACPI_BUTTON_TYPE_LID) { 506 button->last_state = !!acpi_lid_evaluate_state(device); 507 button->last_time = ktime_get(); 508 acpi_lid_initialize_state(device); 509 } 510 511 if (button->type == ACPI_BUTTON_TYPE_POWER) { 512 input = button->input; 513 input_report_key(input, KEY_WAKEUP, 1); 514 input_sync(input); 515 input_report_key(input, KEY_WAKEUP, 0); 516 input_sync(input); 517 } 518 return 0; 519 } 520 #endif 521 522 static int acpi_lid_input_open(struct input_dev *input) 523 { 524 struct acpi_device *device = input_get_drvdata(input); 525 struct acpi_button *button = acpi_driver_data(device); 526 527 button->last_state = !!acpi_lid_evaluate_state(device); 528 button->last_time = ktime_get(); 529 acpi_lid_initialize_state(device); 530 531 return 0; 532 } 533 534 static int acpi_button_add(struct acpi_device *device) 535 { 536 acpi_notify_handler handler; 537 struct acpi_button *button; 538 struct input_dev *input; 539 const char *hid = acpi_device_hid(device); 540 acpi_status status; 541 char *name, *class; 542 int error = 0; 543 544 if (!strcmp(hid, ACPI_BUTTON_HID_LID) && 545 lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED) 546 return -ENODEV; 547 548 button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL); 549 if (!button) 550 return -ENOMEM; 551 552 device->driver_data = button; 553 554 button->input = input = input_allocate_device(); 555 if (!input) { 556 error = -ENOMEM; 557 goto err_free_button; 558 } 559 560 name = acpi_device_name(device); 561 class = acpi_device_class(device); 562 563 if (!strcmp(hid, ACPI_BUTTON_HID_POWER) || 564 !strcmp(hid, ACPI_BUTTON_HID_POWERF)) { 565 button->type = ACPI_BUTTON_TYPE_POWER; 566 handler = acpi_button_notify; 567 strscpy(name, ACPI_BUTTON_DEVICE_NAME_POWER, MAX_ACPI_DEVICE_NAME_LEN); 568 sprintf(class, "%s/%s", 569 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER); 570 } else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEP) || 571 !strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) { 572 button->type = ACPI_BUTTON_TYPE_SLEEP; 573 handler = acpi_button_notify; 574 strscpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP, MAX_ACPI_DEVICE_NAME_LEN); 575 sprintf(class, "%s/%s", 576 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP); 577 } else if (!strcmp(hid, ACPI_BUTTON_HID_LID)) { 578 button->type = ACPI_BUTTON_TYPE_LID; 579 handler = acpi_lid_notify; 580 strscpy(name, ACPI_BUTTON_DEVICE_NAME_LID, MAX_ACPI_DEVICE_NAME_LEN); 581 sprintf(class, "%s/%s", 582 ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID); 583 input->open = acpi_lid_input_open; 584 } else { 585 pr_info("Unsupported hid [%s]\n", hid); 586 error = -ENODEV; 587 } 588 589 if (!error) 590 error = acpi_button_add_fs(device); 591 592 if (error) { 593 input_free_device(input); 594 goto err_free_button; 595 } 596 597 snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); 598 599 input->name = name; 600 input->phys = button->phys; 601 input->id.bustype = BUS_HOST; 602 input->id.product = button->type; 603 input->dev.parent = &device->dev; 604 605 switch (button->type) { 606 case ACPI_BUTTON_TYPE_POWER: 607 input_set_capability(input, EV_KEY, KEY_POWER); 608 input_set_capability(input, EV_KEY, KEY_WAKEUP); 609 break; 610 611 case ACPI_BUTTON_TYPE_SLEEP: 612 input_set_capability(input, EV_KEY, KEY_SLEEP); 613 break; 614 615 case ACPI_BUTTON_TYPE_LID: 616 input_set_capability(input, EV_SW, SW_LID); 617 break; 618 } 619 620 input_set_drvdata(input, device); 621 error = input_register_device(input); 622 if (error) 623 goto err_remove_fs; 624 625 switch (device->device_type) { 626 case ACPI_BUS_TYPE_POWER_BUTTON: 627 status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, 628 acpi_button_event, 629 device); 630 break; 631 case ACPI_BUS_TYPE_SLEEP_BUTTON: 632 status = acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, 633 acpi_button_event, 634 device); 635 break; 636 default: 637 status = acpi_install_notify_handler(device->handle, 638 ACPI_ALL_NOTIFY, handler, 639 device); 640 break; 641 } 642 if (ACPI_FAILURE(status)) { 643 error = -ENODEV; 644 goto err_input_unregister; 645 } 646 647 if (button->type == ACPI_BUTTON_TYPE_LID) { 648 /* 649 * This assumes there's only one lid device, or if there are 650 * more we only care about the last one... 651 */ 652 lid_device = device; 653 } 654 655 device_init_wakeup(&device->dev, true); 656 pr_info("%s [%s]\n", name, acpi_device_bid(device)); 657 return 0; 658 659 err_input_unregister: 660 input_unregister_device(input); 661 err_remove_fs: 662 acpi_button_remove_fs(device); 663 err_free_button: 664 kfree(button); 665 return error; 666 } 667 668 static void acpi_button_remove(struct acpi_device *device) 669 { 670 struct acpi_button *button = acpi_driver_data(device); 671 672 switch (device->device_type) { 673 case ACPI_BUS_TYPE_POWER_BUTTON: 674 acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, 675 acpi_button_event); 676 break; 677 case ACPI_BUS_TYPE_SLEEP_BUTTON: 678 acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, 679 acpi_button_event); 680 break; 681 default: 682 acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, 683 button->type == ACPI_BUTTON_TYPE_LID ? 684 acpi_lid_notify : 685 acpi_button_notify); 686 break; 687 } 688 acpi_os_wait_events_complete(); 689 690 acpi_button_remove_fs(device); 691 input_unregister_device(button->input); 692 kfree(button); 693 } 694 695 static int param_set_lid_init_state(const char *val, 696 const struct kernel_param *kp) 697 { 698 int i; 699 700 i = sysfs_match_string(lid_init_state_str, val); 701 if (i < 0) 702 return i; 703 704 lid_init_state = i; 705 pr_info("Initial lid state set to '%s'\n", lid_init_state_str[i]); 706 return 0; 707 } 708 709 static int param_get_lid_init_state(char *buf, const struct kernel_param *kp) 710 { 711 int i, c = 0; 712 713 for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++) 714 if (i == lid_init_state) 715 c += sprintf(buf + c, "[%s] ", lid_init_state_str[i]); 716 else 717 c += sprintf(buf + c, "%s ", lid_init_state_str[i]); 718 719 buf[c - 1] = '\n'; /* Replace the final space with a newline */ 720 721 return c; 722 } 723 724 module_param_call(lid_init_state, 725 param_set_lid_init_state, param_get_lid_init_state, 726 NULL, 0644); 727 MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state"); 728 729 static int acpi_button_register_driver(struct acpi_driver *driver) 730 { 731 const struct dmi_system_id *dmi_id; 732 733 if (lid_init_state == -1) { 734 dmi_id = dmi_first_match(dmi_lid_quirks); 735 if (dmi_id) 736 lid_init_state = (long)dmi_id->driver_data; 737 else 738 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; 739 } 740 741 /* 742 * Modules such as nouveau.ko and i915.ko have a link time dependency 743 * on acpi_lid_open(), and would therefore not be loadable on ACPI 744 * capable kernels booted in non-ACPI mode if the return value of 745 * acpi_bus_register_driver() is returned from here with ACPI disabled 746 * when this driver is built as a module. 747 */ 748 if (acpi_disabled) 749 return 0; 750 751 return acpi_bus_register_driver(driver); 752 } 753 754 static void acpi_button_unregister_driver(struct acpi_driver *driver) 755 { 756 if (!acpi_disabled) 757 acpi_bus_unregister_driver(driver); 758 } 759 760 module_driver(acpi_button_driver, acpi_button_register_driver, 761 acpi_button_unregister_driver); 762