brintos

brintos / linux-shallow public Read only

0
0
Text · 46.2 KiB · 8c05e0d Raw
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