| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * HP WMI hotkeys |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 8 | 9 | * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> |
|---|
| 9 | 10 | * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> |
|---|
| 10 | 11 | * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 13 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 14 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 15 | | - * (at your option) any later version. |
|---|
| 16 | | - * |
|---|
| 17 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 18 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 19 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 20 | | - * GNU General Public License for more details. |
|---|
| 21 | | - * |
|---|
| 22 | | - * You should have received a copy of the GNU General Public License |
|---|
| 23 | | - * along with this program; if not, write to the Free Software |
|---|
| 24 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 25 | 12 | */ |
|---|
| 26 | 13 | |
|---|
| 27 | 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 75 | 62 | HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D, |
|---|
| 76 | 63 | HPWMI_PEAKSHIFT_PERIOD = 0x0F, |
|---|
| 77 | 64 | HPWMI_BATTERY_CHARGE_PERIOD = 0x10, |
|---|
| 65 | + HPWMI_SANITIZATION_MODE = 0x17, |
|---|
| 66 | + HPWMI_SMART_EXPERIENCE_APP = 0x21, |
|---|
| 78 | 67 | }; |
|---|
| 79 | 68 | |
|---|
| 80 | 69 | struct bios_args { |
|---|
| .. | .. |
|---|
| 98 | 87 | HPWMI_FEATURE2_QUERY = 0x0d, |
|---|
| 99 | 88 | HPWMI_WIRELESS2_QUERY = 0x1b, |
|---|
| 100 | 89 | HPWMI_POSTCODEERROR_QUERY = 0x2a, |
|---|
| 90 | + HPWMI_THERMAL_POLICY_QUERY = 0x4c, |
|---|
| 101 | 91 | }; |
|---|
| 102 | 92 | |
|---|
| 103 | 93 | enum hp_wmi_command { |
|---|
| .. | .. |
|---|
| 128 | 118 | HPWMI_POWER_SOFT = 0x02, |
|---|
| 129 | 119 | HPWMI_POWER_BIOS = 0x04, |
|---|
| 130 | 120 | HPWMI_POWER_HARD = 0x08, |
|---|
| 121 | + HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD, |
|---|
| 131 | 122 | }; |
|---|
| 132 | 123 | |
|---|
| 133 | | -#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \ |
|---|
| 134 | | - != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) |
|---|
| 124 | +#define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW) |
|---|
| 135 | 125 | #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) |
|---|
| 136 | 126 | |
|---|
| 137 | 127 | struct bios_rfkill2_device_state { |
|---|
| .. | .. |
|---|
| 263 | 253 | ret = bios_return->return_code; |
|---|
| 264 | 254 | |
|---|
| 265 | 255 | if (ret) { |
|---|
| 266 | | - if (ret != HPWMI_RET_UNKNOWN_CMDTYPE) |
|---|
| 256 | + if (ret != HPWMI_RET_UNKNOWN_COMMAND && |
|---|
| 257 | + ret != HPWMI_RET_UNKNOWN_CMDTYPE) |
|---|
| 267 | 258 | pr_warn("query 0x%x returned error 0x%x\n", query, ret); |
|---|
| 268 | 259 | goto out_free; |
|---|
| 269 | 260 | } |
|---|
| .. | .. |
|---|
| 496 | 487 | static ssize_t postcode_store(struct device *dev, struct device_attribute *attr, |
|---|
| 497 | 488 | const char *buf, size_t count) |
|---|
| 498 | 489 | { |
|---|
| 499 | | - long unsigned int tmp2; |
|---|
| 490 | + u32 tmp = 1; |
|---|
| 491 | + bool clear; |
|---|
| 500 | 492 | int ret; |
|---|
| 501 | | - u32 tmp; |
|---|
| 502 | 493 | |
|---|
| 503 | | - ret = kstrtoul(buf, 10, &tmp2); |
|---|
| 504 | | - if (!ret && tmp2 != 1) |
|---|
| 505 | | - ret = -EINVAL; |
|---|
| 494 | + ret = kstrtobool(buf, &clear); |
|---|
| 506 | 495 | if (ret) |
|---|
| 507 | | - goto out; |
|---|
| 496 | + return ret; |
|---|
| 497 | + |
|---|
| 498 | + if (clear == false) |
|---|
| 499 | + return -EINVAL; |
|---|
| 508 | 500 | |
|---|
| 509 | 501 | /* Clear the POST error code. It is kept until until cleared. */ |
|---|
| 510 | | - tmp = (u32) tmp2; |
|---|
| 511 | 502 | ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp, |
|---|
| 512 | 503 | sizeof(tmp), sizeof(tmp)); |
|---|
| 513 | | - |
|---|
| 514 | | -out: |
|---|
| 515 | 504 | if (ret) |
|---|
| 516 | 505 | return ret < 0 ? ret : -EINVAL; |
|---|
| 517 | 506 | |
|---|
| .. | .. |
|---|
| 524 | 513 | static DEVICE_ATTR_RO(dock); |
|---|
| 525 | 514 | static DEVICE_ATTR_RO(tablet); |
|---|
| 526 | 515 | static DEVICE_ATTR_RW(postcode); |
|---|
| 516 | + |
|---|
| 517 | +static struct attribute *hp_wmi_attrs[] = { |
|---|
| 518 | + &dev_attr_display.attr, |
|---|
| 519 | + &dev_attr_hddtemp.attr, |
|---|
| 520 | + &dev_attr_als.attr, |
|---|
| 521 | + &dev_attr_dock.attr, |
|---|
| 522 | + &dev_attr_tablet.attr, |
|---|
| 523 | + &dev_attr_postcode.attr, |
|---|
| 524 | + NULL, |
|---|
| 525 | +}; |
|---|
| 526 | +ATTRIBUTE_GROUPS(hp_wmi); |
|---|
| 527 | 527 | |
|---|
| 528 | 528 | static void hp_wmi_notify(u32 value, void *context) |
|---|
| 529 | 529 | { |
|---|
| .. | .. |
|---|
| 631 | 631 | break; |
|---|
| 632 | 632 | case HPWMI_BATTERY_CHARGE_PERIOD: |
|---|
| 633 | 633 | break; |
|---|
| 634 | + case HPWMI_SANITIZATION_MODE: |
|---|
| 635 | + break; |
|---|
| 636 | + case HPWMI_SMART_EXPERIENCE_APP: |
|---|
| 637 | + break; |
|---|
| 634 | 638 | default: |
|---|
| 635 | 639 | pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data); |
|---|
| 636 | 640 | break; |
|---|
| .. | .. |
|---|
| 701 | 705 | { |
|---|
| 702 | 706 | wmi_remove_notify_handler(HPWMI_EVENT_GUID); |
|---|
| 703 | 707 | input_unregister_device(hp_wmi_input_dev); |
|---|
| 704 | | -} |
|---|
| 705 | | - |
|---|
| 706 | | -static void cleanup_sysfs(struct platform_device *device) |
|---|
| 707 | | -{ |
|---|
| 708 | | - device_remove_file(&device->dev, &dev_attr_display); |
|---|
| 709 | | - device_remove_file(&device->dev, &dev_attr_hddtemp); |
|---|
| 710 | | - device_remove_file(&device->dev, &dev_attr_als); |
|---|
| 711 | | - device_remove_file(&device->dev, &dev_attr_dock); |
|---|
| 712 | | - device_remove_file(&device->dev, &dev_attr_tablet); |
|---|
| 713 | | - device_remove_file(&device->dev, &dev_attr_postcode); |
|---|
| 714 | 708 | } |
|---|
| 715 | 709 | |
|---|
| 716 | 710 | static int __init hp_wmi_rfkill_setup(struct platform_device *device) |
|---|
| .. | .. |
|---|
| 881 | 875 | return err; |
|---|
| 882 | 876 | } |
|---|
| 883 | 877 | |
|---|
| 878 | +static int thermal_policy_setup(struct platform_device *device) |
|---|
| 879 | +{ |
|---|
| 880 | + int err, tp; |
|---|
| 881 | + |
|---|
| 882 | + tp = hp_wmi_read_int(HPWMI_THERMAL_POLICY_QUERY); |
|---|
| 883 | + if (tp < 0) |
|---|
| 884 | + return tp; |
|---|
| 885 | + |
|---|
| 886 | + /* |
|---|
| 887 | + * call thermal policy write command to ensure that the firmware correctly |
|---|
| 888 | + * sets the OEM variables for the DPTF |
|---|
| 889 | + */ |
|---|
| 890 | + err = hp_wmi_perform_query(HPWMI_THERMAL_POLICY_QUERY, HPWMI_WRITE, &tp, |
|---|
| 891 | + sizeof(tp), 0); |
|---|
| 892 | + if (err) |
|---|
| 893 | + return err; |
|---|
| 894 | + |
|---|
| 895 | + return 0; |
|---|
| 896 | +} |
|---|
| 897 | + |
|---|
| 884 | 898 | static int __init hp_wmi_bios_setup(struct platform_device *device) |
|---|
| 885 | 899 | { |
|---|
| 886 | | - int err; |
|---|
| 887 | | - |
|---|
| 888 | 900 | /* clear detected rfkill devices */ |
|---|
| 889 | 901 | wifi_rfkill = NULL; |
|---|
| 890 | 902 | bluetooth_rfkill = NULL; |
|---|
| 891 | 903 | wwan_rfkill = NULL; |
|---|
| 892 | 904 | rfkill2_count = 0; |
|---|
| 893 | 905 | |
|---|
| 894 | | - if (hp_wmi_rfkill_setup(device)) |
|---|
| 895 | | - hp_wmi_rfkill2_setup(device); |
|---|
| 906 | + /* |
|---|
| 907 | + * In pre-2009 BIOS, command 1Bh return 0x4 to indicate that |
|---|
| 908 | + * BIOS no longer controls the power for the wireless |
|---|
| 909 | + * devices. All features supported by this command will no |
|---|
| 910 | + * longer be supported. |
|---|
| 911 | + */ |
|---|
| 912 | + if (!hp_wmi_bios_2009_later()) { |
|---|
| 913 | + if (hp_wmi_rfkill_setup(device)) |
|---|
| 914 | + hp_wmi_rfkill2_setup(device); |
|---|
| 915 | + } |
|---|
| 896 | 916 | |
|---|
| 897 | | - err = device_create_file(&device->dev, &dev_attr_display); |
|---|
| 898 | | - if (err) |
|---|
| 899 | | - goto add_sysfs_error; |
|---|
| 900 | | - err = device_create_file(&device->dev, &dev_attr_hddtemp); |
|---|
| 901 | | - if (err) |
|---|
| 902 | | - goto add_sysfs_error; |
|---|
| 903 | | - err = device_create_file(&device->dev, &dev_attr_als); |
|---|
| 904 | | - if (err) |
|---|
| 905 | | - goto add_sysfs_error; |
|---|
| 906 | | - err = device_create_file(&device->dev, &dev_attr_dock); |
|---|
| 907 | | - if (err) |
|---|
| 908 | | - goto add_sysfs_error; |
|---|
| 909 | | - err = device_create_file(&device->dev, &dev_attr_tablet); |
|---|
| 910 | | - if (err) |
|---|
| 911 | | - goto add_sysfs_error; |
|---|
| 912 | | - err = device_create_file(&device->dev, &dev_attr_postcode); |
|---|
| 913 | | - if (err) |
|---|
| 914 | | - goto add_sysfs_error; |
|---|
| 917 | + thermal_policy_setup(device); |
|---|
| 918 | + |
|---|
| 915 | 919 | return 0; |
|---|
| 916 | | - |
|---|
| 917 | | -add_sysfs_error: |
|---|
| 918 | | - cleanup_sysfs(device); |
|---|
| 919 | | - return err; |
|---|
| 920 | 920 | } |
|---|
| 921 | 921 | |
|---|
| 922 | 922 | static int __exit hp_wmi_bios_remove(struct platform_device *device) |
|---|
| 923 | 923 | { |
|---|
| 924 | 924 | int i; |
|---|
| 925 | | - cleanup_sysfs(device); |
|---|
| 926 | 925 | |
|---|
| 927 | 926 | for (i = 0; i < rfkill2_count; i++) { |
|---|
| 928 | 927 | rfkill_unregister(rfkill2[i].rfkill); |
|---|
| .. | .. |
|---|
| 991 | 990 | .driver = { |
|---|
| 992 | 991 | .name = "hp-wmi", |
|---|
| 993 | 992 | .pm = &hp_wmi_pm_ops, |
|---|
| 993 | + .dev_groups = hp_wmi_groups, |
|---|
| 994 | 994 | }, |
|---|
| 995 | 995 | .remove = __exit_p(hp_wmi_bios_remove), |
|---|
| 996 | 996 | }; |
|---|