.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * button.c - ACPI Button Driver |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> |
---|
5 | 6 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> |
---|
6 | | - * |
---|
7 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or modify |
---|
10 | | - * it under the terms of the GNU General Public License as published by |
---|
11 | | - * the Free Software Foundation; either version 2 of the License, or (at |
---|
12 | | - * your option) any later version. |
---|
13 | | - * |
---|
14 | | - * This program is distributed in the hope that it will be useful, but |
---|
15 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
17 | | - * General Public License for more details. |
---|
18 | | - * |
---|
19 | | - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
---|
20 | 7 | */ |
---|
21 | 8 | |
---|
22 | 9 | #define pr_fmt(fmt) "ACPI: button: " fmt |
---|
.. | .. |
---|
37 | 24 | #define PREFIX "ACPI: " |
---|
38 | 25 | |
---|
39 | 26 | #define ACPI_BUTTON_CLASS "button" |
---|
40 | | -#define ACPI_BUTTON_FILE_INFO "info" |
---|
41 | 27 | #define ACPI_BUTTON_FILE_STATE "state" |
---|
42 | 28 | #define ACPI_BUTTON_TYPE_UNKNOWN 0x00 |
---|
43 | 29 | #define ACPI_BUTTON_NOTIFY_STATUS 0x80 |
---|
44 | 30 | |
---|
45 | 31 | #define ACPI_BUTTON_SUBCLASS_POWER "power" |
---|
46 | | -#define ACPI_BUTTON_HID_POWER "PNP0C0C" |
---|
47 | 32 | #define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button" |
---|
48 | 33 | #define ACPI_BUTTON_TYPE_POWER 0x01 |
---|
49 | 34 | |
---|
50 | 35 | #define ACPI_BUTTON_SUBCLASS_SLEEP "sleep" |
---|
51 | | -#define ACPI_BUTTON_HID_SLEEP "PNP0C0E" |
---|
52 | 36 | #define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button" |
---|
53 | 37 | #define ACPI_BUTTON_TYPE_SLEEP 0x03 |
---|
54 | 38 | |
---|
55 | 39 | #define ACPI_BUTTON_SUBCLASS_LID "lid" |
---|
56 | | -#define ACPI_BUTTON_HID_LID "PNP0C0D" |
---|
57 | 40 | #define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch" |
---|
58 | 41 | #define ACPI_BUTTON_TYPE_LID 0x05 |
---|
59 | 42 | |
---|
60 | | -#define ACPI_BUTTON_LID_INIT_IGNORE 0x00 |
---|
61 | | -#define ACPI_BUTTON_LID_INIT_OPEN 0x01 |
---|
62 | | -#define ACPI_BUTTON_LID_INIT_METHOD 0x02 |
---|
| 43 | +enum { |
---|
| 44 | + ACPI_BUTTON_LID_INIT_IGNORE, |
---|
| 45 | + ACPI_BUTTON_LID_INIT_OPEN, |
---|
| 46 | + ACPI_BUTTON_LID_INIT_METHOD, |
---|
| 47 | + ACPI_BUTTON_LID_INIT_DISABLED, |
---|
| 48 | +}; |
---|
| 49 | + |
---|
| 50 | +static const char * const lid_init_state_str[] = { |
---|
| 51 | + [ACPI_BUTTON_LID_INIT_IGNORE] = "ignore", |
---|
| 52 | + [ACPI_BUTTON_LID_INIT_OPEN] = "open", |
---|
| 53 | + [ACPI_BUTTON_LID_INIT_METHOD] = "method", |
---|
| 54 | + [ACPI_BUTTON_LID_INIT_DISABLED] = "disabled", |
---|
| 55 | +}; |
---|
63 | 56 | |
---|
64 | 57 | #define _COMPONENT ACPI_BUTTON_COMPONENT |
---|
65 | 58 | ACPI_MODULE_NAME("button"); |
---|
.. | .. |
---|
78 | 71 | }; |
---|
79 | 72 | MODULE_DEVICE_TABLE(acpi, button_device_ids); |
---|
80 | 73 | |
---|
81 | | -/* |
---|
82 | | - * Some devices which don't even have a lid in anyway have a broken _LID |
---|
83 | | - * method (e.g. pointing to a floating gpio pin) causing spurious LID events. |
---|
84 | | - */ |
---|
85 | | -static const struct dmi_system_id lid_blacklst[] = { |
---|
| 74 | +/* Please keep this list sorted alphabetically by vendor and model */ |
---|
| 75 | +static const struct dmi_system_id dmi_lid_quirks[] = { |
---|
86 | 76 | { |
---|
87 | | - /* GP-electronic T701 */ |
---|
| 77 | + /* GP-electronic T701, _LID method points to a floating GPIO */ |
---|
88 | 78 | .matches = { |
---|
89 | 79 | DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), |
---|
90 | 80 | DMI_MATCH(DMI_PRODUCT_NAME, "T701"), |
---|
91 | 81 | DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), |
---|
92 | 82 | }, |
---|
| 83 | + .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED, |
---|
93 | 84 | }, |
---|
94 | 85 | { |
---|
95 | 86 | /* |
---|
.. | .. |
---|
163 | 154 | bool lid_state_initialized; |
---|
164 | 155 | }; |
---|
165 | 156 | |
---|
166 | | -static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); |
---|
167 | 157 | static struct acpi_device *lid_device; |
---|
168 | | -static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; |
---|
| 158 | +static long lid_init_state = -1; |
---|
169 | 159 | |
---|
170 | 160 | static unsigned long lid_report_interval __read_mostly = 500; |
---|
171 | 161 | module_param(lid_report_interval, ulong, 0644); |
---|
.. | .. |
---|
193 | 183 | static int acpi_lid_notify_state(struct acpi_device *device, int state) |
---|
194 | 184 | { |
---|
195 | 185 | struct acpi_button *button = acpi_driver_data(device); |
---|
196 | | - int ret; |
---|
197 | 186 | ktime_t next_report; |
---|
198 | 187 | bool do_update; |
---|
199 | 188 | |
---|
.. | .. |
---|
270 | 259 | button->last_time = ktime_get(); |
---|
271 | 260 | } |
---|
272 | 261 | |
---|
273 | | - ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device); |
---|
274 | | - if (ret == NOTIFY_DONE) |
---|
275 | | - ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, |
---|
276 | | - device); |
---|
277 | | - if (ret == NOTIFY_DONE || ret == NOTIFY_OK) { |
---|
278 | | - /* |
---|
279 | | - * It is also regarded as success if the notifier_chain |
---|
280 | | - * returns NOTIFY_OK or NOTIFY_DONE. |
---|
281 | | - */ |
---|
282 | | - ret = 0; |
---|
283 | | - } |
---|
284 | | - return ret; |
---|
| 262 | + return 0; |
---|
285 | 263 | } |
---|
286 | 264 | |
---|
287 | 265 | static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq, |
---|
.. | .. |
---|
378 | 356 | /* -------------------------------------------------------------------------- |
---|
379 | 357 | Driver Interface |
---|
380 | 358 | -------------------------------------------------------------------------- */ |
---|
381 | | -int acpi_lid_notifier_register(struct notifier_block *nb) |
---|
382 | | -{ |
---|
383 | | - return blocking_notifier_chain_register(&acpi_lid_notifier, nb); |
---|
384 | | -} |
---|
385 | | -EXPORT_SYMBOL(acpi_lid_notifier_register); |
---|
386 | | - |
---|
387 | | -int acpi_lid_notifier_unregister(struct notifier_block *nb) |
---|
388 | | -{ |
---|
389 | | - return blocking_notifier_chain_unregister(&acpi_lid_notifier, nb); |
---|
390 | | -} |
---|
391 | | -EXPORT_SYMBOL(acpi_lid_notifier_unregister); |
---|
392 | | - |
---|
393 | 359 | int acpi_lid_open(void) |
---|
394 | 360 | { |
---|
395 | 361 | if (!lid_device) |
---|
.. | .. |
---|
441 | 407 | switch (event) { |
---|
442 | 408 | case ACPI_FIXED_HARDWARE_EVENT: |
---|
443 | 409 | event = ACPI_BUTTON_NOTIFY_STATUS; |
---|
444 | | - /* fall through */ |
---|
| 410 | + fallthrough; |
---|
445 | 411 | case ACPI_BUTTON_NOTIFY_STATUS: |
---|
446 | 412 | input = button->input; |
---|
447 | 413 | if (button->type == ACPI_BUTTON_TYPE_LID) { |
---|
.. | .. |
---|
519 | 485 | char *name, *class; |
---|
520 | 486 | int error; |
---|
521 | 487 | |
---|
522 | | - if (!strcmp(hid, ACPI_BUTTON_HID_LID) && dmi_check_system(lid_blacklst)) |
---|
| 488 | + if (!strcmp(hid, ACPI_BUTTON_HID_LID) && |
---|
| 489 | + lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED) |
---|
523 | 490 | return -ENODEV; |
---|
524 | 491 | |
---|
525 | 492 | button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL); |
---|
.. | .. |
---|
625 | 592 | static int param_set_lid_init_state(const char *val, |
---|
626 | 593 | const struct kernel_param *kp) |
---|
627 | 594 | { |
---|
628 | | - int result = 0; |
---|
| 595 | + int i; |
---|
629 | 596 | |
---|
630 | | - if (!strncmp(val, "open", sizeof("open") - 1)) { |
---|
631 | | - lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; |
---|
632 | | - pr_info("Notify initial lid state as open\n"); |
---|
633 | | - } else if (!strncmp(val, "method", sizeof("method") - 1)) { |
---|
634 | | - lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; |
---|
635 | | - pr_info("Notify initial lid state with _LID return value\n"); |
---|
636 | | - } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) { |
---|
637 | | - lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE; |
---|
638 | | - pr_info("Do not notify initial lid state\n"); |
---|
639 | | - } else |
---|
640 | | - result = -EINVAL; |
---|
641 | | - return result; |
---|
| 597 | + i = sysfs_match_string(lid_init_state_str, val); |
---|
| 598 | + if (i < 0) |
---|
| 599 | + return i; |
---|
| 600 | + |
---|
| 601 | + lid_init_state = i; |
---|
| 602 | + pr_info("Initial lid state set to '%s'\n", lid_init_state_str[i]); |
---|
| 603 | + return 0; |
---|
642 | 604 | } |
---|
643 | 605 | |
---|
644 | | -static int param_get_lid_init_state(char *buffer, |
---|
645 | | - const struct kernel_param *kp) |
---|
| 606 | +static int param_get_lid_init_state(char *buf, const struct kernel_param *kp) |
---|
646 | 607 | { |
---|
647 | | - switch (lid_init_state) { |
---|
648 | | - case ACPI_BUTTON_LID_INIT_OPEN: |
---|
649 | | - return sprintf(buffer, "open"); |
---|
650 | | - case ACPI_BUTTON_LID_INIT_METHOD: |
---|
651 | | - return sprintf(buffer, "method"); |
---|
652 | | - case ACPI_BUTTON_LID_INIT_IGNORE: |
---|
653 | | - return sprintf(buffer, "ignore"); |
---|
654 | | - default: |
---|
655 | | - return sprintf(buffer, "invalid"); |
---|
656 | | - } |
---|
657 | | - return 0; |
---|
| 608 | + int i, c = 0; |
---|
| 609 | + |
---|
| 610 | + for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++) |
---|
| 611 | + if (i == lid_init_state) |
---|
| 612 | + c += sprintf(buf + c, "[%s] ", lid_init_state_str[i]); |
---|
| 613 | + else |
---|
| 614 | + c += sprintf(buf + c, "%s ", lid_init_state_str[i]); |
---|
| 615 | + |
---|
| 616 | + buf[c - 1] = '\n'; /* Replace the final space with a newline */ |
---|
| 617 | + |
---|
| 618 | + return c; |
---|
658 | 619 | } |
---|
659 | 620 | |
---|
660 | 621 | module_param_call(lid_init_state, |
---|
.. | .. |
---|
664 | 625 | |
---|
665 | 626 | static int acpi_button_register_driver(struct acpi_driver *driver) |
---|
666 | 627 | { |
---|
| 628 | + const struct dmi_system_id *dmi_id; |
---|
| 629 | + |
---|
| 630 | + if (lid_init_state == -1) { |
---|
| 631 | + dmi_id = dmi_first_match(dmi_lid_quirks); |
---|
| 632 | + if (dmi_id) |
---|
| 633 | + lid_init_state = (long)dmi_id->driver_data; |
---|
| 634 | + else |
---|
| 635 | + lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; |
---|
| 636 | + } |
---|
| 637 | + |
---|
667 | 638 | /* |
---|
668 | 639 | * Modules such as nouveau.ko and i915.ko have a link time dependency |
---|
669 | 640 | * on acpi_lid_open(), and would therefore not be loadable on ACPI |
---|