1927 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * HP WMI hotkeys4 *5 * Copyright (C) 2008 Red Hat <mjg@redhat.com>6 * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>7 *8 * Portions based on wistron_btns.c:9 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>10 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>11 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>12 */13 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt15 16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/init.h>19#include <linux/slab.h>20#include <linux/types.h>21#include <linux/input.h>22#include <linux/input/sparse-keymap.h>23#include <linux/platform_device.h>24#include <linux/platform_profile.h>25#include <linux/hwmon.h>26#include <linux/acpi.h>27#include <linux/mutex.h>28#include <linux/cleanup.h>29#include <linux/power_supply.h>30#include <linux/rfkill.h>31#include <linux/string.h>32#include <linux/dmi.h>33 34MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");35MODULE_DESCRIPTION("HP laptop WMI driver");36MODULE_LICENSE("GPL");37 38MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");39MODULE_ALIAS("wmi:5FB7F034-2C63-45E9-BE91-3D44E2C707E4");40 41#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"42#define HPWMI_BIOS_GUID "5FB7F034-2C63-45E9-BE91-3D44E2C707E4"43 44#define HP_OMEN_EC_THERMAL_PROFILE_FLAGS_OFFSET 0x6245#define HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET 0x6346#define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x9547 48#define ACPI_AC_CLASS "ac_adapter"49 50#define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required51 52/* DMI board names of devices that should use the omen specific path for53 * thermal profiles.54 * This was obtained by taking a look in the windows omen command center55 * app and parsing a json file that they use to figure out what capabilities56 * the device should have.57 * A device is considered an omen if the DisplayName in that list contains58 * "OMEN", and it can use the thermal profile stuff if the "Feature" array59 * contains "PerformanceControl".60 */61static const char * const omen_thermal_profile_boards[] = {62 "84DA", "84DB", "84DC", "8574", "8575", "860A", "87B5", "8572", "8573",63 "8600", "8601", "8602", "8605", "8606", "8607", "8746", "8747", "8749",64 "874A", "8603", "8604", "8748", "886B", "886C", "878A", "878B", "878C",65 "88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD",66 "88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912",67 "8917", "8918", "8949", "894A", "89EB", "8BAD", "8A42"68};69 70/* DMI Board names of Omen laptops that are specifically set to be thermal71 * profile version 0 by the Omen Command Center app, regardless of what72 * the get system design information WMI call returns73 */74static const char * const omen_thermal_profile_force_v0_boards[] = {75 "8607", "8746", "8747", "8749", "874A", "8748"76};77 78/* DMI board names of Omen laptops that have a thermal profile timer which will79 * cause the embedded controller to set the thermal profile back to80 * "balanced" when reaching zero.81 */82static const char * const omen_timed_thermal_profile_boards[] = {83 "8BAD", "8A42"84};85 86/* DMI Board names of Victus laptops */87static const char * const victus_thermal_profile_boards[] = {88 "8A25"89};90 91enum hp_wmi_radio {92 HPWMI_WIFI = 0x0,93 HPWMI_BLUETOOTH = 0x1,94 HPWMI_WWAN = 0x2,95 HPWMI_GPS = 0x3,96};97 98enum hp_wmi_event_ids {99 HPWMI_DOCK_EVENT = 0x01,100 HPWMI_PARK_HDD = 0x02,101 HPWMI_SMART_ADAPTER = 0x03,102 HPWMI_BEZEL_BUTTON = 0x04,103 HPWMI_WIRELESS = 0x05,104 HPWMI_CPU_BATTERY_THROTTLE = 0x06,105 HPWMI_LOCK_SWITCH = 0x07,106 HPWMI_LID_SWITCH = 0x08,107 HPWMI_SCREEN_ROTATION = 0x09,108 HPWMI_COOLSENSE_SYSTEM_MOBILE = 0x0A,109 HPWMI_COOLSENSE_SYSTEM_HOT = 0x0B,110 HPWMI_PROXIMITY_SENSOR = 0x0C,111 HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D,112 HPWMI_PEAKSHIFT_PERIOD = 0x0F,113 HPWMI_BATTERY_CHARGE_PERIOD = 0x10,114 HPWMI_SANITIZATION_MODE = 0x17,115 HPWMI_CAMERA_TOGGLE = 0x1A,116 HPWMI_OMEN_KEY = 0x1D,117 HPWMI_SMART_EXPERIENCE_APP = 0x21,118};119 120/*121 * struct bios_args buffer is dynamically allocated. New WMI command types122 * were introduced that exceeds 128-byte data size. Changes to handle123 * the data size allocation scheme were kept in hp_wmi_perform_qurey function.124 */125struct bios_args {126 u32 signature;127 u32 command;128 u32 commandtype;129 u32 datasize;130 u8 data[];131};132 133enum hp_wmi_commandtype {134 HPWMI_DISPLAY_QUERY = 0x01,135 HPWMI_HDDTEMP_QUERY = 0x02,136 HPWMI_ALS_QUERY = 0x03,137 HPWMI_HARDWARE_QUERY = 0x04,138 HPWMI_WIRELESS_QUERY = 0x05,139 HPWMI_BATTERY_QUERY = 0x07,140 HPWMI_BIOS_QUERY = 0x09,141 HPWMI_FEATURE_QUERY = 0x0b,142 HPWMI_HOTKEY_QUERY = 0x0c,143 HPWMI_FEATURE2_QUERY = 0x0d,144 HPWMI_WIRELESS2_QUERY = 0x1b,145 HPWMI_POSTCODEERROR_QUERY = 0x2a,146 HPWMI_SYSTEM_DEVICE_MODE = 0x40,147 HPWMI_THERMAL_PROFILE_QUERY = 0x4c,148};149 150enum hp_wmi_gm_commandtype {151 HPWMI_FAN_SPEED_GET_QUERY = 0x11,152 HPWMI_SET_PERFORMANCE_MODE = 0x1A,153 HPWMI_FAN_SPEED_MAX_GET_QUERY = 0x26,154 HPWMI_FAN_SPEED_MAX_SET_QUERY = 0x27,155 HPWMI_GET_SYSTEM_DESIGN_DATA = 0x28,156};157 158enum hp_wmi_command {159 HPWMI_READ = 0x01,160 HPWMI_WRITE = 0x02,161 HPWMI_ODM = 0x03,162 HPWMI_GM = 0x20008,163};164 165enum hp_wmi_hardware_mask {166 HPWMI_DOCK_MASK = 0x01,167 HPWMI_TABLET_MASK = 0x04,168};169 170struct bios_return {171 u32 sigpass;172 u32 return_code;173};174 175enum hp_return_value {176 HPWMI_RET_WRONG_SIGNATURE = 0x02,177 HPWMI_RET_UNKNOWN_COMMAND = 0x03,178 HPWMI_RET_UNKNOWN_CMDTYPE = 0x04,179 HPWMI_RET_INVALID_PARAMETERS = 0x05,180};181 182enum hp_wireless2_bits {183 HPWMI_POWER_STATE = 0x01,184 HPWMI_POWER_SOFT = 0x02,185 HPWMI_POWER_BIOS = 0x04,186 HPWMI_POWER_HARD = 0x08,187 HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD,188};189 190enum hp_thermal_profile_omen_v0 {191 HP_OMEN_V0_THERMAL_PROFILE_DEFAULT = 0x00,192 HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE = 0x01,193 HP_OMEN_V0_THERMAL_PROFILE_COOL = 0x02,194};195 196enum hp_thermal_profile_omen_v1 {197 HP_OMEN_V1_THERMAL_PROFILE_DEFAULT = 0x30,198 HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE = 0x31,199 HP_OMEN_V1_THERMAL_PROFILE_COOL = 0x50,200};201 202enum hp_thermal_profile_omen_flags {203 HP_OMEN_EC_FLAGS_TURBO = 0x04,204 HP_OMEN_EC_FLAGS_NOTIMER = 0x02,205 HP_OMEN_EC_FLAGS_JUSTSET = 0x01,206};207 208enum hp_thermal_profile_victus {209 HP_VICTUS_THERMAL_PROFILE_DEFAULT = 0x00,210 HP_VICTUS_THERMAL_PROFILE_PERFORMANCE = 0x01,211 HP_VICTUS_THERMAL_PROFILE_QUIET = 0x03,212};213 214enum hp_thermal_profile {215 HP_THERMAL_PROFILE_PERFORMANCE = 0x00,216 HP_THERMAL_PROFILE_DEFAULT = 0x01,217 HP_THERMAL_PROFILE_COOL = 0x02,218 HP_THERMAL_PROFILE_QUIET = 0x03,219};220 221#define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW)222#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)223 224struct bios_rfkill2_device_state {225 u8 radio_type;226 u8 bus_type;227 u16 vendor_id;228 u16 product_id;229 u16 subsys_vendor_id;230 u16 subsys_product_id;231 u8 rfkill_id;232 u8 power;233 u8 unknown[4];234};235 236/* 7 devices fit into the 128 byte buffer */237#define HPWMI_MAX_RFKILL2_DEVICES 7238 239struct bios_rfkill2_state {240 u8 unknown[7];241 u8 count;242 u8 pad[8];243 struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];244};245 246static const struct key_entry hp_wmi_keymap[] = {247 { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } },248 { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } },249 { KE_KEY, 0x270, { KEY_MICMUTE } },250 { KE_KEY, 0x20e6, { KEY_PROG1 } },251 { KE_KEY, 0x20e8, { KEY_MEDIA } },252 { KE_KEY, 0x2142, { KEY_MEDIA } },253 { KE_KEY, 0x213b, { KEY_INFO } },254 { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } },255 { KE_KEY, 0x216a, { KEY_SETUP } },256 { KE_IGNORE, 0x21a4, }, /* Win Lock On */257 { KE_IGNORE, 0x121a4, }, /* Win Lock Off */258 { KE_KEY, 0x21a5, { KEY_PROG2 } }, /* HP Omen Key */259 { KE_KEY, 0x21a7, { KEY_FN_ESC } },260 { KE_KEY, 0x21a8, { KEY_PROG2 } }, /* HP Envy x360 programmable key */261 { KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } },262 { KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } },263 { KE_KEY, 0x231b, { KEY_HELP } },264 { KE_END, 0 }265};266 267/*268 * Mutex for the active_platform_profile variable,269 * see omen_powersource_event.270 */271static DEFINE_MUTEX(active_platform_profile_lock);272 273static struct input_dev *hp_wmi_input_dev;274static struct input_dev *camera_shutter_input_dev;275static struct platform_device *hp_wmi_platform_dev;276static struct platform_profile_handler platform_profile_handler;277static struct notifier_block platform_power_source_nb;278static enum platform_profile_option active_platform_profile;279static bool platform_profile_support;280static bool zero_insize_support;281 282static struct rfkill *wifi_rfkill;283static struct rfkill *bluetooth_rfkill;284static struct rfkill *wwan_rfkill;285 286struct rfkill2_device {287 u8 id;288 int num;289 struct rfkill *rfkill;290};291 292static int rfkill2_count;293static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];294 295/*296 * Chassis Types values were obtained from SMBIOS reference297 * specification version 3.00. A complete list of system enclosures298 * and chassis types is available on Table 17.299 */300static const char * const tablet_chassis_types[] = {301 "30", /* Tablet*/302 "31", /* Convertible */303 "32" /* Detachable */304};305 306#define DEVICE_MODE_TABLET 0x06307 308/* map output size to the corresponding WMI method id */309static inline int encode_outsize_for_pvsz(int outsize)310{311 if (outsize > 4096)312 return -EINVAL;313 if (outsize > 1024)314 return 5;315 if (outsize > 128)316 return 4;317 if (outsize > 4)318 return 3;319 if (outsize > 0)320 return 2;321 return 1;322}323 324/*325 * hp_wmi_perform_query326 *327 * query: The commandtype (enum hp_wmi_commandtype)328 * write: The command (enum hp_wmi_command)329 * buffer: Buffer used as input and/or output330 * insize: Size of input buffer331 * outsize: Size of output buffer332 *333 * returns zero on success334 * an HP WMI query specific error code (which is positive)335 * -EINVAL if the query was not successful at all336 * -EINVAL if the output buffer size exceeds buffersize337 *338 * Note: The buffersize must at least be the maximum of the input and output339 * size. E.g. Battery info query is defined to have 1 byte input340 * and 128 byte output. The caller would do:341 * buffer = kzalloc(128, GFP_KERNEL);342 * ret = hp_wmi_perform_query(HPWMI_BATTERY_QUERY, HPWMI_READ, buffer, 1, 128)343 */344static int hp_wmi_perform_query(int query, enum hp_wmi_command command,345 void *buffer, int insize, int outsize)346{347 struct acpi_buffer input, output = { ACPI_ALLOCATE_BUFFER, NULL };348 struct bios_return *bios_return;349 union acpi_object *obj = NULL;350 struct bios_args *args = NULL;351 int mid, actual_insize, actual_outsize;352 size_t bios_args_size;353 int ret;354 355 mid = encode_outsize_for_pvsz(outsize);356 if (WARN_ON(mid < 0))357 return mid;358 359 actual_insize = max(insize, 128);360 bios_args_size = struct_size(args, data, actual_insize);361 args = kmalloc(bios_args_size, GFP_KERNEL);362 if (!args)363 return -ENOMEM;364 365 input.length = bios_args_size;366 input.pointer = args;367 368 args->signature = 0x55434553;369 args->command = command;370 args->commandtype = query;371 args->datasize = insize;372 memcpy(args->data, buffer, flex_array_size(args, data, insize));373 374 ret = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);375 if (ret)376 goto out_free;377 378 obj = output.pointer;379 if (!obj) {380 ret = -EINVAL;381 goto out_free;382 }383 384 if (obj->type != ACPI_TYPE_BUFFER) {385 pr_warn("query 0x%x returned an invalid object 0x%x\n", query, ret);386 ret = -EINVAL;387 goto out_free;388 }389 390 bios_return = (struct bios_return *)obj->buffer.pointer;391 ret = bios_return->return_code;392 393 if (ret) {394 if (ret != HPWMI_RET_UNKNOWN_COMMAND &&395 ret != HPWMI_RET_UNKNOWN_CMDTYPE)396 pr_warn("query 0x%x returned error 0x%x\n", query, ret);397 goto out_free;398 }399 400 /* Ignore output data of zero size */401 if (!outsize)402 goto out_free;403 404 actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));405 memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);406 memset(buffer + actual_outsize, 0, outsize - actual_outsize);407 408out_free:409 kfree(obj);410 kfree(args);411 return ret;412}413 414static int hp_wmi_get_fan_speed(int fan)415{416 u8 fsh, fsl;417 char fan_data[4] = { fan, 0, 0, 0 };418 419 int ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_GET_QUERY, HPWMI_GM,420 &fan_data, sizeof(char),421 sizeof(fan_data));422 423 if (ret != 0)424 return -EINVAL;425 426 fsh = fan_data[2];427 fsl = fan_data[3];428 429 return (fsh << 8) | fsl;430}431 432static int hp_wmi_read_int(int query)433{434 int val = 0, ret;435 436 ret = hp_wmi_perform_query(query, HPWMI_READ, &val,437 zero_if_sup(val), sizeof(val));438 439 if (ret)440 return ret < 0 ? ret : -EINVAL;441 442 return val;443}444 445static int hp_wmi_get_dock_state(void)446{447 int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY);448 449 if (state < 0)450 return state;451 452 return !!(state & HPWMI_DOCK_MASK);453}454 455static int hp_wmi_get_tablet_mode(void)456{457 char system_device_mode[4] = { 0 };458 const char *chassis_type;459 bool tablet_found;460 int ret;461 462 chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);463 if (!chassis_type)464 return -ENODEV;465 466 tablet_found = match_string(tablet_chassis_types,467 ARRAY_SIZE(tablet_chassis_types),468 chassis_type) >= 0;469 if (!tablet_found)470 return -ENODEV;471 472 ret = hp_wmi_perform_query(HPWMI_SYSTEM_DEVICE_MODE, HPWMI_READ,473 system_device_mode, zero_if_sup(system_device_mode),474 sizeof(system_device_mode));475 if (ret < 0)476 return ret;477 478 return system_device_mode[0] == DEVICE_MODE_TABLET;479}480 481static int omen_thermal_profile_set(int mode)482{483 /* The Omen Control Center actively sets the first byte of the buffer to484 * 255, so let's mimic this behaviour to be as close as possible to485 * the original software.486 */487 char buffer[2] = {-1, mode};488 int ret;489 490 ret = hp_wmi_perform_query(HPWMI_SET_PERFORMANCE_MODE, HPWMI_GM,491 &buffer, sizeof(buffer), 0);492 493 if (ret)494 return ret < 0 ? ret : -EINVAL;495 496 return mode;497}498 499static bool is_omen_thermal_profile(void)500{501 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);502 503 if (!board_name)504 return false;505 506 return match_string(omen_thermal_profile_boards,507 ARRAY_SIZE(omen_thermal_profile_boards),508 board_name) >= 0;509}510 511static int omen_get_thermal_policy_version(void)512{513 unsigned char buffer[8] = { 0 };514 int ret;515 516 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);517 518 if (board_name) {519 int matches = match_string(omen_thermal_profile_force_v0_boards,520 ARRAY_SIZE(omen_thermal_profile_force_v0_boards),521 board_name);522 if (matches >= 0)523 return 0;524 }525 526 ret = hp_wmi_perform_query(HPWMI_GET_SYSTEM_DESIGN_DATA, HPWMI_GM,527 &buffer, sizeof(buffer), sizeof(buffer));528 529 if (ret)530 return ret < 0 ? ret : -EINVAL;531 532 return buffer[3];533}534 535static int omen_thermal_profile_get(void)536{537 u8 data;538 539 int ret = ec_read(HP_OMEN_EC_THERMAL_PROFILE_OFFSET, &data);540 541 if (ret)542 return ret;543 544 return data;545}546 547static int hp_wmi_fan_speed_max_set(int enabled)548{549 int ret;550 551 ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_SET_QUERY, HPWMI_GM,552 &enabled, sizeof(enabled), 0);553 554 if (ret)555 return ret < 0 ? ret : -EINVAL;556 557 return enabled;558}559 560static int hp_wmi_fan_speed_max_get(void)561{562 int val = 0, ret;563 564 ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_GET_QUERY, HPWMI_GM,565 &val, zero_if_sup(val), sizeof(val));566 567 if (ret)568 return ret < 0 ? ret : -EINVAL;569 570 return val;571}572 573static int __init hp_wmi_bios_2008_later(void)574{575 int state = 0;576 int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, HPWMI_READ, &state,577 zero_if_sup(state), sizeof(state));578 if (!ret)579 return 1;580 581 return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;582}583 584static int __init hp_wmi_bios_2009_later(void)585{586 u8 state[128];587 int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state,588 zero_if_sup(state), sizeof(state));589 if (!ret)590 return 1;591 592 return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;593}594 595static int __init hp_wmi_enable_hotkeys(void)596{597 int value = 0x6e;598 int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, HPWMI_WRITE, &value,599 sizeof(value), 0);600 601 return ret <= 0 ? ret : -EINVAL;602}603 604static int hp_wmi_set_block(void *data, bool blocked)605{606 enum hp_wmi_radio r = (long)data;607 int query = BIT(r + 8) | ((!blocked) << r);608 int ret;609 610 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE,611 &query, sizeof(query), 0);612 613 return ret <= 0 ? ret : -EINVAL;614}615 616static const struct rfkill_ops hp_wmi_rfkill_ops = {617 .set_block = hp_wmi_set_block,618};619 620static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)621{622 int mask = 0x200 << (r * 8);623 624 int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);625 626 /* TBD: Pass error */627 WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");628 629 return !(wireless & mask);630}631 632static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)633{634 int mask = 0x800 << (r * 8);635 636 int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);637 638 /* TBD: Pass error */639 WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");640 641 return !(wireless & mask);642}643 644static int hp_wmi_rfkill2_set_block(void *data, bool blocked)645{646 int rfkill_id = (int)(long)data;647 char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };648 int ret;649 650 ret = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_WRITE,651 buffer, sizeof(buffer), 0);652 653 return ret <= 0 ? ret : -EINVAL;654}655 656static const struct rfkill_ops hp_wmi_rfkill2_ops = {657 .set_block = hp_wmi_rfkill2_set_block,658};659 660static int hp_wmi_rfkill2_refresh(void)661{662 struct bios_rfkill2_state state;663 int err, i;664 665 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,666 zero_if_sup(state), sizeof(state));667 if (err)668 return err;669 670 for (i = 0; i < rfkill2_count; i++) {671 int num = rfkill2[i].num;672 struct bios_rfkill2_device_state *devstate;673 674 devstate = &state.device[num];675 676 if (num >= state.count ||677 devstate->rfkill_id != rfkill2[i].id) {678 pr_warn("power configuration of the wireless devices unexpectedly changed\n");679 continue;680 }681 682 rfkill_set_states(rfkill2[i].rfkill,683 IS_SWBLOCKED(devstate->power),684 IS_HWBLOCKED(devstate->power));685 }686 687 return 0;688}689 690static ssize_t display_show(struct device *dev, struct device_attribute *attr,691 char *buf)692{693 int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY);694 695 if (value < 0)696 return value;697 return sysfs_emit(buf, "%d\n", value);698}699 700static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr,701 char *buf)702{703 int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY);704 705 if (value < 0)706 return value;707 return sysfs_emit(buf, "%d\n", value);708}709 710static ssize_t als_show(struct device *dev, struct device_attribute *attr,711 char *buf)712{713 int value = hp_wmi_read_int(HPWMI_ALS_QUERY);714 715 if (value < 0)716 return value;717 return sysfs_emit(buf, "%d\n", value);718}719 720static ssize_t dock_show(struct device *dev, struct device_attribute *attr,721 char *buf)722{723 int value = hp_wmi_get_dock_state();724 725 if (value < 0)726 return value;727 return sysfs_emit(buf, "%d\n", value);728}729 730static ssize_t tablet_show(struct device *dev, struct device_attribute *attr,731 char *buf)732{733 int value = hp_wmi_get_tablet_mode();734 735 if (value < 0)736 return value;737 return sysfs_emit(buf, "%d\n", value);738}739 740static ssize_t postcode_show(struct device *dev, struct device_attribute *attr,741 char *buf)742{743 /* Get the POST error code of previous boot failure. */744 int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY);745 746 if (value < 0)747 return value;748 return sysfs_emit(buf, "0x%x\n", value);749}750 751static ssize_t als_store(struct device *dev, struct device_attribute *attr,752 const char *buf, size_t count)753{754 u32 tmp;755 int ret;756 757 ret = kstrtou32(buf, 10, &tmp);758 if (ret)759 return ret;760 761 ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_WRITE, &tmp,762 sizeof(tmp), 0);763 if (ret)764 return ret < 0 ? ret : -EINVAL;765 766 return count;767}768 769static ssize_t postcode_store(struct device *dev, struct device_attribute *attr,770 const char *buf, size_t count)771{772 u32 tmp = 1;773 bool clear;774 int ret;775 776 ret = kstrtobool(buf, &clear);777 if (ret)778 return ret;779 780 if (clear == false)781 return -EINVAL;782 783 /* Clear the POST error code. It is kept until cleared. */784 ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp,785 sizeof(tmp), 0);786 if (ret)787 return ret < 0 ? ret : -EINVAL;788 789 return count;790}791 792static int camera_shutter_input_setup(void)793{794 int err;795 796 camera_shutter_input_dev = input_allocate_device();797 if (!camera_shutter_input_dev)798 return -ENOMEM;799 800 camera_shutter_input_dev->name = "HP WMI camera shutter";801 camera_shutter_input_dev->phys = "wmi/input1";802 camera_shutter_input_dev->id.bustype = BUS_HOST;803 804 __set_bit(EV_SW, camera_shutter_input_dev->evbit);805 __set_bit(SW_CAMERA_LENS_COVER, camera_shutter_input_dev->swbit);806 807 err = input_register_device(camera_shutter_input_dev);808 if (err)809 goto err_free_dev;810 811 return 0;812 813 err_free_dev:814 input_free_device(camera_shutter_input_dev);815 camera_shutter_input_dev = NULL;816 return err;817}818 819static DEVICE_ATTR_RO(display);820static DEVICE_ATTR_RO(hddtemp);821static DEVICE_ATTR_RW(als);822static DEVICE_ATTR_RO(dock);823static DEVICE_ATTR_RO(tablet);824static DEVICE_ATTR_RW(postcode);825 826static struct attribute *hp_wmi_attrs[] = {827 &dev_attr_display.attr,828 &dev_attr_hddtemp.attr,829 &dev_attr_als.attr,830 &dev_attr_dock.attr,831 &dev_attr_tablet.attr,832 &dev_attr_postcode.attr,833 NULL,834};835ATTRIBUTE_GROUPS(hp_wmi);836 837static void hp_wmi_notify(union acpi_object *obj, void *context)838{839 u32 event_id, event_data;840 u32 *location;841 int key_code;842 843 if (!obj)844 return;845 if (obj->type != ACPI_TYPE_BUFFER) {846 pr_info("Unknown response received %d\n", obj->type);847 return;848 }849 850 /*851 * Depending on ACPI version the concatenation of id and event data852 * inside _WED function will result in a 8 or 16 byte buffer.853 */854 location = (u32 *)obj->buffer.pointer;855 if (obj->buffer.length == 8) {856 event_id = *location;857 event_data = *(location + 1);858 } else if (obj->buffer.length == 16) {859 event_id = *location;860 event_data = *(location + 2);861 } else {862 pr_info("Unknown buffer length %d\n", obj->buffer.length);863 return;864 }865 866 switch (event_id) {867 case HPWMI_DOCK_EVENT:868 if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))869 input_report_switch(hp_wmi_input_dev, SW_DOCK,870 hp_wmi_get_dock_state());871 if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))872 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,873 hp_wmi_get_tablet_mode());874 input_sync(hp_wmi_input_dev);875 break;876 case HPWMI_PARK_HDD:877 break;878 case HPWMI_SMART_ADAPTER:879 break;880 case HPWMI_BEZEL_BUTTON:881 key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);882 if (key_code < 0)883 break;884 885 if (!sparse_keymap_report_event(hp_wmi_input_dev,886 key_code, 1, true))887 pr_info("Unknown key code - 0x%x\n", key_code);888 break;889 case HPWMI_OMEN_KEY:890 if (event_data) /* Only should be true for HP Omen */891 key_code = event_data;892 else893 key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);894 895 if (!sparse_keymap_report_event(hp_wmi_input_dev,896 key_code, 1, true))897 pr_info("Unknown key code - 0x%x\n", key_code);898 break;899 case HPWMI_WIRELESS:900 if (rfkill2_count) {901 hp_wmi_rfkill2_refresh();902 break;903 }904 905 if (wifi_rfkill)906 rfkill_set_states(wifi_rfkill,907 hp_wmi_get_sw_state(HPWMI_WIFI),908 hp_wmi_get_hw_state(HPWMI_WIFI));909 if (bluetooth_rfkill)910 rfkill_set_states(bluetooth_rfkill,911 hp_wmi_get_sw_state(HPWMI_BLUETOOTH),912 hp_wmi_get_hw_state(HPWMI_BLUETOOTH));913 if (wwan_rfkill)914 rfkill_set_states(wwan_rfkill,915 hp_wmi_get_sw_state(HPWMI_WWAN),916 hp_wmi_get_hw_state(HPWMI_WWAN));917 break;918 case HPWMI_CPU_BATTERY_THROTTLE:919 pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");920 break;921 case HPWMI_LOCK_SWITCH:922 break;923 case HPWMI_LID_SWITCH:924 break;925 case HPWMI_SCREEN_ROTATION:926 break;927 case HPWMI_COOLSENSE_SYSTEM_MOBILE:928 break;929 case HPWMI_COOLSENSE_SYSTEM_HOT:930 break;931 case HPWMI_PROXIMITY_SENSOR:932 break;933 case HPWMI_BACKLIT_KB_BRIGHTNESS:934 break;935 case HPWMI_PEAKSHIFT_PERIOD:936 break;937 case HPWMI_BATTERY_CHARGE_PERIOD:938 break;939 case HPWMI_SANITIZATION_MODE:940 break;941 case HPWMI_CAMERA_TOGGLE:942 if (!camera_shutter_input_dev)943 if (camera_shutter_input_setup()) {944 pr_err("Failed to setup camera shutter input device\n");945 break;946 }947 if (event_data == 0xff)948 input_report_switch(camera_shutter_input_dev, SW_CAMERA_LENS_COVER, 1);949 else if (event_data == 0xfe)950 input_report_switch(camera_shutter_input_dev, SW_CAMERA_LENS_COVER, 0);951 else952 pr_warn("Unknown camera shutter state - 0x%x\n", event_data);953 input_sync(camera_shutter_input_dev);954 break;955 case HPWMI_SMART_EXPERIENCE_APP:956 break;957 default:958 pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);959 break;960 }961}962 963static int __init hp_wmi_input_setup(void)964{965 acpi_status status;966 int err, val;967 968 hp_wmi_input_dev = input_allocate_device();969 if (!hp_wmi_input_dev)970 return -ENOMEM;971 972 hp_wmi_input_dev->name = "HP WMI hotkeys";973 hp_wmi_input_dev->phys = "wmi/input0";974 hp_wmi_input_dev->id.bustype = BUS_HOST;975 976 __set_bit(EV_SW, hp_wmi_input_dev->evbit);977 978 /* Dock */979 val = hp_wmi_get_dock_state();980 if (!(val < 0)) {981 __set_bit(SW_DOCK, hp_wmi_input_dev->swbit);982 input_report_switch(hp_wmi_input_dev, SW_DOCK, val);983 }984 985 /* Tablet mode */986 val = hp_wmi_get_tablet_mode();987 if (!(val < 0)) {988 __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);989 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);990 }991 992 err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);993 if (err)994 goto err_free_dev;995 996 /* Set initial hardware state */997 input_sync(hp_wmi_input_dev);998 999 if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later())1000 hp_wmi_enable_hotkeys();1001 1002 status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);1003 if (ACPI_FAILURE(status)) {1004 err = -EIO;1005 goto err_free_dev;1006 }1007 1008 err = input_register_device(hp_wmi_input_dev);1009 if (err)1010 goto err_uninstall_notifier;1011 1012 return 0;1013 1014 err_uninstall_notifier:1015 wmi_remove_notify_handler(HPWMI_EVENT_GUID);1016 err_free_dev:1017 input_free_device(hp_wmi_input_dev);1018 return err;1019}1020 1021static void hp_wmi_input_destroy(void)1022{1023 wmi_remove_notify_handler(HPWMI_EVENT_GUID);1024 input_unregister_device(hp_wmi_input_dev);1025}1026 1027static int __init hp_wmi_rfkill_setup(struct platform_device *device)1028{1029 int err, wireless;1030 1031 wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);1032 if (wireless < 0)1033 return wireless;1034 1035 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &wireless,1036 sizeof(wireless), 0);1037 if (err)1038 return err;1039 1040 if (wireless & 0x1) {1041 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,1042 RFKILL_TYPE_WLAN,1043 &hp_wmi_rfkill_ops,1044 (void *) HPWMI_WIFI);1045 if (!wifi_rfkill)1046 return -ENOMEM;1047 rfkill_init_sw_state(wifi_rfkill,1048 hp_wmi_get_sw_state(HPWMI_WIFI));1049 rfkill_set_hw_state(wifi_rfkill,1050 hp_wmi_get_hw_state(HPWMI_WIFI));1051 err = rfkill_register(wifi_rfkill);1052 if (err)1053 goto register_wifi_error;1054 }1055 1056 if (wireless & 0x2) {1057 bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,1058 RFKILL_TYPE_BLUETOOTH,1059 &hp_wmi_rfkill_ops,1060 (void *) HPWMI_BLUETOOTH);1061 if (!bluetooth_rfkill) {1062 err = -ENOMEM;1063 goto register_bluetooth_error;1064 }1065 rfkill_init_sw_state(bluetooth_rfkill,1066 hp_wmi_get_sw_state(HPWMI_BLUETOOTH));1067 rfkill_set_hw_state(bluetooth_rfkill,1068 hp_wmi_get_hw_state(HPWMI_BLUETOOTH));1069 err = rfkill_register(bluetooth_rfkill);1070 if (err)1071 goto register_bluetooth_error;1072 }1073 1074 if (wireless & 0x4) {1075 wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,1076 RFKILL_TYPE_WWAN,1077 &hp_wmi_rfkill_ops,1078 (void *) HPWMI_WWAN);1079 if (!wwan_rfkill) {1080 err = -ENOMEM;1081 goto register_wwan_error;1082 }1083 rfkill_init_sw_state(wwan_rfkill,1084 hp_wmi_get_sw_state(HPWMI_WWAN));1085 rfkill_set_hw_state(wwan_rfkill,1086 hp_wmi_get_hw_state(HPWMI_WWAN));1087 err = rfkill_register(wwan_rfkill);1088 if (err)1089 goto register_wwan_error;1090 }1091 1092 return 0;1093 1094register_wwan_error:1095 rfkill_destroy(wwan_rfkill);1096 wwan_rfkill = NULL;1097 if (bluetooth_rfkill)1098 rfkill_unregister(bluetooth_rfkill);1099register_bluetooth_error:1100 rfkill_destroy(bluetooth_rfkill);1101 bluetooth_rfkill = NULL;1102 if (wifi_rfkill)1103 rfkill_unregister(wifi_rfkill);1104register_wifi_error:1105 rfkill_destroy(wifi_rfkill);1106 wifi_rfkill = NULL;1107 return err;1108}1109 1110static int __init hp_wmi_rfkill2_setup(struct platform_device *device)1111{1112 struct bios_rfkill2_state state;1113 int err, i;1114 1115 err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,1116 zero_if_sup(state), sizeof(state));1117 if (err)1118 return err < 0 ? err : -EINVAL;1119 1120 if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {1121 pr_warn("unable to parse 0x1b query output\n");1122 return -EINVAL;1123 }1124 1125 for (i = 0; i < state.count; i++) {1126 struct rfkill *rfkill;1127 enum rfkill_type type;1128 char *name;1129 1130 switch (state.device[i].radio_type) {1131 case HPWMI_WIFI:1132 type = RFKILL_TYPE_WLAN;1133 name = "hp-wifi";1134 break;1135 case HPWMI_BLUETOOTH:1136 type = RFKILL_TYPE_BLUETOOTH;1137 name = "hp-bluetooth";1138 break;1139 case HPWMI_WWAN:1140 type = RFKILL_TYPE_WWAN;1141 name = "hp-wwan";1142 break;1143 case HPWMI_GPS:1144 type = RFKILL_TYPE_GPS;1145 name = "hp-gps";1146 break;1147 default:1148 pr_warn("unknown device type 0x%x\n",1149 state.device[i].radio_type);1150 continue;1151 }1152 1153 if (!state.device[i].vendor_id) {1154 pr_warn("zero device %d while %d reported\n",1155 i, state.count);1156 continue;1157 }1158 1159 rfkill = rfkill_alloc(name, &device->dev, type,1160 &hp_wmi_rfkill2_ops, (void *)(long)i);1161 if (!rfkill) {1162 err = -ENOMEM;1163 goto fail;1164 }1165 1166 rfkill2[rfkill2_count].id = state.device[i].rfkill_id;1167 rfkill2[rfkill2_count].num = i;1168 rfkill2[rfkill2_count].rfkill = rfkill;1169 1170 rfkill_init_sw_state(rfkill,1171 IS_SWBLOCKED(state.device[i].power));1172 rfkill_set_hw_state(rfkill,1173 IS_HWBLOCKED(state.device[i].power));1174 1175 if (!(state.device[i].power & HPWMI_POWER_BIOS))1176 pr_info("device %s blocked by BIOS\n", name);1177 1178 err = rfkill_register(rfkill);1179 if (err) {1180 rfkill_destroy(rfkill);1181 goto fail;1182 }1183 1184 rfkill2_count++;1185 }1186 1187 return 0;1188fail:1189 for (; rfkill2_count > 0; rfkill2_count--) {1190 rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);1191 rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);1192 }1193 return err;1194}1195 1196static int platform_profile_omen_get_ec(enum platform_profile_option *profile)1197{1198 int tp;1199 1200 tp = omen_thermal_profile_get();1201 if (tp < 0)1202 return tp;1203 1204 switch (tp) {1205 case HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE:1206 case HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE:1207 *profile = PLATFORM_PROFILE_PERFORMANCE;1208 break;1209 case HP_OMEN_V0_THERMAL_PROFILE_DEFAULT:1210 case HP_OMEN_V1_THERMAL_PROFILE_DEFAULT:1211 *profile = PLATFORM_PROFILE_BALANCED;1212 break;1213 case HP_OMEN_V0_THERMAL_PROFILE_COOL:1214 case HP_OMEN_V1_THERMAL_PROFILE_COOL:1215 *profile = PLATFORM_PROFILE_COOL;1216 break;1217 default:1218 return -EINVAL;1219 }1220 1221 return 0;1222}1223 1224static int platform_profile_omen_get(struct platform_profile_handler *pprof,1225 enum platform_profile_option *profile)1226{1227 /*1228 * We directly return the stored platform profile, as the embedded1229 * controller will not accept switching to the performance option when1230 * the conditions are not met (e.g. the laptop is not plugged in).1231 *1232 * If we directly return what the EC reports, the platform profile will1233 * immediately "switch back" to normal mode, which is against the1234 * expected behaviour from a userspace point of view, as described in1235 * the Platform Profile Section page of the kernel documentation.1236 *1237 * See also omen_powersource_event.1238 */1239 guard(mutex)(&active_platform_profile_lock);1240 *profile = active_platform_profile;1241 1242 return 0;1243}1244 1245static bool has_omen_thermal_profile_ec_timer(void)1246{1247 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);1248 1249 if (!board_name)1250 return false;1251 1252 return match_string(omen_timed_thermal_profile_boards,1253 ARRAY_SIZE(omen_timed_thermal_profile_boards),1254 board_name) >= 0;1255}1256 1257inline int omen_thermal_profile_ec_flags_set(enum hp_thermal_profile_omen_flags flags)1258{1259 return ec_write(HP_OMEN_EC_THERMAL_PROFILE_FLAGS_OFFSET, flags);1260}1261 1262inline int omen_thermal_profile_ec_timer_set(u8 value)1263{1264 return ec_write(HP_OMEN_EC_THERMAL_PROFILE_TIMER_OFFSET, value);1265}1266 1267static int platform_profile_omen_set_ec(enum platform_profile_option profile)1268{1269 int err, tp, tp_version;1270 enum hp_thermal_profile_omen_flags flags = 0;1271 1272 tp_version = omen_get_thermal_policy_version();1273 1274 if (tp_version < 0 || tp_version > 1)1275 return -EOPNOTSUPP;1276 1277 switch (profile) {1278 case PLATFORM_PROFILE_PERFORMANCE:1279 if (tp_version == 0)1280 tp = HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE;1281 else1282 tp = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE;1283 break;1284 case PLATFORM_PROFILE_BALANCED:1285 if (tp_version == 0)1286 tp = HP_OMEN_V0_THERMAL_PROFILE_DEFAULT;1287 else1288 tp = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT;1289 break;1290 case PLATFORM_PROFILE_COOL:1291 if (tp_version == 0)1292 tp = HP_OMEN_V0_THERMAL_PROFILE_COOL;1293 else1294 tp = HP_OMEN_V1_THERMAL_PROFILE_COOL;1295 break;1296 default:1297 return -EOPNOTSUPP;1298 }1299 1300 err = omen_thermal_profile_set(tp);1301 if (err < 0)1302 return err;1303 1304 if (has_omen_thermal_profile_ec_timer()) {1305 err = omen_thermal_profile_ec_timer_set(0);1306 if (err < 0)1307 return err;1308 1309 if (profile == PLATFORM_PROFILE_PERFORMANCE)1310 flags = HP_OMEN_EC_FLAGS_NOTIMER |1311 HP_OMEN_EC_FLAGS_TURBO;1312 1313 err = omen_thermal_profile_ec_flags_set(flags);1314 if (err < 0)1315 return err;1316 }1317 1318 return 0;1319}1320 1321static int platform_profile_omen_set(struct platform_profile_handler *pprof,1322 enum platform_profile_option profile)1323{1324 int err;1325 1326 guard(mutex)(&active_platform_profile_lock);1327 1328 err = platform_profile_omen_set_ec(profile);1329 if (err < 0)1330 return err;1331 1332 active_platform_profile = profile;1333 1334 return 0;1335}1336 1337static int thermal_profile_get(void)1338{1339 return hp_wmi_read_int(HPWMI_THERMAL_PROFILE_QUERY);1340}1341 1342static int thermal_profile_set(int thermal_profile)1343{1344 return hp_wmi_perform_query(HPWMI_THERMAL_PROFILE_QUERY, HPWMI_WRITE, &thermal_profile,1345 sizeof(thermal_profile), 0);1346}1347 1348static int hp_wmi_platform_profile_get(struct platform_profile_handler *pprof,1349 enum platform_profile_option *profile)1350{1351 int tp;1352 1353 tp = thermal_profile_get();1354 if (tp < 0)1355 return tp;1356 1357 switch (tp) {1358 case HP_THERMAL_PROFILE_PERFORMANCE:1359 *profile = PLATFORM_PROFILE_PERFORMANCE;1360 break;1361 case HP_THERMAL_PROFILE_DEFAULT:1362 *profile = PLATFORM_PROFILE_BALANCED;1363 break;1364 case HP_THERMAL_PROFILE_COOL:1365 *profile = PLATFORM_PROFILE_COOL;1366 break;1367 case HP_THERMAL_PROFILE_QUIET:1368 *profile = PLATFORM_PROFILE_QUIET;1369 break;1370 default:1371 return -EINVAL;1372 }1373 1374 return 0;1375}1376 1377static int hp_wmi_platform_profile_set(struct platform_profile_handler *pprof,1378 enum platform_profile_option profile)1379{1380 int err, tp;1381 1382 switch (profile) {1383 case PLATFORM_PROFILE_PERFORMANCE:1384 tp = HP_THERMAL_PROFILE_PERFORMANCE;1385 break;1386 case PLATFORM_PROFILE_BALANCED:1387 tp = HP_THERMAL_PROFILE_DEFAULT;1388 break;1389 case PLATFORM_PROFILE_COOL:1390 tp = HP_THERMAL_PROFILE_COOL;1391 break;1392 case PLATFORM_PROFILE_QUIET:1393 tp = HP_THERMAL_PROFILE_QUIET;1394 break;1395 default:1396 return -EOPNOTSUPP;1397 }1398 1399 err = thermal_profile_set(tp);1400 if (err)1401 return err;1402 1403 return 0;1404}1405 1406static bool is_victus_thermal_profile(void)1407{1408 const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);1409 1410 if (!board_name)1411 return false;1412 1413 return match_string(victus_thermal_profile_boards,1414 ARRAY_SIZE(victus_thermal_profile_boards),1415 board_name) >= 0;1416}1417 1418static int platform_profile_victus_get_ec(enum platform_profile_option *profile)1419{1420 int tp;1421 1422 tp = omen_thermal_profile_get();1423 if (tp < 0)1424 return tp;1425 1426 switch (tp) {1427 case HP_VICTUS_THERMAL_PROFILE_PERFORMANCE:1428 *profile = PLATFORM_PROFILE_PERFORMANCE;1429 break;1430 case HP_VICTUS_THERMAL_PROFILE_DEFAULT:1431 *profile = PLATFORM_PROFILE_BALANCED;1432 break;1433 case HP_VICTUS_THERMAL_PROFILE_QUIET:1434 *profile = PLATFORM_PROFILE_QUIET;1435 break;1436 default:1437 return -EOPNOTSUPP;1438 }1439 1440 return 0;1441}1442 1443static int platform_profile_victus_get(struct platform_profile_handler *pprof,1444 enum platform_profile_option *profile)1445{1446 /* Same behaviour as platform_profile_omen_get */1447 return platform_profile_omen_get(pprof, profile);1448}1449 1450static int platform_profile_victus_set_ec(enum platform_profile_option profile)1451{1452 int err, tp;1453 1454 switch (profile) {1455 case PLATFORM_PROFILE_PERFORMANCE:1456 tp = HP_VICTUS_THERMAL_PROFILE_PERFORMANCE;1457 break;1458 case PLATFORM_PROFILE_BALANCED:1459 tp = HP_VICTUS_THERMAL_PROFILE_DEFAULT;1460 break;1461 case PLATFORM_PROFILE_QUIET:1462 tp = HP_VICTUS_THERMAL_PROFILE_QUIET;1463 break;1464 default:1465 return -EOPNOTSUPP;1466 }1467 1468 err = omen_thermal_profile_set(tp);1469 if (err < 0)1470 return err;1471 1472 return 0;1473}1474 1475static int platform_profile_victus_set(struct platform_profile_handler *pprof,1476 enum platform_profile_option profile)1477{1478 int err;1479 1480 guard(mutex)(&active_platform_profile_lock);1481 1482 err = platform_profile_victus_set_ec(profile);1483 if (err < 0)1484 return err;1485 1486 active_platform_profile = profile;1487 1488 return 0;1489}1490 1491static int omen_powersource_event(struct notifier_block *nb,1492 unsigned long value,1493 void *data)1494{1495 struct acpi_bus_event *event_entry = data;1496 enum platform_profile_option actual_profile;1497 int err;1498 1499 if (strcmp(event_entry->device_class, ACPI_AC_CLASS) != 0)1500 return NOTIFY_DONE;1501 1502 pr_debug("Received power source device event\n");1503 1504 guard(mutex)(&active_platform_profile_lock);1505 1506 /*1507 * This handler can only be called on Omen and Victus models, so1508 * there's no need to call is_victus_thermal_profile() here.1509 */1510 if (is_omen_thermal_profile())1511 err = platform_profile_omen_get_ec(&actual_profile);1512 else1513 err = platform_profile_victus_get_ec(&actual_profile);1514 1515 if (err < 0) {1516 /*1517 * Although we failed to get the current platform profile, we1518 * still want the other event consumers to process it.1519 */1520 pr_warn("Failed to read current platform profile (%d)\n", err);1521 return NOTIFY_DONE;1522 }1523 1524 /*1525 * If we're back on AC and that the user-chosen power profile is1526 * different from what the EC reports, we restore the user-chosen1527 * one.1528 */1529 if (power_supply_is_system_supplied() <= 0 ||1530 active_platform_profile == actual_profile) {1531 pr_debug("Platform profile update skipped, conditions unmet\n");1532 return NOTIFY_DONE;1533 }1534 1535 if (is_omen_thermal_profile())1536 err = platform_profile_omen_set_ec(active_platform_profile);1537 else1538 err = platform_profile_victus_set_ec(active_platform_profile);1539 1540 if (err < 0) {1541 pr_warn("Failed to restore platform profile (%d)\n", err);1542 return NOTIFY_DONE;1543 }1544 1545 return NOTIFY_OK;1546}1547 1548static int omen_register_powersource_event_handler(void)1549{1550 int err;1551 1552 platform_power_source_nb.notifier_call = omen_powersource_event;1553 err = register_acpi_notifier(&platform_power_source_nb);1554 1555 if (err < 0) {1556 pr_warn("Failed to install ACPI power source notify handler\n");1557 return err;1558 }1559 1560 return 0;1561}1562 1563static inline void omen_unregister_powersource_event_handler(void)1564{1565 unregister_acpi_notifier(&platform_power_source_nb);1566}1567 1568static int thermal_profile_setup(void)1569{1570 int err, tp;1571 1572 if (is_omen_thermal_profile()) {1573 err = platform_profile_omen_get_ec(&active_platform_profile);1574 if (err < 0)1575 return err;1576 1577 /*1578 * call thermal profile write command to ensure that the1579 * firmware correctly sets the OEM variables1580 */1581 err = platform_profile_omen_set_ec(active_platform_profile);1582 if (err < 0)1583 return err;1584 1585 platform_profile_handler.profile_get = platform_profile_omen_get;1586 platform_profile_handler.profile_set = platform_profile_omen_set;1587 1588 set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices);1589 } else if (is_victus_thermal_profile()) {1590 err = platform_profile_victus_get_ec(&active_platform_profile);1591 if (err < 0)1592 return err;1593 1594 /*1595 * call thermal profile write command to ensure that the1596 * firmware correctly sets the OEM variables1597 */1598 err = platform_profile_victus_set_ec(active_platform_profile);1599 if (err < 0)1600 return err;1601 1602 platform_profile_handler.profile_get = platform_profile_victus_get;1603 platform_profile_handler.profile_set = platform_profile_victus_set;1604 1605 set_bit(PLATFORM_PROFILE_QUIET, platform_profile_handler.choices);1606 } else {1607 tp = thermal_profile_get();1608 1609 if (tp < 0)1610 return tp;1611 1612 /*1613 * call thermal profile write command to ensure that the1614 * firmware correctly sets the OEM variables for the DPTF1615 */1616 err = thermal_profile_set(tp);1617 if (err)1618 return err;1619 1620 platform_profile_handler.profile_get = hp_wmi_platform_profile_get;1621 platform_profile_handler.profile_set = hp_wmi_platform_profile_set;1622 1623 set_bit(PLATFORM_PROFILE_QUIET, platform_profile_handler.choices);1624 set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices);1625 }1626 1627 set_bit(PLATFORM_PROFILE_BALANCED, platform_profile_handler.choices);1628 set_bit(PLATFORM_PROFILE_PERFORMANCE, platform_profile_handler.choices);1629 1630 err = platform_profile_register(&platform_profile_handler);1631 if (err)1632 return err;1633 1634 platform_profile_support = true;1635 1636 return 0;1637}1638 1639static int hp_wmi_hwmon_init(void);1640 1641static int __init hp_wmi_bios_setup(struct platform_device *device)1642{1643 int err;1644 /* clear detected rfkill devices */1645 wifi_rfkill = NULL;1646 bluetooth_rfkill = NULL;1647 wwan_rfkill = NULL;1648 rfkill2_count = 0;1649 1650 /*1651 * In pre-2009 BIOS, command 1Bh return 0x4 to indicate that1652 * BIOS no longer controls the power for the wireless1653 * devices. All features supported by this command will no1654 * longer be supported.1655 */1656 if (!hp_wmi_bios_2009_later()) {1657 if (hp_wmi_rfkill_setup(device))1658 hp_wmi_rfkill2_setup(device);1659 }1660 1661 err = hp_wmi_hwmon_init();1662 1663 if (err < 0)1664 return err;1665 1666 thermal_profile_setup();1667 1668 return 0;1669}1670 1671static void __exit hp_wmi_bios_remove(struct platform_device *device)1672{1673 int i;1674 1675 for (i = 0; i < rfkill2_count; i++) {1676 rfkill_unregister(rfkill2[i].rfkill);1677 rfkill_destroy(rfkill2[i].rfkill);1678 }1679 1680 if (wifi_rfkill) {1681 rfkill_unregister(wifi_rfkill);1682 rfkill_destroy(wifi_rfkill);1683 }1684 if (bluetooth_rfkill) {1685 rfkill_unregister(bluetooth_rfkill);1686 rfkill_destroy(bluetooth_rfkill);1687 }1688 if (wwan_rfkill) {1689 rfkill_unregister(wwan_rfkill);1690 rfkill_destroy(wwan_rfkill);1691 }1692 1693 if (platform_profile_support)1694 platform_profile_remove();1695}1696 1697static int hp_wmi_resume_handler(struct device *device)1698{1699 /*1700 * Hardware state may have changed while suspended, so trigger1701 * input events for the current state. As this is a switch,1702 * the input layer will only actually pass it on if the state1703 * changed.1704 */1705 if (hp_wmi_input_dev) {1706 if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))1707 input_report_switch(hp_wmi_input_dev, SW_DOCK,1708 hp_wmi_get_dock_state());1709 if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))1710 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,1711 hp_wmi_get_tablet_mode());1712 input_sync(hp_wmi_input_dev);1713 }1714 1715 if (rfkill2_count)1716 hp_wmi_rfkill2_refresh();1717 1718 if (wifi_rfkill)1719 rfkill_set_states(wifi_rfkill,1720 hp_wmi_get_sw_state(HPWMI_WIFI),1721 hp_wmi_get_hw_state(HPWMI_WIFI));1722 if (bluetooth_rfkill)1723 rfkill_set_states(bluetooth_rfkill,1724 hp_wmi_get_sw_state(HPWMI_BLUETOOTH),1725 hp_wmi_get_hw_state(HPWMI_BLUETOOTH));1726 if (wwan_rfkill)1727 rfkill_set_states(wwan_rfkill,1728 hp_wmi_get_sw_state(HPWMI_WWAN),1729 hp_wmi_get_hw_state(HPWMI_WWAN));1730 1731 return 0;1732}1733 1734static const struct dev_pm_ops hp_wmi_pm_ops = {1735 .resume = hp_wmi_resume_handler,1736 .restore = hp_wmi_resume_handler,1737};1738 1739/*1740 * hp_wmi_bios_remove() lives in .exit.text. For drivers registered via1741 * module_platform_driver_probe() this is ok because they cannot get unbound at1742 * runtime. So mark the driver struct with __refdata to prevent modpost1743 * triggering a section mismatch warning.1744 */1745static struct platform_driver hp_wmi_driver __refdata = {1746 .driver = {1747 .name = "hp-wmi",1748 .pm = &hp_wmi_pm_ops,1749 .dev_groups = hp_wmi_groups,1750 },1751 .remove_new = __exit_p(hp_wmi_bios_remove),1752};1753 1754static umode_t hp_wmi_hwmon_is_visible(const void *data,1755 enum hwmon_sensor_types type,1756 u32 attr, int channel)1757{1758 switch (type) {1759 case hwmon_pwm:1760 return 0644;1761 case hwmon_fan:1762 if (hp_wmi_get_fan_speed(channel) >= 0)1763 return 0444;1764 break;1765 default:1766 return 0;1767 }1768 1769 return 0;1770}1771 1772static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,1773 u32 attr, int channel, long *val)1774{1775 int ret;1776 1777 switch (type) {1778 case hwmon_fan:1779 ret = hp_wmi_get_fan_speed(channel);1780 1781 if (ret < 0)1782 return ret;1783 *val = ret;1784 return 0;1785 case hwmon_pwm:1786 switch (hp_wmi_fan_speed_max_get()) {1787 case 0:1788 /* 0 is automatic fan, which is 2 for hwmon */1789 *val = 2;1790 return 0;1791 case 1:1792 /* 1 is max fan, which is 01793 * (no fan speed control) for hwmon1794 */1795 *val = 0;1796 return 0;1797 default:1798 /* shouldn't happen */1799 return -ENODATA;1800 }1801 default:1802 return -EINVAL;1803 }1804}1805 1806static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,1807 u32 attr, int channel, long val)1808{1809 switch (type) {1810 case hwmon_pwm:1811 switch (val) {1812 case 0:1813 /* 0 is no fan speed control (max), which is 1 for us */1814 return hp_wmi_fan_speed_max_set(1);1815 case 2:1816 /* 2 is automatic speed control, which is 0 for us */1817 return hp_wmi_fan_speed_max_set(0);1818 default:1819 /* we don't support manual fan speed control */1820 return -EINVAL;1821 }1822 default:1823 return -EOPNOTSUPP;1824 }1825}1826 1827static const struct hwmon_channel_info * const info[] = {1828 HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT),1829 HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE),1830 NULL1831};1832 1833static const struct hwmon_ops ops = {1834 .is_visible = hp_wmi_hwmon_is_visible,1835 .read = hp_wmi_hwmon_read,1836 .write = hp_wmi_hwmon_write,1837};1838 1839static const struct hwmon_chip_info chip_info = {1840 .ops = &ops,1841 .info = info,1842};1843 1844static int hp_wmi_hwmon_init(void)1845{1846 struct device *dev = &hp_wmi_platform_dev->dev;1847 struct device *hwmon;1848 1849 hwmon = devm_hwmon_device_register_with_info(dev, "hp", &hp_wmi_driver,1850 &chip_info, NULL);1851 1852 if (IS_ERR(hwmon)) {1853 dev_err(dev, "Could not register hp hwmon device\n");1854 return PTR_ERR(hwmon);1855 }1856 1857 return 0;1858}1859 1860static int __init hp_wmi_init(void)1861{1862 int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);1863 int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);1864 int err, tmp = 0;1865 1866 if (!bios_capable && !event_capable)1867 return -ENODEV;1868 1869 if (hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_READ, &tmp,1870 sizeof(tmp), sizeof(tmp)) == HPWMI_RET_INVALID_PARAMETERS)1871 zero_insize_support = true;1872 1873 if (event_capable) {1874 err = hp_wmi_input_setup();1875 if (err)1876 return err;1877 }1878 1879 if (bios_capable) {1880 hp_wmi_platform_dev =1881 platform_device_register_simple("hp-wmi", PLATFORM_DEVID_NONE, NULL, 0);1882 if (IS_ERR(hp_wmi_platform_dev)) {1883 err = PTR_ERR(hp_wmi_platform_dev);1884 goto err_destroy_input;1885 }1886 1887 err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup);1888 if (err)1889 goto err_unregister_device;1890 }1891 1892 if (is_omen_thermal_profile() || is_victus_thermal_profile()) {1893 err = omen_register_powersource_event_handler();1894 if (err)1895 goto err_unregister_device;1896 }1897 1898 return 0;1899 1900err_unregister_device:1901 platform_device_unregister(hp_wmi_platform_dev);1902err_destroy_input:1903 if (event_capable)1904 hp_wmi_input_destroy();1905 1906 return err;1907}1908module_init(hp_wmi_init);1909 1910static void __exit hp_wmi_exit(void)1911{1912 if (is_omen_thermal_profile() || is_victus_thermal_profile())1913 omen_unregister_powersource_event_handler();1914 1915 if (wmi_has_guid(HPWMI_EVENT_GUID))1916 hp_wmi_input_destroy();1917 1918 if (camera_shutter_input_dev)1919 input_unregister_device(camera_shutter_input_dev);1920 1921 if (hp_wmi_platform_dev) {1922 platform_device_unregister(hp_wmi_platform_dev);1923 platform_driver_unregister(&hp_wmi_driver);1924 }1925}1926module_exit(hp_wmi_exit);1927