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