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