^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * HP WMI hotkeys
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2008 Red Hat <mjg@redhat.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Portions based on wistron_btns.c:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/input/sparse-keymap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/rfkill.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static int enable_tablet_mode_sw = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) module_param(enable_tablet_mode_sw, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) MODULE_PARM_DESC(enable_tablet_mode_sw, "Enable SW_TABLET_MODE reporting (-1=auto, 0=no, 1=yes)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) enum hp_wmi_radio {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) HPWMI_WIFI = 0x0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) HPWMI_BLUETOOTH = 0x1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) HPWMI_WWAN = 0x2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) HPWMI_GPS = 0x3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) enum hp_wmi_event_ids {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) HPWMI_DOCK_EVENT = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) HPWMI_PARK_HDD = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) HPWMI_SMART_ADAPTER = 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) HPWMI_BEZEL_BUTTON = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) HPWMI_WIRELESS = 0x05,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) HPWMI_CPU_BATTERY_THROTTLE = 0x06,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) HPWMI_LOCK_SWITCH = 0x07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) HPWMI_LID_SWITCH = 0x08,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) HPWMI_SCREEN_ROTATION = 0x09,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) HPWMI_COOLSENSE_SYSTEM_MOBILE = 0x0A,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) HPWMI_COOLSENSE_SYSTEM_HOT = 0x0B,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) HPWMI_PROXIMITY_SENSOR = 0x0C,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) HPWMI_PEAKSHIFT_PERIOD = 0x0F,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) HPWMI_BATTERY_CHARGE_PERIOD = 0x10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct bios_args {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) u32 signature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) u32 command;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) u32 commandtype;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) u32 datasize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) u8 data[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) enum hp_wmi_commandtype {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) HPWMI_DISPLAY_QUERY = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) HPWMI_HDDTEMP_QUERY = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) HPWMI_ALS_QUERY = 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) HPWMI_HARDWARE_QUERY = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) HPWMI_WIRELESS_QUERY = 0x05,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) HPWMI_BATTERY_QUERY = 0x07,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) HPWMI_BIOS_QUERY = 0x09,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) HPWMI_FEATURE_QUERY = 0x0b,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) HPWMI_HOTKEY_QUERY = 0x0c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) HPWMI_FEATURE2_QUERY = 0x0d,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) HPWMI_WIRELESS2_QUERY = 0x1b,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) HPWMI_POSTCODEERROR_QUERY = 0x2a,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) HPWMI_THERMAL_POLICY_QUERY = 0x4c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) enum hp_wmi_command {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) HPWMI_READ = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) HPWMI_WRITE = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) HPWMI_ODM = 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) enum hp_wmi_hardware_mask {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) HPWMI_DOCK_MASK = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) HPWMI_TABLET_MASK = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct bios_return {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) u32 sigpass;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) u32 return_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) enum hp_return_value {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) HPWMI_RET_WRONG_SIGNATURE = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) HPWMI_RET_UNKNOWN_COMMAND = 0x03,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) HPWMI_RET_UNKNOWN_CMDTYPE = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) HPWMI_RET_INVALID_PARAMETERS = 0x05,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) enum hp_wireless2_bits {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) HPWMI_POWER_STATE = 0x01,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) HPWMI_POWER_SOFT = 0x02,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) HPWMI_POWER_BIOS = 0x04,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) HPWMI_POWER_HARD = 0x08,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) #define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct bios_rfkill2_device_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) u8 radio_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) u8 bus_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) u16 vendor_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) u16 product_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) u16 subsys_vendor_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) u16 subsys_product_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) u8 rfkill_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) u8 power;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) u8 unknown[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) /* 7 devices fit into the 128 byte buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define HPWMI_MAX_RFKILL2_DEVICES 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct bios_rfkill2_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) u8 unknown[7];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) u8 count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) u8 pad[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) static const struct key_entry hp_wmi_keymap[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) { KE_KEY, 0x20e6, { KEY_PROG1 } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) { KE_KEY, 0x20e8, { KEY_MEDIA } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) { KE_KEY, 0x2142, { KEY_MEDIA } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) { KE_KEY, 0x213b, { KEY_INFO } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) { KE_KEY, 0x216a, { KEY_SETUP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) { KE_KEY, 0x231b, { KEY_HELP } },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) { KE_END, 0 }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static struct input_dev *hp_wmi_input_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) static struct platform_device *hp_wmi_platform_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) static struct rfkill *wifi_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) static struct rfkill *bluetooth_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static struct rfkill *wwan_rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct rfkill2_device {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) u8 id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) int num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct rfkill *rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static int rfkill2_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) /* map output size to the corresponding WMI method id */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static inline int encode_outsize_for_pvsz(int outsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (outsize > 4096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (outsize > 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (outsize > 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (outsize > 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (outsize > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) return 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) * hp_wmi_perform_query
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) * query: The commandtype (enum hp_wmi_commandtype)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) * write: The command (enum hp_wmi_command)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) * buffer: Buffer used as input and/or output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * insize: Size of input buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * outsize: Size of output buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) * returns zero on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) * an HP WMI query specific error code (which is positive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) * -EINVAL if the query was not successful at all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) * -EINVAL if the output buffer size exceeds buffersize
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) * Note: The buffersize must at least be the maximum of the input and output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) * size. E.g. Battery info query is defined to have 1 byte input
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) * and 128 byte output. The caller would do:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * buffer = kzalloc(128, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * ret = hp_wmi_perform_query(HPWMI_BATTERY_QUERY, HPWMI_READ, buffer, 1, 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) void *buffer, int insize, int outsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) int mid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) struct bios_return *bios_return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) int actual_outsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) union acpi_object *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) struct bios_args args = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .signature = 0x55434553,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .command = command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .commandtype = query,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .datasize = insize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .data = { 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) struct acpi_buffer input = { sizeof(struct bios_args), &args };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) mid = encode_outsize_for_pvsz(outsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (WARN_ON(mid < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return mid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (WARN_ON(insize > sizeof(args.data)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) memcpy(&args.data[0], buffer, insize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) obj = output.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (!obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) if (obj->type != ACPI_TYPE_BUFFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) bios_return = (struct bios_return *)obj->buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) ret = bios_return->return_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (ret != HPWMI_RET_UNKNOWN_COMMAND &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) ret != HPWMI_RET_UNKNOWN_CMDTYPE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) pr_warn("query 0x%x returned error 0x%x\n", query, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /* Ignore output data of zero size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) if (!outsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) memset(buffer + actual_outsize, 0, outsize - actual_outsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) kfree(obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static int hp_wmi_read_int(int query)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) int val = 0, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) ret = hp_wmi_perform_query(query, HPWMI_READ, &val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) sizeof(val), sizeof(val));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) return ret < 0 ? ret : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) static int hp_wmi_hw_state(int mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (state < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) return state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return !!(state & mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) static int __init hp_wmi_bios_2008_later(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) int state = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, HPWMI_READ, &state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) sizeof(state), sizeof(state));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) static int __init hp_wmi_bios_2009_later(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) u8 state[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) sizeof(state), sizeof(state));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) static int __init hp_wmi_enable_hotkeys(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) int value = 0x6e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, HPWMI_WRITE, &value,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) sizeof(value), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return ret <= 0 ? ret : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static int hp_wmi_set_block(void *data, bool blocked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) enum hp_wmi_radio r = (enum hp_wmi_radio) data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) int query = BIT(r + 8) | ((!blocked) << r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) &query, sizeof(query), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return ret <= 0 ? ret : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static const struct rfkill_ops hp_wmi_rfkill_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .set_block = hp_wmi_set_block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) int mask = 0x200 << (r * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) /* TBD: Pass error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) return !(wireless & mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) int mask = 0x800 << (r * 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /* TBD: Pass error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) return !(wireless & mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) int rfkill_id = (int)(long)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) ret = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_WRITE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) buffer, sizeof(buffer), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) return ret <= 0 ? ret : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) static const struct rfkill_ops hp_wmi_rfkill2_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) .set_block = hp_wmi_rfkill2_set_block,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) static int hp_wmi_rfkill2_refresh(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) struct bios_rfkill2_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) int err, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) sizeof(state), sizeof(state));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) for (i = 0; i < rfkill2_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) int num = rfkill2[i].num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct bios_rfkill2_device_state *devstate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) devstate = &state.device[num];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) if (num >= state.count ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) devstate->rfkill_id != rfkill2[i].id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) pr_warn("power configuration of the wireless devices unexpectedly changed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) rfkill_set_states(rfkill2[i].rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) IS_SWBLOCKED(devstate->power),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) IS_HWBLOCKED(devstate->power));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) static ssize_t display_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (value < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) return sprintf(buf, "%d\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if (value < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) return sprintf(buf, "%d\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) static ssize_t als_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) int value = hp_wmi_read_int(HPWMI_ALS_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (value < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) return sprintf(buf, "%d\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) int value = hp_wmi_hw_state(HPWMI_DOCK_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) if (value < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) return sprintf(buf, "%d\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) static ssize_t tablet_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) int value = hp_wmi_hw_state(HPWMI_TABLET_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (value < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) return sprintf(buf, "%d\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) static ssize_t postcode_show(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) /* Get the POST error code of previous boot failure. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (value < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) return sprintf(buf, "0x%x\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) static ssize_t als_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) u32 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) ret = kstrtou32(buf, 10, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_WRITE, &tmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) sizeof(tmp), sizeof(tmp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) return ret < 0 ? ret : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) static ssize_t postcode_store(struct device *dev, struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) u32 tmp = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) bool clear;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) ret = kstrtobool(buf, &clear);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (clear == false)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) /* Clear the POST error code. It is kept until until cleared. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) sizeof(tmp), sizeof(tmp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) return ret < 0 ? ret : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) static DEVICE_ATTR_RO(display);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) static DEVICE_ATTR_RO(hddtemp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) static DEVICE_ATTR_RW(als);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static DEVICE_ATTR_RO(dock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) static DEVICE_ATTR_RO(tablet);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) static DEVICE_ATTR_RW(postcode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) static struct attribute *hp_wmi_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) &dev_attr_display.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) &dev_attr_hddtemp.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) &dev_attr_als.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) &dev_attr_dock.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) &dev_attr_tablet.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) &dev_attr_postcode.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) ATTRIBUTE_GROUPS(hp_wmi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) static void hp_wmi_notify(u32 value, void *context)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) u32 event_id, event_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) union acpi_object *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) u32 *location;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) int key_code;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) status = wmi_get_event_data(value, &response);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (status != AE_OK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) pr_info("bad event status 0x%x\n", status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) obj = (union acpi_object *)response.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) if (!obj)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if (obj->type != ACPI_TYPE_BUFFER) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) pr_info("Unknown response received %d\n", obj->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) kfree(obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) * Depending on ACPI version the concatenation of id and event data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) * inside _WED function will result in a 8 or 16 byte buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) location = (u32 *)obj->buffer.pointer;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (obj->buffer.length == 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) event_id = *location;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) event_data = *(location + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) } else if (obj->buffer.length == 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) event_id = *location;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) event_data = *(location + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) pr_info("Unknown buffer length %d\n", obj->buffer.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) kfree(obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) kfree(obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) switch (event_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) case HPWMI_DOCK_EVENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) input_report_switch(hp_wmi_input_dev, SW_DOCK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) hp_wmi_hw_state(HPWMI_DOCK_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) hp_wmi_hw_state(HPWMI_TABLET_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) input_sync(hp_wmi_input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) case HPWMI_PARK_HDD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) case HPWMI_SMART_ADAPTER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) case HPWMI_BEZEL_BUTTON:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) if (key_code < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (!sparse_keymap_report_event(hp_wmi_input_dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) key_code, 1, true))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) pr_info("Unknown key code - 0x%x\n", key_code);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) case HPWMI_WIRELESS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (rfkill2_count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) hp_wmi_rfkill2_refresh();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) if (wifi_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) rfkill_set_states(wifi_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) hp_wmi_get_sw_state(HPWMI_WIFI),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) hp_wmi_get_hw_state(HPWMI_WIFI));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (bluetooth_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) rfkill_set_states(bluetooth_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) if (wwan_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) rfkill_set_states(wwan_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) hp_wmi_get_sw_state(HPWMI_WWAN),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) hp_wmi_get_hw_state(HPWMI_WWAN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) case HPWMI_CPU_BATTERY_THROTTLE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) case HPWMI_LOCK_SWITCH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) case HPWMI_LID_SWITCH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) case HPWMI_SCREEN_ROTATION:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) case HPWMI_COOLSENSE_SYSTEM_MOBILE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) case HPWMI_COOLSENSE_SYSTEM_HOT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) case HPWMI_PROXIMITY_SENSOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) case HPWMI_BACKLIT_KB_BRIGHTNESS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) case HPWMI_PEAKSHIFT_PERIOD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) case HPWMI_BATTERY_CHARGE_PERIOD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) static int __init hp_wmi_input_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) int err, val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) hp_wmi_input_dev = input_allocate_device();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (!hp_wmi_input_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) hp_wmi_input_dev->name = "HP WMI hotkeys";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) hp_wmi_input_dev->phys = "wmi/input0";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) hp_wmi_input_dev->id.bustype = BUS_HOST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) __set_bit(EV_SW, hp_wmi_input_dev->evbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) /* Dock */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) val = hp_wmi_hw_state(HPWMI_DOCK_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) if (!(val < 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) input_report_switch(hp_wmi_input_dev, SW_DOCK, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) /* Tablet mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) if (enable_tablet_mode_sw > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) val = hp_wmi_hw_state(HPWMI_TABLET_MASK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) if (val >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) goto err_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) /* Set initial hardware state */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) input_sync(hp_wmi_input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later())
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) hp_wmi_enable_hotkeys();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) err = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) goto err_free_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) err = input_register_device(hp_wmi_input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) goto err_uninstall_notifier;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) err_uninstall_notifier:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) wmi_remove_notify_handler(HPWMI_EVENT_GUID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) err_free_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) input_free_device(hp_wmi_input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) static void hp_wmi_input_destroy(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) wmi_remove_notify_handler(HPWMI_EVENT_GUID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) input_unregister_device(hp_wmi_input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) static int __init hp_wmi_rfkill_setup(struct platform_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) int err, wireless;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (wireless < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) return wireless;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &wireless,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) sizeof(wireless), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) if (wireless & 0x1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) RFKILL_TYPE_WLAN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) &hp_wmi_rfkill_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) (void *) HPWMI_WIFI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) if (!wifi_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) rfkill_init_sw_state(wifi_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) hp_wmi_get_sw_state(HPWMI_WIFI));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) rfkill_set_hw_state(wifi_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) hp_wmi_get_hw_state(HPWMI_WIFI));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) err = rfkill_register(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) goto register_wifi_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (wireless & 0x2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) RFKILL_TYPE_BLUETOOTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) &hp_wmi_rfkill_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) (void *) HPWMI_BLUETOOTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) if (!bluetooth_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) goto register_bluetooth_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) rfkill_init_sw_state(bluetooth_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) rfkill_set_hw_state(bluetooth_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) err = rfkill_register(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) goto register_bluetooth_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if (wireless & 0x4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) RFKILL_TYPE_WWAN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) &hp_wmi_rfkill_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) (void *) HPWMI_WWAN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) if (!wwan_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) goto register_wwan_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) rfkill_init_sw_state(wwan_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) hp_wmi_get_sw_state(HPWMI_WWAN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) rfkill_set_hw_state(wwan_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) hp_wmi_get_hw_state(HPWMI_WWAN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) err = rfkill_register(wwan_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) goto register_wwan_error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) register_wwan_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) rfkill_destroy(wwan_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) wwan_rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) if (bluetooth_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) rfkill_unregister(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) register_bluetooth_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) rfkill_destroy(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) bluetooth_rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) if (wifi_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) rfkill_unregister(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) register_wifi_error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) rfkill_destroy(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) wifi_rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) struct bios_rfkill2_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) int err, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) sizeof(state), sizeof(state));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) return err < 0 ? err : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) pr_warn("unable to parse 0x1b query output\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) for (i = 0; i < state.count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) struct rfkill *rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) enum rfkill_type type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) switch (state.device[i].radio_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) case HPWMI_WIFI:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) type = RFKILL_TYPE_WLAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) name = "hp-wifi";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) case HPWMI_BLUETOOTH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) type = RFKILL_TYPE_BLUETOOTH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) name = "hp-bluetooth";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) case HPWMI_WWAN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) type = RFKILL_TYPE_WWAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) name = "hp-wwan";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) case HPWMI_GPS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) type = RFKILL_TYPE_GPS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) name = "hp-gps";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) pr_warn("unknown device type 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) state.device[i].radio_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) if (!state.device[i].vendor_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) pr_warn("zero device %d while %d reported\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) i, state.count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) rfkill = rfkill_alloc(name, &device->dev, type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) &hp_wmi_rfkill2_ops, (void *)(long)i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) if (!rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) rfkill2[rfkill2_count].num = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) rfkill2[rfkill2_count].rfkill = rfkill;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) rfkill_init_sw_state(rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) IS_SWBLOCKED(state.device[i].power));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) rfkill_set_hw_state(rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) IS_HWBLOCKED(state.device[i].power));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) if (!(state.device[i].power & HPWMI_POWER_BIOS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) pr_info("device %s blocked by BIOS\n", name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) err = rfkill_register(rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) rfkill_destroy(rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) rfkill2_count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) for (; rfkill2_count > 0; rfkill2_count--) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) static int thermal_policy_setup(struct platform_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) int err, tp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) tp = hp_wmi_read_int(HPWMI_THERMAL_POLICY_QUERY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) if (tp < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) return tp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) * call thermal policy write command to ensure that the firmware correctly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) * sets the OEM variables for the DPTF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) err = hp_wmi_perform_query(HPWMI_THERMAL_POLICY_QUERY, HPWMI_WRITE, &tp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) sizeof(tp), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) static int __init hp_wmi_bios_setup(struct platform_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) /* clear detected rfkill devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) wifi_rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) bluetooth_rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) wwan_rfkill = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) rfkill2_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) if (hp_wmi_rfkill_setup(device))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) hp_wmi_rfkill2_setup(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) thermal_policy_setup(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) static int __exit hp_wmi_bios_remove(struct platform_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) for (i = 0; i < rfkill2_count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) rfkill_unregister(rfkill2[i].rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) rfkill_destroy(rfkill2[i].rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) if (wifi_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) rfkill_unregister(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) rfkill_destroy(wifi_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) if (bluetooth_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) rfkill_unregister(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) rfkill_destroy(bluetooth_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) if (wwan_rfkill) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) rfkill_unregister(wwan_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) rfkill_destroy(wwan_rfkill);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) static int hp_wmi_resume_handler(struct device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) * Hardware state may have changed while suspended, so trigger
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) * input events for the current state. As this is a switch,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) * the input layer will only actually pass it on if the state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) * changed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) if (hp_wmi_input_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) input_report_switch(hp_wmi_input_dev, SW_DOCK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) hp_wmi_hw_state(HPWMI_DOCK_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) hp_wmi_hw_state(HPWMI_TABLET_MASK));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) input_sync(hp_wmi_input_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) if (rfkill2_count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) hp_wmi_rfkill2_refresh();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) if (wifi_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) rfkill_set_states(wifi_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) hp_wmi_get_sw_state(HPWMI_WIFI),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) hp_wmi_get_hw_state(HPWMI_WIFI));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) if (bluetooth_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) rfkill_set_states(bluetooth_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) if (wwan_rfkill)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) rfkill_set_states(wwan_rfkill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) hp_wmi_get_sw_state(HPWMI_WWAN),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) hp_wmi_get_hw_state(HPWMI_WWAN));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) static const struct dev_pm_ops hp_wmi_pm_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) .resume = hp_wmi_resume_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) .restore = hp_wmi_resume_handler,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) static struct platform_driver hp_wmi_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) .name = "hp-wmi",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) .pm = &hp_wmi_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) .dev_groups = hp_wmi_groups,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) .remove = __exit_p(hp_wmi_bios_remove),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) static int __init hp_wmi_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) if (!bios_capable && !event_capable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) if (event_capable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) err = hp_wmi_input_setup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) if (bios_capable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) hp_wmi_platform_dev =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) platform_device_register_simple("hp-wmi", -1, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (IS_ERR(hp_wmi_platform_dev)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) err = PTR_ERR(hp_wmi_platform_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) goto err_destroy_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) goto err_unregister_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) err_unregister_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) platform_device_unregister(hp_wmi_platform_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) err_destroy_input:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) if (event_capable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) hp_wmi_input_destroy();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) module_init(hp_wmi_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) static void __exit hp_wmi_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) if (wmi_has_guid(HPWMI_EVENT_GUID))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) hp_wmi_input_destroy();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) if (hp_wmi_platform_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) platform_device_unregister(hp_wmi_platform_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) platform_driver_unregister(&hp_wmi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) module_exit(hp_wmi_exit);