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