xref: /openbmc/linux/drivers/platform/x86/hp/hp-wmi.c (revision 5b44abbc)
16e9b8992SJorge Lopez // SPDX-License-Identifier: GPL-2.0-or-later
26e9b8992SJorge Lopez /*
36e9b8992SJorge Lopez  * HP WMI hotkeys
46e9b8992SJorge Lopez  *
56e9b8992SJorge Lopez  * Copyright (C) 2008 Red Hat <mjg@redhat.com>
66e9b8992SJorge Lopez  * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
76e9b8992SJorge Lopez  *
86e9b8992SJorge Lopez  * Portions based on wistron_btns.c:
96e9b8992SJorge Lopez  * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
106e9b8992SJorge Lopez  * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
116e9b8992SJorge Lopez  * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
126e9b8992SJorge Lopez  */
136e9b8992SJorge Lopez 
146e9b8992SJorge Lopez #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
156e9b8992SJorge Lopez 
166e9b8992SJorge Lopez #include <linux/kernel.h>
176e9b8992SJorge Lopez #include <linux/module.h>
186e9b8992SJorge Lopez #include <linux/init.h>
196e9b8992SJorge Lopez #include <linux/slab.h>
206e9b8992SJorge Lopez #include <linux/types.h>
216e9b8992SJorge Lopez #include <linux/input.h>
226e9b8992SJorge Lopez #include <linux/input/sparse-keymap.h>
236e9b8992SJorge Lopez #include <linux/platform_device.h>
246e9b8992SJorge Lopez #include <linux/platform_profile.h>
256e9b8992SJorge Lopez #include <linux/hwmon.h>
266e9b8992SJorge Lopez #include <linux/acpi.h>
276e9b8992SJorge Lopez #include <linux/rfkill.h>
286e9b8992SJorge Lopez #include <linux/string.h>
296e9b8992SJorge Lopez #include <linux/dmi.h>
306e9b8992SJorge Lopez 
316e9b8992SJorge Lopez MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
326e9b8992SJorge Lopez MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
336e9b8992SJorge Lopez MODULE_LICENSE("GPL");
346e9b8992SJorge Lopez 
356e9b8992SJorge Lopez MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
366e9b8992SJorge Lopez MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
376e9b8992SJorge Lopez 
386e9b8992SJorge Lopez #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
396e9b8992SJorge Lopez #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
406e9b8992SJorge Lopez #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
416e9b8992SJorge Lopez #define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required
426e9b8992SJorge Lopez 
436e9b8992SJorge Lopez /* DMI board names of devices that should use the omen specific path for
446e9b8992SJorge Lopez  * thermal profiles.
456e9b8992SJorge Lopez  * This was obtained by taking a look in the windows omen command center
466e9b8992SJorge Lopez  * app and parsing a json file that they use to figure out what capabilities
476e9b8992SJorge Lopez  * the device should have.
486e9b8992SJorge Lopez  * A device is considered an omen if the DisplayName in that list contains
496e9b8992SJorge Lopez  * "OMEN", and it can use the thermal profile stuff if the "Feature" array
506e9b8992SJorge Lopez  * contains "PerformanceControl".
516e9b8992SJorge Lopez  */
526e9b8992SJorge Lopez static const char * const omen_thermal_profile_boards[] = {
536e9b8992SJorge Lopez 	"84DA", "84DB", "84DC", "8574", "8575", "860A", "87B5", "8572", "8573",
546e9b8992SJorge Lopez 	"8600", "8601", "8602", "8605", "8606", "8607", "8746", "8747", "8749",
556e9b8992SJorge Lopez 	"874A", "8603", "8604", "8748", "886B", "886C", "878A", "878B", "878C",
566e9b8992SJorge Lopez 	"88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD",
576e9b8992SJorge Lopez 	"88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912",
586e9b8992SJorge Lopez 	"8917", "8918", "8949", "894A", "89EB"
596e9b8992SJorge Lopez };
606e9b8992SJorge Lopez 
616e9b8992SJorge Lopez /* DMI Board names of Omen laptops that are specifically set to be thermal
626e9b8992SJorge Lopez  * profile version 0 by the Omen Command Center app, regardless of what
636e9b8992SJorge Lopez  * the get system design information WMI call returns
646e9b8992SJorge Lopez  */
656e9b8992SJorge Lopez static const char *const omen_thermal_profile_force_v0_boards[] = {
666e9b8992SJorge Lopez 	"8607", "8746", "8747", "8749", "874A", "8748"
676e9b8992SJorge Lopez };
686e9b8992SJorge Lopez 
692515e542SSungHwan Jung /* DMI Board names of Victus laptops */
702515e542SSungHwan Jung static const char * const victus_thermal_profile_boards[] = {
712515e542SSungHwan Jung 	"8A25"
722515e542SSungHwan Jung };
732515e542SSungHwan Jung 
746e9b8992SJorge Lopez enum hp_wmi_radio {
756e9b8992SJorge Lopez 	HPWMI_WIFI	= 0x0,
766e9b8992SJorge Lopez 	HPWMI_BLUETOOTH	= 0x1,
776e9b8992SJorge Lopez 	HPWMI_WWAN	= 0x2,
786e9b8992SJorge Lopez 	HPWMI_GPS	= 0x3,
796e9b8992SJorge Lopez };
806e9b8992SJorge Lopez 
816e9b8992SJorge Lopez enum hp_wmi_event_ids {
826e9b8992SJorge Lopez 	HPWMI_DOCK_EVENT		= 0x01,
836e9b8992SJorge Lopez 	HPWMI_PARK_HDD			= 0x02,
846e9b8992SJorge Lopez 	HPWMI_SMART_ADAPTER		= 0x03,
856e9b8992SJorge Lopez 	HPWMI_BEZEL_BUTTON		= 0x04,
866e9b8992SJorge Lopez 	HPWMI_WIRELESS			= 0x05,
876e9b8992SJorge Lopez 	HPWMI_CPU_BATTERY_THROTTLE	= 0x06,
886e9b8992SJorge Lopez 	HPWMI_LOCK_SWITCH		= 0x07,
896e9b8992SJorge Lopez 	HPWMI_LID_SWITCH		= 0x08,
906e9b8992SJorge Lopez 	HPWMI_SCREEN_ROTATION		= 0x09,
916e9b8992SJorge Lopez 	HPWMI_COOLSENSE_SYSTEM_MOBILE	= 0x0A,
926e9b8992SJorge Lopez 	HPWMI_COOLSENSE_SYSTEM_HOT	= 0x0B,
936e9b8992SJorge Lopez 	HPWMI_PROXIMITY_SENSOR		= 0x0C,
946e9b8992SJorge Lopez 	HPWMI_BACKLIT_KB_BRIGHTNESS	= 0x0D,
956e9b8992SJorge Lopez 	HPWMI_PEAKSHIFT_PERIOD		= 0x0F,
966e9b8992SJorge Lopez 	HPWMI_BATTERY_CHARGE_PERIOD	= 0x10,
976e9b8992SJorge Lopez 	HPWMI_SANITIZATION_MODE		= 0x17,
98604915f1SJonathan Singer 	HPWMI_CAMERA_TOGGLE		= 0x1A,
993ee5447bSRishit Bansal 	HPWMI_OMEN_KEY			= 0x1D,
1006e9b8992SJorge Lopez 	HPWMI_SMART_EXPERIENCE_APP	= 0x21,
1016e9b8992SJorge Lopez };
1026e9b8992SJorge Lopez 
1036e9b8992SJorge Lopez /*
1046e9b8992SJorge Lopez  * struct bios_args buffer is dynamically allocated.  New WMI command types
1056e9b8992SJorge Lopez  * were introduced that exceeds 128-byte data size.  Changes to handle
1066e9b8992SJorge Lopez  * the data size allocation scheme were kept in hp_wmi_perform_qurey function.
1076e9b8992SJorge Lopez  */
1086e9b8992SJorge Lopez struct bios_args {
1096e9b8992SJorge Lopez 	u32 signature;
1106e9b8992SJorge Lopez 	u32 command;
1116e9b8992SJorge Lopez 	u32 commandtype;
1126e9b8992SJorge Lopez 	u32 datasize;
1136e9b8992SJorge Lopez 	u8 data[];
1146e9b8992SJorge Lopez };
1156e9b8992SJorge Lopez 
1166e9b8992SJorge Lopez enum hp_wmi_commandtype {
1176e9b8992SJorge Lopez 	HPWMI_DISPLAY_QUERY		= 0x01,
1186e9b8992SJorge Lopez 	HPWMI_HDDTEMP_QUERY		= 0x02,
1196e9b8992SJorge Lopez 	HPWMI_ALS_QUERY			= 0x03,
1206e9b8992SJorge Lopez 	HPWMI_HARDWARE_QUERY		= 0x04,
1216e9b8992SJorge Lopez 	HPWMI_WIRELESS_QUERY		= 0x05,
1226e9b8992SJorge Lopez 	HPWMI_BATTERY_QUERY		= 0x07,
1236e9b8992SJorge Lopez 	HPWMI_BIOS_QUERY		= 0x09,
1246e9b8992SJorge Lopez 	HPWMI_FEATURE_QUERY		= 0x0b,
1256e9b8992SJorge Lopez 	HPWMI_HOTKEY_QUERY		= 0x0c,
1266e9b8992SJorge Lopez 	HPWMI_FEATURE2_QUERY		= 0x0d,
1276e9b8992SJorge Lopez 	HPWMI_WIRELESS2_QUERY		= 0x1b,
1286e9b8992SJorge Lopez 	HPWMI_POSTCODEERROR_QUERY	= 0x2a,
1296e9b8992SJorge Lopez 	HPWMI_SYSTEM_DEVICE_MODE	= 0x40,
1306e9b8992SJorge Lopez 	HPWMI_THERMAL_PROFILE_QUERY	= 0x4c,
1316e9b8992SJorge Lopez };
1326e9b8992SJorge Lopez 
1336e9b8992SJorge Lopez enum hp_wmi_gm_commandtype {
1346e9b8992SJorge Lopez 	HPWMI_FAN_SPEED_GET_QUERY = 0x11,
1356e9b8992SJorge Lopez 	HPWMI_SET_PERFORMANCE_MODE = 0x1A,
1366e9b8992SJorge Lopez 	HPWMI_FAN_SPEED_MAX_GET_QUERY = 0x26,
1376e9b8992SJorge Lopez 	HPWMI_FAN_SPEED_MAX_SET_QUERY = 0x27,
1386e9b8992SJorge Lopez 	HPWMI_GET_SYSTEM_DESIGN_DATA = 0x28,
1396e9b8992SJorge Lopez };
1406e9b8992SJorge Lopez 
1416e9b8992SJorge Lopez enum hp_wmi_command {
1426e9b8992SJorge Lopez 	HPWMI_READ	= 0x01,
1436e9b8992SJorge Lopez 	HPWMI_WRITE	= 0x02,
1446e9b8992SJorge Lopez 	HPWMI_ODM	= 0x03,
1456e9b8992SJorge Lopez 	HPWMI_GM	= 0x20008,
1466e9b8992SJorge Lopez };
1476e9b8992SJorge Lopez 
1486e9b8992SJorge Lopez enum hp_wmi_hardware_mask {
1496e9b8992SJorge Lopez 	HPWMI_DOCK_MASK		= 0x01,
1506e9b8992SJorge Lopez 	HPWMI_TABLET_MASK	= 0x04,
1516e9b8992SJorge Lopez };
1526e9b8992SJorge Lopez 
1536e9b8992SJorge Lopez struct bios_return {
1546e9b8992SJorge Lopez 	u32 sigpass;
1556e9b8992SJorge Lopez 	u32 return_code;
1566e9b8992SJorge Lopez };
1576e9b8992SJorge Lopez 
1586e9b8992SJorge Lopez enum hp_return_value {
1596e9b8992SJorge Lopez 	HPWMI_RET_WRONG_SIGNATURE	= 0x02,
1606e9b8992SJorge Lopez 	HPWMI_RET_UNKNOWN_COMMAND	= 0x03,
1616e9b8992SJorge Lopez 	HPWMI_RET_UNKNOWN_CMDTYPE	= 0x04,
1626e9b8992SJorge Lopez 	HPWMI_RET_INVALID_PARAMETERS	= 0x05,
1636e9b8992SJorge Lopez };
1646e9b8992SJorge Lopez 
1656e9b8992SJorge Lopez enum hp_wireless2_bits {
1666e9b8992SJorge Lopez 	HPWMI_POWER_STATE	= 0x01,
1676e9b8992SJorge Lopez 	HPWMI_POWER_SOFT	= 0x02,
1686e9b8992SJorge Lopez 	HPWMI_POWER_BIOS	= 0x04,
1696e9b8992SJorge Lopez 	HPWMI_POWER_HARD	= 0x08,
1706e9b8992SJorge Lopez 	HPWMI_POWER_FW_OR_HW	= HPWMI_POWER_BIOS | HPWMI_POWER_HARD,
1716e9b8992SJorge Lopez };
1726e9b8992SJorge Lopez 
1736e9b8992SJorge Lopez enum hp_thermal_profile_omen_v0 {
1746e9b8992SJorge Lopez 	HP_OMEN_V0_THERMAL_PROFILE_DEFAULT     = 0x00,
1756e9b8992SJorge Lopez 	HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE = 0x01,
1766e9b8992SJorge Lopez 	HP_OMEN_V0_THERMAL_PROFILE_COOL        = 0x02,
1776e9b8992SJorge Lopez };
1786e9b8992SJorge Lopez 
1796e9b8992SJorge Lopez enum hp_thermal_profile_omen_v1 {
1806e9b8992SJorge Lopez 	HP_OMEN_V1_THERMAL_PROFILE_DEFAULT	= 0x30,
1816e9b8992SJorge Lopez 	HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE	= 0x31,
1826e9b8992SJorge Lopez 	HP_OMEN_V1_THERMAL_PROFILE_COOL		= 0x50,
1836e9b8992SJorge Lopez };
1846e9b8992SJorge Lopez 
1852515e542SSungHwan Jung enum hp_thermal_profile_victus {
1862515e542SSungHwan Jung 	HP_VICTUS_THERMAL_PROFILE_DEFAULT		= 0x00,
1872515e542SSungHwan Jung 	HP_VICTUS_THERMAL_PROFILE_PERFORMANCE		= 0x01,
1882515e542SSungHwan Jung 	HP_VICTUS_THERMAL_PROFILE_QUIET			= 0x03,
1892515e542SSungHwan Jung };
1902515e542SSungHwan Jung 
1916e9b8992SJorge Lopez enum hp_thermal_profile {
1926e9b8992SJorge Lopez 	HP_THERMAL_PROFILE_PERFORMANCE	= 0x00,
1936e9b8992SJorge Lopez 	HP_THERMAL_PROFILE_DEFAULT		= 0x01,
1946e9b8992SJorge Lopez 	HP_THERMAL_PROFILE_COOL			= 0x02,
1956e9b8992SJorge Lopez 	HP_THERMAL_PROFILE_QUIET		= 0x03,
1966e9b8992SJorge Lopez };
1976e9b8992SJorge Lopez 
1986e9b8992SJorge Lopez #define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW)
1996e9b8992SJorge Lopez #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
2006e9b8992SJorge Lopez 
2016e9b8992SJorge Lopez struct bios_rfkill2_device_state {
2026e9b8992SJorge Lopez 	u8 radio_type;
2036e9b8992SJorge Lopez 	u8 bus_type;
2046e9b8992SJorge Lopez 	u16 vendor_id;
2056e9b8992SJorge Lopez 	u16 product_id;
2066e9b8992SJorge Lopez 	u16 subsys_vendor_id;
2076e9b8992SJorge Lopez 	u16 subsys_product_id;
2086e9b8992SJorge Lopez 	u8 rfkill_id;
2096e9b8992SJorge Lopez 	u8 power;
2106e9b8992SJorge Lopez 	u8 unknown[4];
2116e9b8992SJorge Lopez };
2126e9b8992SJorge Lopez 
2136e9b8992SJorge Lopez /* 7 devices fit into the 128 byte buffer */
2146e9b8992SJorge Lopez #define HPWMI_MAX_RFKILL2_DEVICES	7
2156e9b8992SJorge Lopez 
2166e9b8992SJorge Lopez struct bios_rfkill2_state {
2176e9b8992SJorge Lopez 	u8 unknown[7];
2186e9b8992SJorge Lopez 	u8 count;
2196e9b8992SJorge Lopez 	u8 pad[8];
2206e9b8992SJorge Lopez 	struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
2216e9b8992SJorge Lopez };
2226e9b8992SJorge Lopez 
2236e9b8992SJorge Lopez static const struct key_entry hp_wmi_keymap[] = {
2246e9b8992SJorge Lopez 	{ KE_KEY, 0x02,    { KEY_BRIGHTNESSUP } },
2256e9b8992SJorge Lopez 	{ KE_KEY, 0x03,    { KEY_BRIGHTNESSDOWN } },
226decab282SFae 	{ KE_KEY, 0x270,   { KEY_MICMUTE } },
2276e9b8992SJorge Lopez 	{ KE_KEY, 0x20e6,  { KEY_PROG1 } },
2286e9b8992SJorge Lopez 	{ KE_KEY, 0x20e8,  { KEY_MEDIA } },
2296e9b8992SJorge Lopez 	{ KE_KEY, 0x2142,  { KEY_MEDIA } },
2306e9b8992SJorge Lopez 	{ KE_KEY, 0x213b,  { KEY_INFO } },
2316e9b8992SJorge Lopez 	{ KE_KEY, 0x2169,  { KEY_ROTATE_DISPLAY } },
2326e9b8992SJorge Lopez 	{ KE_KEY, 0x216a,  { KEY_SETUP } },
2338071b210SRishit Bansal 	{ KE_IGNORE, 0x21a4,  }, /* Win Lock On */
2348071b210SRishit Bansal 	{ KE_IGNORE, 0x121a4, }, /* Win Lock Off */
2353ee5447bSRishit Bansal 	{ KE_KEY, 0x21a5,  { KEY_PROG2 } }, /* HP Omen Key */
2363ee5447bSRishit Bansal 	{ KE_KEY, 0x21a7,  { KEY_FN_ESC } },
237f4a31a42SJonathan Singer 	{ KE_KEY, 0x21a8,  { KEY_PROG2 } }, /* HP Envy x360 programmable key */
2386e9b8992SJorge Lopez 	{ KE_KEY, 0x21a9,  { KEY_TOUCHPAD_OFF } },
2396e9b8992SJorge Lopez 	{ KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } },
2406e9b8992SJorge Lopez 	{ KE_KEY, 0x231b,  { KEY_HELP } },
2416e9b8992SJorge Lopez 	{ KE_END, 0 }
2426e9b8992SJorge Lopez };
2436e9b8992SJorge Lopez 
2446e9b8992SJorge Lopez static struct input_dev *hp_wmi_input_dev;
245604915f1SJonathan Singer static struct input_dev *camera_shutter_input_dev;
2466e9b8992SJorge Lopez static struct platform_device *hp_wmi_platform_dev;
2476e9b8992SJorge Lopez static struct platform_profile_handler platform_profile_handler;
2486e9b8992SJorge Lopez static bool platform_profile_support;
2496e9b8992SJorge Lopez static bool zero_insize_support;
2506e9b8992SJorge Lopez 
2516e9b8992SJorge Lopez static struct rfkill *wifi_rfkill;
2526e9b8992SJorge Lopez static struct rfkill *bluetooth_rfkill;
2536e9b8992SJorge Lopez static struct rfkill *wwan_rfkill;
2546e9b8992SJorge Lopez 
2556e9b8992SJorge Lopez struct rfkill2_device {
2566e9b8992SJorge Lopez 	u8 id;
2576e9b8992SJorge Lopez 	int num;
2586e9b8992SJorge Lopez 	struct rfkill *rfkill;
2596e9b8992SJorge Lopez };
2606e9b8992SJorge Lopez 
2616e9b8992SJorge Lopez static int rfkill2_count;
2626e9b8992SJorge Lopez static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
2636e9b8992SJorge Lopez 
2646e9b8992SJorge Lopez /*
2656e9b8992SJorge Lopez  * Chassis Types values were obtained from SMBIOS reference
2666e9b8992SJorge Lopez  * specification version 3.00. A complete list of system enclosures
2676e9b8992SJorge Lopez  * and chassis types is available on Table 17.
2686e9b8992SJorge Lopez  */
2696e9b8992SJorge Lopez static const char * const tablet_chassis_types[] = {
2706e9b8992SJorge Lopez 	"30", /* Tablet*/
2716e9b8992SJorge Lopez 	"31", /* Convertible */
2726e9b8992SJorge Lopez 	"32"  /* Detachable */
2736e9b8992SJorge Lopez };
2746e9b8992SJorge Lopez 
2756e9b8992SJorge Lopez #define DEVICE_MODE_TABLET	0x06
2766e9b8992SJorge Lopez 
2776e9b8992SJorge Lopez /* map output size to the corresponding WMI method id */
encode_outsize_for_pvsz(int outsize)2786e9b8992SJorge Lopez static inline int encode_outsize_for_pvsz(int outsize)
2796e9b8992SJorge Lopez {
2806e9b8992SJorge Lopez 	if (outsize > 4096)
2816e9b8992SJorge Lopez 		return -EINVAL;
2826e9b8992SJorge Lopez 	if (outsize > 1024)
2836e9b8992SJorge Lopez 		return 5;
2846e9b8992SJorge Lopez 	if (outsize > 128)
2856e9b8992SJorge Lopez 		return 4;
2866e9b8992SJorge Lopez 	if (outsize > 4)
2876e9b8992SJorge Lopez 		return 3;
2886e9b8992SJorge Lopez 	if (outsize > 0)
2896e9b8992SJorge Lopez 		return 2;
2906e9b8992SJorge Lopez 	return 1;
2916e9b8992SJorge Lopez }
2926e9b8992SJorge Lopez 
2936e9b8992SJorge Lopez /*
2946e9b8992SJorge Lopez  * hp_wmi_perform_query
2956e9b8992SJorge Lopez  *
2966e9b8992SJorge Lopez  * query:	The commandtype (enum hp_wmi_commandtype)
2976e9b8992SJorge Lopez  * write:	The command (enum hp_wmi_command)
2986e9b8992SJorge Lopez  * buffer:	Buffer used as input and/or output
2996e9b8992SJorge Lopez  * insize:	Size of input buffer
3006e9b8992SJorge Lopez  * outsize:	Size of output buffer
3016e9b8992SJorge Lopez  *
3026e9b8992SJorge Lopez  * returns zero on success
3036e9b8992SJorge Lopez  *         an HP WMI query specific error code (which is positive)
3046e9b8992SJorge Lopez  *         -EINVAL if the query was not successful at all
3056e9b8992SJorge Lopez  *         -EINVAL if the output buffer size exceeds buffersize
3066e9b8992SJorge Lopez  *
3076e9b8992SJorge Lopez  * Note: The buffersize must at least be the maximum of the input and output
3086e9b8992SJorge Lopez  *       size. E.g. Battery info query is defined to have 1 byte input
3096e9b8992SJorge Lopez  *       and 128 byte output. The caller would do:
3106e9b8992SJorge Lopez  *       buffer = kzalloc(128, GFP_KERNEL);
3116e9b8992SJorge Lopez  *       ret = hp_wmi_perform_query(HPWMI_BATTERY_QUERY, HPWMI_READ, buffer, 1, 128)
3126e9b8992SJorge Lopez  */
hp_wmi_perform_query(int query,enum hp_wmi_command command,void * buffer,int insize,int outsize)3136e9b8992SJorge Lopez static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
3146e9b8992SJorge Lopez 				void *buffer, int insize, int outsize)
3156e9b8992SJorge Lopez {
3166e9b8992SJorge Lopez 	struct acpi_buffer input, output = { ACPI_ALLOCATE_BUFFER, NULL };
3176e9b8992SJorge Lopez 	struct bios_return *bios_return;
3186e9b8992SJorge Lopez 	union acpi_object *obj = NULL;
3196e9b8992SJorge Lopez 	struct bios_args *args = NULL;
3206e9b8992SJorge Lopez 	int mid, actual_insize, actual_outsize;
3216e9b8992SJorge Lopez 	size_t bios_args_size;
3226e9b8992SJorge Lopez 	int ret;
3236e9b8992SJorge Lopez 
3246e9b8992SJorge Lopez 	mid = encode_outsize_for_pvsz(outsize);
3256e9b8992SJorge Lopez 	if (WARN_ON(mid < 0))
3266e9b8992SJorge Lopez 		return mid;
3276e9b8992SJorge Lopez 
3286e9b8992SJorge Lopez 	actual_insize = max(insize, 128);
3296e9b8992SJorge Lopez 	bios_args_size = struct_size(args, data, actual_insize);
3306e9b8992SJorge Lopez 	args = kmalloc(bios_args_size, GFP_KERNEL);
3316e9b8992SJorge Lopez 	if (!args)
3326e9b8992SJorge Lopez 		return -ENOMEM;
3336e9b8992SJorge Lopez 
3346e9b8992SJorge Lopez 	input.length = bios_args_size;
3356e9b8992SJorge Lopez 	input.pointer = args;
3366e9b8992SJorge Lopez 
3376e9b8992SJorge Lopez 	args->signature = 0x55434553;
3386e9b8992SJorge Lopez 	args->command = command;
3396e9b8992SJorge Lopez 	args->commandtype = query;
3406e9b8992SJorge Lopez 	args->datasize = insize;
3416e9b8992SJorge Lopez 	memcpy(args->data, buffer, flex_array_size(args, data, insize));
3426e9b8992SJorge Lopez 
3436e9b8992SJorge Lopez 	ret = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output);
3446e9b8992SJorge Lopez 	if (ret)
3456e9b8992SJorge Lopez 		goto out_free;
3466e9b8992SJorge Lopez 
3476e9b8992SJorge Lopez 	obj = output.pointer;
3486e9b8992SJorge Lopez 	if (!obj) {
3496e9b8992SJorge Lopez 		ret = -EINVAL;
3506e9b8992SJorge Lopez 		goto out_free;
3516e9b8992SJorge Lopez 	}
3526e9b8992SJorge Lopez 
3536e9b8992SJorge Lopez 	if (obj->type != ACPI_TYPE_BUFFER) {
3546e9b8992SJorge Lopez 		pr_warn("query 0x%x returned an invalid object 0x%x\n", query, ret);
3556e9b8992SJorge Lopez 		ret = -EINVAL;
3566e9b8992SJorge Lopez 		goto out_free;
3576e9b8992SJorge Lopez 	}
3586e9b8992SJorge Lopez 
3596e9b8992SJorge Lopez 	bios_return = (struct bios_return *)obj->buffer.pointer;
3606e9b8992SJorge Lopez 	ret = bios_return->return_code;
3616e9b8992SJorge Lopez 
3626e9b8992SJorge Lopez 	if (ret) {
3636e9b8992SJorge Lopez 		if (ret != HPWMI_RET_UNKNOWN_COMMAND &&
3646e9b8992SJorge Lopez 		    ret != HPWMI_RET_UNKNOWN_CMDTYPE)
3656e9b8992SJorge Lopez 			pr_warn("query 0x%x returned error 0x%x\n", query, ret);
3666e9b8992SJorge Lopez 		goto out_free;
3676e9b8992SJorge Lopez 	}
3686e9b8992SJorge Lopez 
3696e9b8992SJorge Lopez 	/* Ignore output data of zero size */
3706e9b8992SJorge Lopez 	if (!outsize)
3716e9b8992SJorge Lopez 		goto out_free;
3726e9b8992SJorge Lopez 
3736e9b8992SJorge Lopez 	actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
3746e9b8992SJorge Lopez 	memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
3756e9b8992SJorge Lopez 	memset(buffer + actual_outsize, 0, outsize - actual_outsize);
3766e9b8992SJorge Lopez 
3776e9b8992SJorge Lopez out_free:
3786e9b8992SJorge Lopez 	kfree(obj);
3796e9b8992SJorge Lopez 	kfree(args);
3806e9b8992SJorge Lopez 	return ret;
3816e9b8992SJorge Lopez }
3826e9b8992SJorge Lopez 
hp_wmi_get_fan_speed(int fan)3836e9b8992SJorge Lopez static int hp_wmi_get_fan_speed(int fan)
3846e9b8992SJorge Lopez {
3856e9b8992SJorge Lopez 	u8 fsh, fsl;
3866e9b8992SJorge Lopez 	char fan_data[4] = { fan, 0, 0, 0 };
3876e9b8992SJorge Lopez 
3886e9b8992SJorge Lopez 	int ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_GET_QUERY, HPWMI_GM,
3896e9b8992SJorge Lopez 				       &fan_data, sizeof(char),
3906e9b8992SJorge Lopez 				       sizeof(fan_data));
3916e9b8992SJorge Lopez 
3926e9b8992SJorge Lopez 	if (ret != 0)
3936e9b8992SJorge Lopez 		return -EINVAL;
3946e9b8992SJorge Lopez 
3956e9b8992SJorge Lopez 	fsh = fan_data[2];
3966e9b8992SJorge Lopez 	fsl = fan_data[3];
3976e9b8992SJorge Lopez 
3986e9b8992SJorge Lopez 	return (fsh << 8) | fsl;
3996e9b8992SJorge Lopez }
4006e9b8992SJorge Lopez 
hp_wmi_read_int(int query)4016e9b8992SJorge Lopez static int hp_wmi_read_int(int query)
4026e9b8992SJorge Lopez {
4036e9b8992SJorge Lopez 	int val = 0, ret;
4046e9b8992SJorge Lopez 
4056e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(query, HPWMI_READ, &val,
4066e9b8992SJorge Lopez 				   zero_if_sup(val), sizeof(val));
4076e9b8992SJorge Lopez 
4086e9b8992SJorge Lopez 	if (ret)
4096e9b8992SJorge Lopez 		return ret < 0 ? ret : -EINVAL;
4106e9b8992SJorge Lopez 
4116e9b8992SJorge Lopez 	return val;
4126e9b8992SJorge Lopez }
4136e9b8992SJorge Lopez 
hp_wmi_get_dock_state(void)4146e9b8992SJorge Lopez static int hp_wmi_get_dock_state(void)
4156e9b8992SJorge Lopez {
4166e9b8992SJorge Lopez 	int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY);
4176e9b8992SJorge Lopez 
4186e9b8992SJorge Lopez 	if (state < 0)
4196e9b8992SJorge Lopez 		return state;
4206e9b8992SJorge Lopez 
4216e9b8992SJorge Lopez 	return !!(state & HPWMI_DOCK_MASK);
4226e9b8992SJorge Lopez }
4236e9b8992SJorge Lopez 
hp_wmi_get_tablet_mode(void)4246e9b8992SJorge Lopez static int hp_wmi_get_tablet_mode(void)
4256e9b8992SJorge Lopez {
4266e9b8992SJorge Lopez 	char system_device_mode[4] = { 0 };
4276e9b8992SJorge Lopez 	const char *chassis_type;
4286e9b8992SJorge Lopez 	bool tablet_found;
4296e9b8992SJorge Lopez 	int ret;
4306e9b8992SJorge Lopez 
4316e9b8992SJorge Lopez 	chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
4326e9b8992SJorge Lopez 	if (!chassis_type)
4336e9b8992SJorge Lopez 		return -ENODEV;
4346e9b8992SJorge Lopez 
4356e9b8992SJorge Lopez 	tablet_found = match_string(tablet_chassis_types,
4366e9b8992SJorge Lopez 				    ARRAY_SIZE(tablet_chassis_types),
4376e9b8992SJorge Lopez 				    chassis_type) >= 0;
4386e9b8992SJorge Lopez 	if (!tablet_found)
4396e9b8992SJorge Lopez 		return -ENODEV;
4406e9b8992SJorge Lopez 
4416e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(HPWMI_SYSTEM_DEVICE_MODE, HPWMI_READ,
4426e9b8992SJorge Lopez 				   system_device_mode, zero_if_sup(system_device_mode),
4436e9b8992SJorge Lopez 				   sizeof(system_device_mode));
4446e9b8992SJorge Lopez 	if (ret < 0)
4456e9b8992SJorge Lopez 		return ret;
4466e9b8992SJorge Lopez 
4476e9b8992SJorge Lopez 	return system_device_mode[0] == DEVICE_MODE_TABLET;
4486e9b8992SJorge Lopez }
4496e9b8992SJorge Lopez 
omen_thermal_profile_set(int mode)4506e9b8992SJorge Lopez static int omen_thermal_profile_set(int mode)
4516e9b8992SJorge Lopez {
4526e9b8992SJorge Lopez 	char buffer[2] = {0, mode};
4536e9b8992SJorge Lopez 	int ret;
4546e9b8992SJorge Lopez 
4556e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(HPWMI_SET_PERFORMANCE_MODE, HPWMI_GM,
4566e9b8992SJorge Lopez 				   &buffer, sizeof(buffer), 0);
4576e9b8992SJorge Lopez 
4586e9b8992SJorge Lopez 	if (ret)
4596e9b8992SJorge Lopez 		return ret < 0 ? ret : -EINVAL;
4606e9b8992SJorge Lopez 
4616e9b8992SJorge Lopez 	return mode;
4626e9b8992SJorge Lopez }
4636e9b8992SJorge Lopez 
is_omen_thermal_profile(void)4646e9b8992SJorge Lopez static bool is_omen_thermal_profile(void)
4656e9b8992SJorge Lopez {
4666e9b8992SJorge Lopez 	const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
4676e9b8992SJorge Lopez 
4686e9b8992SJorge Lopez 	if (!board_name)
4696e9b8992SJorge Lopez 		return false;
4706e9b8992SJorge Lopez 
4716e9b8992SJorge Lopez 	return match_string(omen_thermal_profile_boards,
4726e9b8992SJorge Lopez 			    ARRAY_SIZE(omen_thermal_profile_boards),
4736e9b8992SJorge Lopez 			    board_name) >= 0;
4746e9b8992SJorge Lopez }
4756e9b8992SJorge Lopez 
omen_get_thermal_policy_version(void)4766e9b8992SJorge Lopez static int omen_get_thermal_policy_version(void)
4776e9b8992SJorge Lopez {
4786e9b8992SJorge Lopez 	unsigned char buffer[8] = { 0 };
4796e9b8992SJorge Lopez 	int ret;
4806e9b8992SJorge Lopez 
4816e9b8992SJorge Lopez 	const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
4826e9b8992SJorge Lopez 
4836e9b8992SJorge Lopez 	if (board_name) {
4846e9b8992SJorge Lopez 		int matches = match_string(omen_thermal_profile_force_v0_boards,
4856e9b8992SJorge Lopez 			ARRAY_SIZE(omen_thermal_profile_force_v0_boards),
4866e9b8992SJorge Lopez 			board_name);
4876e9b8992SJorge Lopez 		if (matches >= 0)
4886e9b8992SJorge Lopez 			return 0;
4896e9b8992SJorge Lopez 	}
4906e9b8992SJorge Lopez 
4916e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(HPWMI_GET_SYSTEM_DESIGN_DATA, HPWMI_GM,
4926e9b8992SJorge Lopez 				   &buffer, sizeof(buffer), sizeof(buffer));
4936e9b8992SJorge Lopez 
4946e9b8992SJorge Lopez 	if (ret)
4956e9b8992SJorge Lopez 		return ret < 0 ? ret : -EINVAL;
4966e9b8992SJorge Lopez 
4976e9b8992SJorge Lopez 	return buffer[3];
4986e9b8992SJorge Lopez }
4996e9b8992SJorge Lopez 
omen_thermal_profile_get(void)5006e9b8992SJorge Lopez static int omen_thermal_profile_get(void)
5016e9b8992SJorge Lopez {
5026e9b8992SJorge Lopez 	u8 data;
5036e9b8992SJorge Lopez 
5046e9b8992SJorge Lopez 	int ret = ec_read(HP_OMEN_EC_THERMAL_PROFILE_OFFSET, &data);
5056e9b8992SJorge Lopez 
5066e9b8992SJorge Lopez 	if (ret)
5076e9b8992SJorge Lopez 		return ret;
5086e9b8992SJorge Lopez 
5096e9b8992SJorge Lopez 	return data;
5106e9b8992SJorge Lopez }
5116e9b8992SJorge Lopez 
hp_wmi_fan_speed_max_set(int enabled)5126e9b8992SJorge Lopez static int hp_wmi_fan_speed_max_set(int enabled)
5136e9b8992SJorge Lopez {
5146e9b8992SJorge Lopez 	int ret;
5156e9b8992SJorge Lopez 
5166e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_SET_QUERY, HPWMI_GM,
5176e9b8992SJorge Lopez 				   &enabled, sizeof(enabled), 0);
5186e9b8992SJorge Lopez 
5196e9b8992SJorge Lopez 	if (ret)
5206e9b8992SJorge Lopez 		return ret < 0 ? ret : -EINVAL;
5216e9b8992SJorge Lopez 
5226e9b8992SJorge Lopez 	return enabled;
5236e9b8992SJorge Lopez }
5246e9b8992SJorge Lopez 
hp_wmi_fan_speed_max_get(void)5256e9b8992SJorge Lopez static int hp_wmi_fan_speed_max_get(void)
5266e9b8992SJorge Lopez {
5276e9b8992SJorge Lopez 	int val = 0, ret;
5286e9b8992SJorge Lopez 
5296e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_GET_QUERY, HPWMI_GM,
5306e9b8992SJorge Lopez 				   &val, zero_if_sup(val), sizeof(val));
5316e9b8992SJorge Lopez 
5326e9b8992SJorge Lopez 	if (ret)
5336e9b8992SJorge Lopez 		return ret < 0 ? ret : -EINVAL;
5346e9b8992SJorge Lopez 
5356e9b8992SJorge Lopez 	return val;
5366e9b8992SJorge Lopez }
5376e9b8992SJorge Lopez 
hp_wmi_bios_2008_later(void)5386e9b8992SJorge Lopez static int __init hp_wmi_bios_2008_later(void)
5396e9b8992SJorge Lopez {
5406e9b8992SJorge Lopez 	int state = 0;
5416e9b8992SJorge Lopez 	int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, HPWMI_READ, &state,
5426e9b8992SJorge Lopez 				       zero_if_sup(state), sizeof(state));
5436e9b8992SJorge Lopez 	if (!ret)
5446e9b8992SJorge Lopez 		return 1;
5456e9b8992SJorge Lopez 
5466e9b8992SJorge Lopez 	return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
5476e9b8992SJorge Lopez }
5486e9b8992SJorge Lopez 
hp_wmi_bios_2009_later(void)5496e9b8992SJorge Lopez static int __init hp_wmi_bios_2009_later(void)
5506e9b8992SJorge Lopez {
5516e9b8992SJorge Lopez 	u8 state[128];
5526e9b8992SJorge Lopez 	int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state,
5536e9b8992SJorge Lopez 				       zero_if_sup(state), sizeof(state));
5546e9b8992SJorge Lopez 	if (!ret)
5556e9b8992SJorge Lopez 		return 1;
5566e9b8992SJorge Lopez 
5576e9b8992SJorge Lopez 	return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
5586e9b8992SJorge Lopez }
5596e9b8992SJorge Lopez 
hp_wmi_enable_hotkeys(void)5606e9b8992SJorge Lopez static int __init hp_wmi_enable_hotkeys(void)
5616e9b8992SJorge Lopez {
5626e9b8992SJorge Lopez 	int value = 0x6e;
5636e9b8992SJorge Lopez 	int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, HPWMI_WRITE, &value,
5646e9b8992SJorge Lopez 				       sizeof(value), 0);
5656e9b8992SJorge Lopez 
5666e9b8992SJorge Lopez 	return ret <= 0 ? ret : -EINVAL;
5676e9b8992SJorge Lopez }
5686e9b8992SJorge Lopez 
hp_wmi_set_block(void * data,bool blocked)5696e9b8992SJorge Lopez static int hp_wmi_set_block(void *data, bool blocked)
5706e9b8992SJorge Lopez {
571ce95010eSHans de Goede 	enum hp_wmi_radio r = (long)data;
5726e9b8992SJorge Lopez 	int query = BIT(r + 8) | ((!blocked) << r);
5736e9b8992SJorge Lopez 	int ret;
5746e9b8992SJorge Lopez 
5756e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE,
5766e9b8992SJorge Lopez 				   &query, sizeof(query), 0);
5776e9b8992SJorge Lopez 
5786e9b8992SJorge Lopez 	return ret <= 0 ? ret : -EINVAL;
5796e9b8992SJorge Lopez }
5806e9b8992SJorge Lopez 
5816e9b8992SJorge Lopez static const struct rfkill_ops hp_wmi_rfkill_ops = {
5826e9b8992SJorge Lopez 	.set_block = hp_wmi_set_block,
5836e9b8992SJorge Lopez };
5846e9b8992SJorge Lopez 
hp_wmi_get_sw_state(enum hp_wmi_radio r)5856e9b8992SJorge Lopez static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
5866e9b8992SJorge Lopez {
5876e9b8992SJorge Lopez 	int mask = 0x200 << (r * 8);
5886e9b8992SJorge Lopez 
5896e9b8992SJorge Lopez 	int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
5906e9b8992SJorge Lopez 
5916e9b8992SJorge Lopez 	/* TBD: Pass error */
5926e9b8992SJorge Lopez 	WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");
5936e9b8992SJorge Lopez 
5946e9b8992SJorge Lopez 	return !(wireless & mask);
5956e9b8992SJorge Lopez }
5966e9b8992SJorge Lopez 
hp_wmi_get_hw_state(enum hp_wmi_radio r)5976e9b8992SJorge Lopez static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
5986e9b8992SJorge Lopez {
5996e9b8992SJorge Lopez 	int mask = 0x800 << (r * 8);
6006e9b8992SJorge Lopez 
6016e9b8992SJorge Lopez 	int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
6026e9b8992SJorge Lopez 
6036e9b8992SJorge Lopez 	/* TBD: Pass error */
6046e9b8992SJorge Lopez 	WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");
6056e9b8992SJorge Lopez 
6066e9b8992SJorge Lopez 	return !(wireless & mask);
6076e9b8992SJorge Lopez }
6086e9b8992SJorge Lopez 
hp_wmi_rfkill2_set_block(void * data,bool blocked)6096e9b8992SJorge Lopez static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
6106e9b8992SJorge Lopez {
6116e9b8992SJorge Lopez 	int rfkill_id = (int)(long)data;
6126e9b8992SJorge Lopez 	char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
6136e9b8992SJorge Lopez 	int ret;
6146e9b8992SJorge Lopez 
6156e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_WRITE,
6166e9b8992SJorge Lopez 				   buffer, sizeof(buffer), 0);
6176e9b8992SJorge Lopez 
6186e9b8992SJorge Lopez 	return ret <= 0 ? ret : -EINVAL;
6196e9b8992SJorge Lopez }
6206e9b8992SJorge Lopez 
6216e9b8992SJorge Lopez static const struct rfkill_ops hp_wmi_rfkill2_ops = {
6226e9b8992SJorge Lopez 	.set_block = hp_wmi_rfkill2_set_block,
6236e9b8992SJorge Lopez };
6246e9b8992SJorge Lopez 
hp_wmi_rfkill2_refresh(void)6256e9b8992SJorge Lopez static int hp_wmi_rfkill2_refresh(void)
6266e9b8992SJorge Lopez {
6276e9b8992SJorge Lopez 	struct bios_rfkill2_state state;
6286e9b8992SJorge Lopez 	int err, i;
6296e9b8992SJorge Lopez 
6306e9b8992SJorge Lopez 	err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
6316e9b8992SJorge Lopez 				   zero_if_sup(state), sizeof(state));
6326e9b8992SJorge Lopez 	if (err)
6336e9b8992SJorge Lopez 		return err;
6346e9b8992SJorge Lopez 
6356e9b8992SJorge Lopez 	for (i = 0; i < rfkill2_count; i++) {
6366e9b8992SJorge Lopez 		int num = rfkill2[i].num;
6376e9b8992SJorge Lopez 		struct bios_rfkill2_device_state *devstate;
6386e9b8992SJorge Lopez 
6396e9b8992SJorge Lopez 		devstate = &state.device[num];
6406e9b8992SJorge Lopez 
6416e9b8992SJorge Lopez 		if (num >= state.count ||
6426e9b8992SJorge Lopez 		    devstate->rfkill_id != rfkill2[i].id) {
6436e9b8992SJorge Lopez 			pr_warn("power configuration of the wireless devices unexpectedly changed\n");
6446e9b8992SJorge Lopez 			continue;
6456e9b8992SJorge Lopez 		}
6466e9b8992SJorge Lopez 
6476e9b8992SJorge Lopez 		rfkill_set_states(rfkill2[i].rfkill,
6486e9b8992SJorge Lopez 				  IS_SWBLOCKED(devstate->power),
6496e9b8992SJorge Lopez 				  IS_HWBLOCKED(devstate->power));
6506e9b8992SJorge Lopez 	}
6516e9b8992SJorge Lopez 
6526e9b8992SJorge Lopez 	return 0;
6536e9b8992SJorge Lopez }
6546e9b8992SJorge Lopez 
display_show(struct device * dev,struct device_attribute * attr,char * buf)6556e9b8992SJorge Lopez static ssize_t display_show(struct device *dev, struct device_attribute *attr,
6566e9b8992SJorge Lopez 			    char *buf)
6576e9b8992SJorge Lopez {
6586e9b8992SJorge Lopez 	int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY);
6596e9b8992SJorge Lopez 
6606e9b8992SJorge Lopez 	if (value < 0)
6616e9b8992SJorge Lopez 		return value;
6626e9b8992SJorge Lopez 	return sprintf(buf, "%d\n", value);
6636e9b8992SJorge Lopez }
6646e9b8992SJorge Lopez 
hddtemp_show(struct device * dev,struct device_attribute * attr,char * buf)6656e9b8992SJorge Lopez static ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr,
6666e9b8992SJorge Lopez 			    char *buf)
6676e9b8992SJorge Lopez {
6686e9b8992SJorge Lopez 	int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY);
6696e9b8992SJorge Lopez 
6706e9b8992SJorge Lopez 	if (value < 0)
6716e9b8992SJorge Lopez 		return value;
6726e9b8992SJorge Lopez 	return sprintf(buf, "%d\n", value);
6736e9b8992SJorge Lopez }
6746e9b8992SJorge Lopez 
als_show(struct device * dev,struct device_attribute * attr,char * buf)6756e9b8992SJorge Lopez static ssize_t als_show(struct device *dev, struct device_attribute *attr,
6766e9b8992SJorge Lopez 			char *buf)
6776e9b8992SJorge Lopez {
6786e9b8992SJorge Lopez 	int value = hp_wmi_read_int(HPWMI_ALS_QUERY);
6796e9b8992SJorge Lopez 
6806e9b8992SJorge Lopez 	if (value < 0)
6816e9b8992SJorge Lopez 		return value;
6826e9b8992SJorge Lopez 	return sprintf(buf, "%d\n", value);
6836e9b8992SJorge Lopez }
6846e9b8992SJorge Lopez 
dock_show(struct device * dev,struct device_attribute * attr,char * buf)6856e9b8992SJorge Lopez static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
6866e9b8992SJorge Lopez 			 char *buf)
6876e9b8992SJorge Lopez {
6886e9b8992SJorge Lopez 	int value = hp_wmi_get_dock_state();
6896e9b8992SJorge Lopez 
6906e9b8992SJorge Lopez 	if (value < 0)
6916e9b8992SJorge Lopez 		return value;
6926e9b8992SJorge Lopez 	return sprintf(buf, "%d\n", value);
6936e9b8992SJorge Lopez }
6946e9b8992SJorge Lopez 
tablet_show(struct device * dev,struct device_attribute * attr,char * buf)6956e9b8992SJorge Lopez static ssize_t tablet_show(struct device *dev, struct device_attribute *attr,
6966e9b8992SJorge Lopez 			   char *buf)
6976e9b8992SJorge Lopez {
6986e9b8992SJorge Lopez 	int value = hp_wmi_get_tablet_mode();
6996e9b8992SJorge Lopez 
7006e9b8992SJorge Lopez 	if (value < 0)
7016e9b8992SJorge Lopez 		return value;
7026e9b8992SJorge Lopez 	return sprintf(buf, "%d\n", value);
7036e9b8992SJorge Lopez }
7046e9b8992SJorge Lopez 
postcode_show(struct device * dev,struct device_attribute * attr,char * buf)7056e9b8992SJorge Lopez static ssize_t postcode_show(struct device *dev, struct device_attribute *attr,
7066e9b8992SJorge Lopez 			     char *buf)
7076e9b8992SJorge Lopez {
7086e9b8992SJorge Lopez 	/* Get the POST error code of previous boot failure. */
7096e9b8992SJorge Lopez 	int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY);
7106e9b8992SJorge Lopez 
7116e9b8992SJorge Lopez 	if (value < 0)
7126e9b8992SJorge Lopez 		return value;
7136e9b8992SJorge Lopez 	return sprintf(buf, "0x%x\n", value);
7146e9b8992SJorge Lopez }
7156e9b8992SJorge Lopez 
als_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)7166e9b8992SJorge Lopez static ssize_t als_store(struct device *dev, struct device_attribute *attr,
7176e9b8992SJorge Lopez 			 const char *buf, size_t count)
7186e9b8992SJorge Lopez {
7196e9b8992SJorge Lopez 	u32 tmp;
7206e9b8992SJorge Lopez 	int ret;
7216e9b8992SJorge Lopez 
7226e9b8992SJorge Lopez 	ret = kstrtou32(buf, 10, &tmp);
7236e9b8992SJorge Lopez 	if (ret)
7246e9b8992SJorge Lopez 		return ret;
7256e9b8992SJorge Lopez 
7266e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_WRITE, &tmp,
7276e9b8992SJorge Lopez 				       sizeof(tmp), 0);
7286e9b8992SJorge Lopez 	if (ret)
7296e9b8992SJorge Lopez 		return ret < 0 ? ret : -EINVAL;
7306e9b8992SJorge Lopez 
7316e9b8992SJorge Lopez 	return count;
7326e9b8992SJorge Lopez }
7336e9b8992SJorge Lopez 
postcode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)7346e9b8992SJorge Lopez static ssize_t postcode_store(struct device *dev, struct device_attribute *attr,
7356e9b8992SJorge Lopez 			      const char *buf, size_t count)
7366e9b8992SJorge Lopez {
7376e9b8992SJorge Lopez 	u32 tmp = 1;
7386e9b8992SJorge Lopez 	bool clear;
7396e9b8992SJorge Lopez 	int ret;
7406e9b8992SJorge Lopez 
7416e9b8992SJorge Lopez 	ret = kstrtobool(buf, &clear);
7426e9b8992SJorge Lopez 	if (ret)
7436e9b8992SJorge Lopez 		return ret;
7446e9b8992SJorge Lopez 
7456e9b8992SJorge Lopez 	if (clear == false)
7466e9b8992SJorge Lopez 		return -EINVAL;
7476e9b8992SJorge Lopez 
7486e9b8992SJorge Lopez 	/* Clear the POST error code. It is kept until cleared. */
7496e9b8992SJorge Lopez 	ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp,
7506e9b8992SJorge Lopez 				       sizeof(tmp), 0);
7516e9b8992SJorge Lopez 	if (ret)
7526e9b8992SJorge Lopez 		return ret < 0 ? ret : -EINVAL;
7536e9b8992SJorge Lopez 
7546e9b8992SJorge Lopez 	return count;
7556e9b8992SJorge Lopez }
7566e9b8992SJorge Lopez 
camera_shutter_input_setup(void)757604915f1SJonathan Singer static int camera_shutter_input_setup(void)
758604915f1SJonathan Singer {
759604915f1SJonathan Singer 	int err;
760604915f1SJonathan Singer 
761604915f1SJonathan Singer 	camera_shutter_input_dev = input_allocate_device();
762604915f1SJonathan Singer 	if (!camera_shutter_input_dev)
763604915f1SJonathan Singer 		return -ENOMEM;
764604915f1SJonathan Singer 
765604915f1SJonathan Singer 	camera_shutter_input_dev->name = "HP WMI camera shutter";
766604915f1SJonathan Singer 	camera_shutter_input_dev->phys = "wmi/input1";
767604915f1SJonathan Singer 	camera_shutter_input_dev->id.bustype = BUS_HOST;
768604915f1SJonathan Singer 
769604915f1SJonathan Singer 	__set_bit(EV_SW, camera_shutter_input_dev->evbit);
770604915f1SJonathan Singer 	__set_bit(SW_CAMERA_LENS_COVER, camera_shutter_input_dev->swbit);
771604915f1SJonathan Singer 
772604915f1SJonathan Singer 	err = input_register_device(camera_shutter_input_dev);
773604915f1SJonathan Singer 	if (err)
774604915f1SJonathan Singer 		goto err_free_dev;
775604915f1SJonathan Singer 
776604915f1SJonathan Singer 	return 0;
777604915f1SJonathan Singer 
778604915f1SJonathan Singer  err_free_dev:
779604915f1SJonathan Singer 	input_free_device(camera_shutter_input_dev);
780604915f1SJonathan Singer 	camera_shutter_input_dev = NULL;
781604915f1SJonathan Singer 	return err;
782604915f1SJonathan Singer }
783604915f1SJonathan Singer 
7846e9b8992SJorge Lopez static DEVICE_ATTR_RO(display);
7856e9b8992SJorge Lopez static DEVICE_ATTR_RO(hddtemp);
7866e9b8992SJorge Lopez static DEVICE_ATTR_RW(als);
7876e9b8992SJorge Lopez static DEVICE_ATTR_RO(dock);
7886e9b8992SJorge Lopez static DEVICE_ATTR_RO(tablet);
7896e9b8992SJorge Lopez static DEVICE_ATTR_RW(postcode);
7906e9b8992SJorge Lopez 
7916e9b8992SJorge Lopez static struct attribute *hp_wmi_attrs[] = {
7926e9b8992SJorge Lopez 	&dev_attr_display.attr,
7936e9b8992SJorge Lopez 	&dev_attr_hddtemp.attr,
7946e9b8992SJorge Lopez 	&dev_attr_als.attr,
7956e9b8992SJorge Lopez 	&dev_attr_dock.attr,
7966e9b8992SJorge Lopez 	&dev_attr_tablet.attr,
7976e9b8992SJorge Lopez 	&dev_attr_postcode.attr,
7986e9b8992SJorge Lopez 	NULL,
7996e9b8992SJorge Lopez };
8006e9b8992SJorge Lopez ATTRIBUTE_GROUPS(hp_wmi);
8016e9b8992SJorge Lopez 
hp_wmi_notify(u32 value,void * context)8026e9b8992SJorge Lopez static void hp_wmi_notify(u32 value, void *context)
8036e9b8992SJorge Lopez {
8046e9b8992SJorge Lopez 	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
8056e9b8992SJorge Lopez 	u32 event_id, event_data;
8066e9b8992SJorge Lopez 	union acpi_object *obj;
8076e9b8992SJorge Lopez 	acpi_status status;
8086e9b8992SJorge Lopez 	u32 *location;
8096e9b8992SJorge Lopez 	int key_code;
8106e9b8992SJorge Lopez 
8116e9b8992SJorge Lopez 	status = wmi_get_event_data(value, &response);
8126e9b8992SJorge Lopez 	if (status != AE_OK) {
8136e9b8992SJorge Lopez 		pr_info("bad event status 0x%x\n", status);
8146e9b8992SJorge Lopez 		return;
8156e9b8992SJorge Lopez 	}
8166e9b8992SJorge Lopez 
8176e9b8992SJorge Lopez 	obj = (union acpi_object *)response.pointer;
8186e9b8992SJorge Lopez 
8196e9b8992SJorge Lopez 	if (!obj)
8206e9b8992SJorge Lopez 		return;
8216e9b8992SJorge Lopez 	if (obj->type != ACPI_TYPE_BUFFER) {
8226e9b8992SJorge Lopez 		pr_info("Unknown response received %d\n", obj->type);
8236e9b8992SJorge Lopez 		kfree(obj);
8246e9b8992SJorge Lopez 		return;
8256e9b8992SJorge Lopez 	}
8266e9b8992SJorge Lopez 
8276e9b8992SJorge Lopez 	/*
8286e9b8992SJorge Lopez 	 * Depending on ACPI version the concatenation of id and event data
8296e9b8992SJorge Lopez 	 * inside _WED function will result in a 8 or 16 byte buffer.
8306e9b8992SJorge Lopez 	 */
8316e9b8992SJorge Lopez 	location = (u32 *)obj->buffer.pointer;
8326e9b8992SJorge Lopez 	if (obj->buffer.length == 8) {
8336e9b8992SJorge Lopez 		event_id = *location;
8346e9b8992SJorge Lopez 		event_data = *(location + 1);
8356e9b8992SJorge Lopez 	} else if (obj->buffer.length == 16) {
8366e9b8992SJorge Lopez 		event_id = *location;
8376e9b8992SJorge Lopez 		event_data = *(location + 2);
8386e9b8992SJorge Lopez 	} else {
8396e9b8992SJorge Lopez 		pr_info("Unknown buffer length %d\n", obj->buffer.length);
8406e9b8992SJorge Lopez 		kfree(obj);
8416e9b8992SJorge Lopez 		return;
8426e9b8992SJorge Lopez 	}
8436e9b8992SJorge Lopez 	kfree(obj);
8446e9b8992SJorge Lopez 
8456e9b8992SJorge Lopez 	switch (event_id) {
8466e9b8992SJorge Lopez 	case HPWMI_DOCK_EVENT:
8476e9b8992SJorge Lopez 		if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
8486e9b8992SJorge Lopez 			input_report_switch(hp_wmi_input_dev, SW_DOCK,
8496e9b8992SJorge Lopez 					    hp_wmi_get_dock_state());
8506e9b8992SJorge Lopez 		if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
8516e9b8992SJorge Lopez 			input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
8526e9b8992SJorge Lopez 					    hp_wmi_get_tablet_mode());
8536e9b8992SJorge Lopez 		input_sync(hp_wmi_input_dev);
8546e9b8992SJorge Lopez 		break;
8556e9b8992SJorge Lopez 	case HPWMI_PARK_HDD:
8566e9b8992SJorge Lopez 		break;
8576e9b8992SJorge Lopez 	case HPWMI_SMART_ADAPTER:
8586e9b8992SJorge Lopez 		break;
8596e9b8992SJorge Lopez 	case HPWMI_BEZEL_BUTTON:
8606e9b8992SJorge Lopez 		key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);
8616e9b8992SJorge Lopez 		if (key_code < 0)
8626e9b8992SJorge Lopez 			break;
8636e9b8992SJorge Lopez 
8646e9b8992SJorge Lopez 		if (!sparse_keymap_report_event(hp_wmi_input_dev,
8656e9b8992SJorge Lopez 						key_code, 1, true))
8666e9b8992SJorge Lopez 			pr_info("Unknown key code - 0x%x\n", key_code);
8676e9b8992SJorge Lopez 		break;
868f4a31a42SJonathan Singer 	case HPWMI_OMEN_KEY:
869f4a31a42SJonathan Singer 		if (event_data) /* Only should be true for HP Omen */
870f4a31a42SJonathan Singer 			key_code = event_data;
871f4a31a42SJonathan Singer 		else
872f4a31a42SJonathan Singer 			key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);
873f4a31a42SJonathan Singer 
874f4a31a42SJonathan Singer 		if (!sparse_keymap_report_event(hp_wmi_input_dev,
875f4a31a42SJonathan Singer 						key_code, 1, true))
876f4a31a42SJonathan Singer 			pr_info("Unknown key code - 0x%x\n", key_code);
877f4a31a42SJonathan Singer 		break;
8786e9b8992SJorge Lopez 	case HPWMI_WIRELESS:
8796e9b8992SJorge Lopez 		if (rfkill2_count) {
8806e9b8992SJorge Lopez 			hp_wmi_rfkill2_refresh();
8816e9b8992SJorge Lopez 			break;
8826e9b8992SJorge Lopez 		}
8836e9b8992SJorge Lopez 
8846e9b8992SJorge Lopez 		if (wifi_rfkill)
8856e9b8992SJorge Lopez 			rfkill_set_states(wifi_rfkill,
8866e9b8992SJorge Lopez 					  hp_wmi_get_sw_state(HPWMI_WIFI),
8876e9b8992SJorge Lopez 					  hp_wmi_get_hw_state(HPWMI_WIFI));
8886e9b8992SJorge Lopez 		if (bluetooth_rfkill)
8896e9b8992SJorge Lopez 			rfkill_set_states(bluetooth_rfkill,
8906e9b8992SJorge Lopez 					  hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
8916e9b8992SJorge Lopez 					  hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
8926e9b8992SJorge Lopez 		if (wwan_rfkill)
8936e9b8992SJorge Lopez 			rfkill_set_states(wwan_rfkill,
8946e9b8992SJorge Lopez 					  hp_wmi_get_sw_state(HPWMI_WWAN),
8956e9b8992SJorge Lopez 					  hp_wmi_get_hw_state(HPWMI_WWAN));
8966e9b8992SJorge Lopez 		break;
8976e9b8992SJorge Lopez 	case HPWMI_CPU_BATTERY_THROTTLE:
8986e9b8992SJorge Lopez 		pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
8996e9b8992SJorge Lopez 		break;
9006e9b8992SJorge Lopez 	case HPWMI_LOCK_SWITCH:
9016e9b8992SJorge Lopez 		break;
9026e9b8992SJorge Lopez 	case HPWMI_LID_SWITCH:
9036e9b8992SJorge Lopez 		break;
9046e9b8992SJorge Lopez 	case HPWMI_SCREEN_ROTATION:
9056e9b8992SJorge Lopez 		break;
9066e9b8992SJorge Lopez 	case HPWMI_COOLSENSE_SYSTEM_MOBILE:
9076e9b8992SJorge Lopez 		break;
9086e9b8992SJorge Lopez 	case HPWMI_COOLSENSE_SYSTEM_HOT:
9096e9b8992SJorge Lopez 		break;
9106e9b8992SJorge Lopez 	case HPWMI_PROXIMITY_SENSOR:
9116e9b8992SJorge Lopez 		break;
9126e9b8992SJorge Lopez 	case HPWMI_BACKLIT_KB_BRIGHTNESS:
9136e9b8992SJorge Lopez 		break;
9146e9b8992SJorge Lopez 	case HPWMI_PEAKSHIFT_PERIOD:
9156e9b8992SJorge Lopez 		break;
9166e9b8992SJorge Lopez 	case HPWMI_BATTERY_CHARGE_PERIOD:
9176e9b8992SJorge Lopez 		break;
9186e9b8992SJorge Lopez 	case HPWMI_SANITIZATION_MODE:
9196e9b8992SJorge Lopez 		break;
920604915f1SJonathan Singer 	case HPWMI_CAMERA_TOGGLE:
921604915f1SJonathan Singer 		if (!camera_shutter_input_dev)
922604915f1SJonathan Singer 			if (camera_shutter_input_setup()) {
923604915f1SJonathan Singer 				pr_err("Failed to setup camera shutter input device\n");
924604915f1SJonathan Singer 				break;
925604915f1SJonathan Singer 			}
926604915f1SJonathan Singer 		if (event_data == 0xff)
927604915f1SJonathan Singer 			input_report_switch(camera_shutter_input_dev, SW_CAMERA_LENS_COVER, 1);
928604915f1SJonathan Singer 		else if (event_data == 0xfe)
929604915f1SJonathan Singer 			input_report_switch(camera_shutter_input_dev, SW_CAMERA_LENS_COVER, 0);
930604915f1SJonathan Singer 		else
931604915f1SJonathan Singer 			pr_warn("Unknown camera shutter state - 0x%x\n", event_data);
932604915f1SJonathan Singer 		input_sync(camera_shutter_input_dev);
933604915f1SJonathan Singer 		break;
9346e9b8992SJorge Lopez 	case HPWMI_SMART_EXPERIENCE_APP:
9356e9b8992SJorge Lopez 		break;
9366e9b8992SJorge Lopez 	default:
9376e9b8992SJorge Lopez 		pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);
9386e9b8992SJorge Lopez 		break;
9396e9b8992SJorge Lopez 	}
9406e9b8992SJorge Lopez }
9416e9b8992SJorge Lopez 
hp_wmi_input_setup(void)9426e9b8992SJorge Lopez static int __init hp_wmi_input_setup(void)
9436e9b8992SJorge Lopez {
9446e9b8992SJorge Lopez 	acpi_status status;
9456e9b8992SJorge Lopez 	int err, val;
9466e9b8992SJorge Lopez 
9476e9b8992SJorge Lopez 	hp_wmi_input_dev = input_allocate_device();
9486e9b8992SJorge Lopez 	if (!hp_wmi_input_dev)
9496e9b8992SJorge Lopez 		return -ENOMEM;
9506e9b8992SJorge Lopez 
9516e9b8992SJorge Lopez 	hp_wmi_input_dev->name = "HP WMI hotkeys";
9526e9b8992SJorge Lopez 	hp_wmi_input_dev->phys = "wmi/input0";
9536e9b8992SJorge Lopez 	hp_wmi_input_dev->id.bustype = BUS_HOST;
9546e9b8992SJorge Lopez 
9556e9b8992SJorge Lopez 	__set_bit(EV_SW, hp_wmi_input_dev->evbit);
9566e9b8992SJorge Lopez 
9576e9b8992SJorge Lopez 	/* Dock */
9586e9b8992SJorge Lopez 	val = hp_wmi_get_dock_state();
9596e9b8992SJorge Lopez 	if (!(val < 0)) {
9606e9b8992SJorge Lopez 		__set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
9616e9b8992SJorge Lopez 		input_report_switch(hp_wmi_input_dev, SW_DOCK, val);
9626e9b8992SJorge Lopez 	}
9636e9b8992SJorge Lopez 
9646e9b8992SJorge Lopez 	/* Tablet mode */
9656e9b8992SJorge Lopez 	val = hp_wmi_get_tablet_mode();
9666e9b8992SJorge Lopez 	if (!(val < 0)) {
9676e9b8992SJorge Lopez 		__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
9686e9b8992SJorge Lopez 		input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
9696e9b8992SJorge Lopez 	}
9706e9b8992SJorge Lopez 
9716e9b8992SJorge Lopez 	err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
9726e9b8992SJorge Lopez 	if (err)
9736e9b8992SJorge Lopez 		goto err_free_dev;
9746e9b8992SJorge Lopez 
9756e9b8992SJorge Lopez 	/* Set initial hardware state */
9766e9b8992SJorge Lopez 	input_sync(hp_wmi_input_dev);
9776e9b8992SJorge Lopez 
9786e9b8992SJorge Lopez 	if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later())
9796e9b8992SJorge Lopez 		hp_wmi_enable_hotkeys();
9806e9b8992SJorge Lopez 
9816e9b8992SJorge Lopez 	status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
9826e9b8992SJorge Lopez 	if (ACPI_FAILURE(status)) {
9836e9b8992SJorge Lopez 		err = -EIO;
9846e9b8992SJorge Lopez 		goto err_free_dev;
9856e9b8992SJorge Lopez 	}
9866e9b8992SJorge Lopez 
9876e9b8992SJorge Lopez 	err = input_register_device(hp_wmi_input_dev);
9886e9b8992SJorge Lopez 	if (err)
9896e9b8992SJorge Lopez 		goto err_uninstall_notifier;
9906e9b8992SJorge Lopez 
9916e9b8992SJorge Lopez 	return 0;
9926e9b8992SJorge Lopez 
9936e9b8992SJorge Lopez  err_uninstall_notifier:
9946e9b8992SJorge Lopez 	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
9956e9b8992SJorge Lopez  err_free_dev:
9966e9b8992SJorge Lopez 	input_free_device(hp_wmi_input_dev);
9976e9b8992SJorge Lopez 	return err;
9986e9b8992SJorge Lopez }
9996e9b8992SJorge Lopez 
hp_wmi_input_destroy(void)10006e9b8992SJorge Lopez static void hp_wmi_input_destroy(void)
10016e9b8992SJorge Lopez {
10026e9b8992SJorge Lopez 	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
10036e9b8992SJorge Lopez 	input_unregister_device(hp_wmi_input_dev);
10046e9b8992SJorge Lopez }
10056e9b8992SJorge Lopez 
hp_wmi_rfkill_setup(struct platform_device * device)10066e9b8992SJorge Lopez static int __init hp_wmi_rfkill_setup(struct platform_device *device)
10076e9b8992SJorge Lopez {
10086e9b8992SJorge Lopez 	int err, wireless;
10096e9b8992SJorge Lopez 
10106e9b8992SJorge Lopez 	wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
10116e9b8992SJorge Lopez 	if (wireless < 0)
10126e9b8992SJorge Lopez 		return wireless;
10136e9b8992SJorge Lopez 
10146e9b8992SJorge Lopez 	err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &wireless,
10156e9b8992SJorge Lopez 				   sizeof(wireless), 0);
10166e9b8992SJorge Lopez 	if (err)
10176e9b8992SJorge Lopez 		return err;
10186e9b8992SJorge Lopez 
10196e9b8992SJorge Lopez 	if (wireless & 0x1) {
10206e9b8992SJorge Lopez 		wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
10216e9b8992SJorge Lopez 					   RFKILL_TYPE_WLAN,
10226e9b8992SJorge Lopez 					   &hp_wmi_rfkill_ops,
10236e9b8992SJorge Lopez 					   (void *) HPWMI_WIFI);
10246e9b8992SJorge Lopez 		if (!wifi_rfkill)
10256e9b8992SJorge Lopez 			return -ENOMEM;
10266e9b8992SJorge Lopez 		rfkill_init_sw_state(wifi_rfkill,
10276e9b8992SJorge Lopez 				     hp_wmi_get_sw_state(HPWMI_WIFI));
10286e9b8992SJorge Lopez 		rfkill_set_hw_state(wifi_rfkill,
10296e9b8992SJorge Lopez 				    hp_wmi_get_hw_state(HPWMI_WIFI));
10306e9b8992SJorge Lopez 		err = rfkill_register(wifi_rfkill);
10316e9b8992SJorge Lopez 		if (err)
10326e9b8992SJorge Lopez 			goto register_wifi_error;
10336e9b8992SJorge Lopez 	}
10346e9b8992SJorge Lopez 
10356e9b8992SJorge Lopez 	if (wireless & 0x2) {
10366e9b8992SJorge Lopez 		bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
10376e9b8992SJorge Lopez 						RFKILL_TYPE_BLUETOOTH,
10386e9b8992SJorge Lopez 						&hp_wmi_rfkill_ops,
10396e9b8992SJorge Lopez 						(void *) HPWMI_BLUETOOTH);
10406e9b8992SJorge Lopez 		if (!bluetooth_rfkill) {
10416e9b8992SJorge Lopez 			err = -ENOMEM;
10426e9b8992SJorge Lopez 			goto register_bluetooth_error;
10436e9b8992SJorge Lopez 		}
10446e9b8992SJorge Lopez 		rfkill_init_sw_state(bluetooth_rfkill,
10456e9b8992SJorge Lopez 				     hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
10466e9b8992SJorge Lopez 		rfkill_set_hw_state(bluetooth_rfkill,
10476e9b8992SJorge Lopez 				    hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
10486e9b8992SJorge Lopez 		err = rfkill_register(bluetooth_rfkill);
10496e9b8992SJorge Lopez 		if (err)
10506e9b8992SJorge Lopez 			goto register_bluetooth_error;
10516e9b8992SJorge Lopez 	}
10526e9b8992SJorge Lopez 
10536e9b8992SJorge Lopez 	if (wireless & 0x4) {
10546e9b8992SJorge Lopez 		wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
10556e9b8992SJorge Lopez 					   RFKILL_TYPE_WWAN,
10566e9b8992SJorge Lopez 					   &hp_wmi_rfkill_ops,
10576e9b8992SJorge Lopez 					   (void *) HPWMI_WWAN);
10586e9b8992SJorge Lopez 		if (!wwan_rfkill) {
10596e9b8992SJorge Lopez 			err = -ENOMEM;
10606e9b8992SJorge Lopez 			goto register_wwan_error;
10616e9b8992SJorge Lopez 		}
10626e9b8992SJorge Lopez 		rfkill_init_sw_state(wwan_rfkill,
10636e9b8992SJorge Lopez 				     hp_wmi_get_sw_state(HPWMI_WWAN));
10646e9b8992SJorge Lopez 		rfkill_set_hw_state(wwan_rfkill,
10656e9b8992SJorge Lopez 				    hp_wmi_get_hw_state(HPWMI_WWAN));
10666e9b8992SJorge Lopez 		err = rfkill_register(wwan_rfkill);
10676e9b8992SJorge Lopez 		if (err)
10686e9b8992SJorge Lopez 			goto register_wwan_error;
10696e9b8992SJorge Lopez 	}
10706e9b8992SJorge Lopez 
10716e9b8992SJorge Lopez 	return 0;
10726e9b8992SJorge Lopez 
10736e9b8992SJorge Lopez register_wwan_error:
10746e9b8992SJorge Lopez 	rfkill_destroy(wwan_rfkill);
10756e9b8992SJorge Lopez 	wwan_rfkill = NULL;
10766e9b8992SJorge Lopez 	if (bluetooth_rfkill)
10776e9b8992SJorge Lopez 		rfkill_unregister(bluetooth_rfkill);
10786e9b8992SJorge Lopez register_bluetooth_error:
10796e9b8992SJorge Lopez 	rfkill_destroy(bluetooth_rfkill);
10806e9b8992SJorge Lopez 	bluetooth_rfkill = NULL;
10816e9b8992SJorge Lopez 	if (wifi_rfkill)
10826e9b8992SJorge Lopez 		rfkill_unregister(wifi_rfkill);
10836e9b8992SJorge Lopez register_wifi_error:
10846e9b8992SJorge Lopez 	rfkill_destroy(wifi_rfkill);
10856e9b8992SJorge Lopez 	wifi_rfkill = NULL;
10866e9b8992SJorge Lopez 	return err;
10876e9b8992SJorge Lopez }
10886e9b8992SJorge Lopez 
hp_wmi_rfkill2_setup(struct platform_device * device)10896e9b8992SJorge Lopez static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
10906e9b8992SJorge Lopez {
10916e9b8992SJorge Lopez 	struct bios_rfkill2_state state;
10926e9b8992SJorge Lopez 	int err, i;
10936e9b8992SJorge Lopez 
10946e9b8992SJorge Lopez 	err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
10956e9b8992SJorge Lopez 				   zero_if_sup(state), sizeof(state));
10966e9b8992SJorge Lopez 	if (err)
10976e9b8992SJorge Lopez 		return err < 0 ? err : -EINVAL;
10986e9b8992SJorge Lopez 
10996e9b8992SJorge Lopez 	if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
11006e9b8992SJorge Lopez 		pr_warn("unable to parse 0x1b query output\n");
11016e9b8992SJorge Lopez 		return -EINVAL;
11026e9b8992SJorge Lopez 	}
11036e9b8992SJorge Lopez 
11046e9b8992SJorge Lopez 	for (i = 0; i < state.count; i++) {
11056e9b8992SJorge Lopez 		struct rfkill *rfkill;
11066e9b8992SJorge Lopez 		enum rfkill_type type;
11076e9b8992SJorge Lopez 		char *name;
11086e9b8992SJorge Lopez 
11096e9b8992SJorge Lopez 		switch (state.device[i].radio_type) {
11106e9b8992SJorge Lopez 		case HPWMI_WIFI:
11116e9b8992SJorge Lopez 			type = RFKILL_TYPE_WLAN;
11126e9b8992SJorge Lopez 			name = "hp-wifi";
11136e9b8992SJorge Lopez 			break;
11146e9b8992SJorge Lopez 		case HPWMI_BLUETOOTH:
11156e9b8992SJorge Lopez 			type = RFKILL_TYPE_BLUETOOTH;
11166e9b8992SJorge Lopez 			name = "hp-bluetooth";
11176e9b8992SJorge Lopez 			break;
11186e9b8992SJorge Lopez 		case HPWMI_WWAN:
11196e9b8992SJorge Lopez 			type = RFKILL_TYPE_WWAN;
11206e9b8992SJorge Lopez 			name = "hp-wwan";
11216e9b8992SJorge Lopez 			break;
11226e9b8992SJorge Lopez 		case HPWMI_GPS:
11236e9b8992SJorge Lopez 			type = RFKILL_TYPE_GPS;
11246e9b8992SJorge Lopez 			name = "hp-gps";
11256e9b8992SJorge Lopez 			break;
11266e9b8992SJorge Lopez 		default:
11276e9b8992SJorge Lopez 			pr_warn("unknown device type 0x%x\n",
11286e9b8992SJorge Lopez 				state.device[i].radio_type);
11296e9b8992SJorge Lopez 			continue;
11306e9b8992SJorge Lopez 		}
11316e9b8992SJorge Lopez 
11326e9b8992SJorge Lopez 		if (!state.device[i].vendor_id) {
11336e9b8992SJorge Lopez 			pr_warn("zero device %d while %d reported\n",
11346e9b8992SJorge Lopez 				i, state.count);
11356e9b8992SJorge Lopez 			continue;
11366e9b8992SJorge Lopez 		}
11376e9b8992SJorge Lopez 
11386e9b8992SJorge Lopez 		rfkill = rfkill_alloc(name, &device->dev, type,
11396e9b8992SJorge Lopez 				      &hp_wmi_rfkill2_ops, (void *)(long)i);
11406e9b8992SJorge Lopez 		if (!rfkill) {
11416e9b8992SJorge Lopez 			err = -ENOMEM;
11426e9b8992SJorge Lopez 			goto fail;
11436e9b8992SJorge Lopez 		}
11446e9b8992SJorge Lopez 
11456e9b8992SJorge Lopez 		rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
11466e9b8992SJorge Lopez 		rfkill2[rfkill2_count].num = i;
11476e9b8992SJorge Lopez 		rfkill2[rfkill2_count].rfkill = rfkill;
11486e9b8992SJorge Lopez 
11496e9b8992SJorge Lopez 		rfkill_init_sw_state(rfkill,
11506e9b8992SJorge Lopez 				     IS_SWBLOCKED(state.device[i].power));
11516e9b8992SJorge Lopez 		rfkill_set_hw_state(rfkill,
11526e9b8992SJorge Lopez 				    IS_HWBLOCKED(state.device[i].power));
11536e9b8992SJorge Lopez 
11546e9b8992SJorge Lopez 		if (!(state.device[i].power & HPWMI_POWER_BIOS))
11556e9b8992SJorge Lopez 			pr_info("device %s blocked by BIOS\n", name);
11566e9b8992SJorge Lopez 
11576e9b8992SJorge Lopez 		err = rfkill_register(rfkill);
11586e9b8992SJorge Lopez 		if (err) {
11596e9b8992SJorge Lopez 			rfkill_destroy(rfkill);
11606e9b8992SJorge Lopez 			goto fail;
11616e9b8992SJorge Lopez 		}
11626e9b8992SJorge Lopez 
11636e9b8992SJorge Lopez 		rfkill2_count++;
11646e9b8992SJorge Lopez 	}
11656e9b8992SJorge Lopez 
11666e9b8992SJorge Lopez 	return 0;
11676e9b8992SJorge Lopez fail:
11686e9b8992SJorge Lopez 	for (; rfkill2_count > 0; rfkill2_count--) {
11696e9b8992SJorge Lopez 		rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
11706e9b8992SJorge Lopez 		rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
11716e9b8992SJorge Lopez 	}
11726e9b8992SJorge Lopez 	return err;
11736e9b8992SJorge Lopez }
11746e9b8992SJorge Lopez 
platform_profile_omen_get(struct platform_profile_handler * pprof,enum platform_profile_option * profile)11756e9b8992SJorge Lopez static int platform_profile_omen_get(struct platform_profile_handler *pprof,
11766e9b8992SJorge Lopez 				     enum platform_profile_option *profile)
11776e9b8992SJorge Lopez {
11786e9b8992SJorge Lopez 	int tp;
11796e9b8992SJorge Lopez 
11806e9b8992SJorge Lopez 	tp = omen_thermal_profile_get();
11816e9b8992SJorge Lopez 	if (tp < 0)
11826e9b8992SJorge Lopez 		return tp;
11836e9b8992SJorge Lopez 
11846e9b8992SJorge Lopez 	switch (tp) {
11856e9b8992SJorge Lopez 	case HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE:
11866e9b8992SJorge Lopez 	case HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE:
11876e9b8992SJorge Lopez 		*profile = PLATFORM_PROFILE_PERFORMANCE;
11886e9b8992SJorge Lopez 		break;
11896e9b8992SJorge Lopez 	case HP_OMEN_V0_THERMAL_PROFILE_DEFAULT:
11906e9b8992SJorge Lopez 	case HP_OMEN_V1_THERMAL_PROFILE_DEFAULT:
11916e9b8992SJorge Lopez 		*profile = PLATFORM_PROFILE_BALANCED;
11926e9b8992SJorge Lopez 		break;
11936e9b8992SJorge Lopez 	case HP_OMEN_V0_THERMAL_PROFILE_COOL:
11946e9b8992SJorge Lopez 	case HP_OMEN_V1_THERMAL_PROFILE_COOL:
11956e9b8992SJorge Lopez 		*profile = PLATFORM_PROFILE_COOL;
11966e9b8992SJorge Lopez 		break;
11976e9b8992SJorge Lopez 	default:
11986e9b8992SJorge Lopez 		return -EINVAL;
11996e9b8992SJorge Lopez 	}
12006e9b8992SJorge Lopez 
12016e9b8992SJorge Lopez 	return 0;
12026e9b8992SJorge Lopez }
12036e9b8992SJorge Lopez 
platform_profile_omen_set(struct platform_profile_handler * pprof,enum platform_profile_option profile)12046e9b8992SJorge Lopez static int platform_profile_omen_set(struct platform_profile_handler *pprof,
12056e9b8992SJorge Lopez 				     enum platform_profile_option profile)
12066e9b8992SJorge Lopez {
12076e9b8992SJorge Lopez 	int err, tp, tp_version;
12086e9b8992SJorge Lopez 
12096e9b8992SJorge Lopez 	tp_version = omen_get_thermal_policy_version();
12106e9b8992SJorge Lopez 
12116e9b8992SJorge Lopez 	if (tp_version < 0 || tp_version > 1)
12126e9b8992SJorge Lopez 		return -EOPNOTSUPP;
12136e9b8992SJorge Lopez 
12146e9b8992SJorge Lopez 	switch (profile) {
12156e9b8992SJorge Lopez 	case PLATFORM_PROFILE_PERFORMANCE:
12166e9b8992SJorge Lopez 		if (tp_version == 0)
12176e9b8992SJorge Lopez 			tp = HP_OMEN_V0_THERMAL_PROFILE_PERFORMANCE;
12186e9b8992SJorge Lopez 		else
12196e9b8992SJorge Lopez 			tp = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE;
12206e9b8992SJorge Lopez 		break;
12216e9b8992SJorge Lopez 	case PLATFORM_PROFILE_BALANCED:
12226e9b8992SJorge Lopez 		if (tp_version == 0)
12236e9b8992SJorge Lopez 			tp = HP_OMEN_V0_THERMAL_PROFILE_DEFAULT;
12246e9b8992SJorge Lopez 		else
12256e9b8992SJorge Lopez 			tp = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT;
12266e9b8992SJorge Lopez 		break;
12276e9b8992SJorge Lopez 	case PLATFORM_PROFILE_COOL:
12286e9b8992SJorge Lopez 		if (tp_version == 0)
12296e9b8992SJorge Lopez 			tp = HP_OMEN_V0_THERMAL_PROFILE_COOL;
12306e9b8992SJorge Lopez 		else
12316e9b8992SJorge Lopez 			tp = HP_OMEN_V1_THERMAL_PROFILE_COOL;
12326e9b8992SJorge Lopez 		break;
12336e9b8992SJorge Lopez 	default:
12346e9b8992SJorge Lopez 		return -EOPNOTSUPP;
12356e9b8992SJorge Lopez 	}
12366e9b8992SJorge Lopez 
12376e9b8992SJorge Lopez 	err = omen_thermal_profile_set(tp);
12386e9b8992SJorge Lopez 	if (err < 0)
12396e9b8992SJorge Lopez 		return err;
12406e9b8992SJorge Lopez 
12416e9b8992SJorge Lopez 	return 0;
12426e9b8992SJorge Lopez }
12436e9b8992SJorge Lopez 
thermal_profile_get(void)12446e9b8992SJorge Lopez static int thermal_profile_get(void)
12456e9b8992SJorge Lopez {
12466e9b8992SJorge Lopez 	return hp_wmi_read_int(HPWMI_THERMAL_PROFILE_QUERY);
12476e9b8992SJorge Lopez }
12486e9b8992SJorge Lopez 
thermal_profile_set(int thermal_profile)12496e9b8992SJorge Lopez static int thermal_profile_set(int thermal_profile)
12506e9b8992SJorge Lopez {
12516e9b8992SJorge Lopez 	return hp_wmi_perform_query(HPWMI_THERMAL_PROFILE_QUERY, HPWMI_WRITE, &thermal_profile,
12526e9b8992SJorge Lopez 							   sizeof(thermal_profile), 0);
12536e9b8992SJorge Lopez }
12546e9b8992SJorge Lopez 
hp_wmi_platform_profile_get(struct platform_profile_handler * pprof,enum platform_profile_option * profile)12556e9b8992SJorge Lopez static int hp_wmi_platform_profile_get(struct platform_profile_handler *pprof,
12566e9b8992SJorge Lopez 					enum platform_profile_option *profile)
12576e9b8992SJorge Lopez {
12586e9b8992SJorge Lopez 	int tp;
12596e9b8992SJorge Lopez 
12606e9b8992SJorge Lopez 	tp = thermal_profile_get();
12616e9b8992SJorge Lopez 	if (tp < 0)
12626e9b8992SJorge Lopez 		return tp;
12636e9b8992SJorge Lopez 
12646e9b8992SJorge Lopez 	switch (tp) {
12656e9b8992SJorge Lopez 	case HP_THERMAL_PROFILE_PERFORMANCE:
12666e9b8992SJorge Lopez 		*profile =  PLATFORM_PROFILE_PERFORMANCE;
12676e9b8992SJorge Lopez 		break;
12686e9b8992SJorge Lopez 	case HP_THERMAL_PROFILE_DEFAULT:
12696e9b8992SJorge Lopez 		*profile =  PLATFORM_PROFILE_BALANCED;
12706e9b8992SJorge Lopez 		break;
12716e9b8992SJorge Lopez 	case HP_THERMAL_PROFILE_COOL:
12726e9b8992SJorge Lopez 		*profile =  PLATFORM_PROFILE_COOL;
12736e9b8992SJorge Lopez 		break;
12746e9b8992SJorge Lopez 	case HP_THERMAL_PROFILE_QUIET:
12756e9b8992SJorge Lopez 		*profile = PLATFORM_PROFILE_QUIET;
12766e9b8992SJorge Lopez 		break;
12776e9b8992SJorge Lopez 	default:
12786e9b8992SJorge Lopez 		return -EINVAL;
12796e9b8992SJorge Lopez 	}
12806e9b8992SJorge Lopez 
12816e9b8992SJorge Lopez 	return 0;
12826e9b8992SJorge Lopez }
12836e9b8992SJorge Lopez 
hp_wmi_platform_profile_set(struct platform_profile_handler * pprof,enum platform_profile_option profile)12846e9b8992SJorge Lopez static int hp_wmi_platform_profile_set(struct platform_profile_handler *pprof,
12856e9b8992SJorge Lopez 					enum platform_profile_option profile)
12866e9b8992SJorge Lopez {
12876e9b8992SJorge Lopez 	int err, tp;
12886e9b8992SJorge Lopez 
12896e9b8992SJorge Lopez 	switch (profile) {
12906e9b8992SJorge Lopez 	case PLATFORM_PROFILE_PERFORMANCE:
12916e9b8992SJorge Lopez 		tp =  HP_THERMAL_PROFILE_PERFORMANCE;
12926e9b8992SJorge Lopez 		break;
12936e9b8992SJorge Lopez 	case PLATFORM_PROFILE_BALANCED:
12946e9b8992SJorge Lopez 		tp =  HP_THERMAL_PROFILE_DEFAULT;
12956e9b8992SJorge Lopez 		break;
12966e9b8992SJorge Lopez 	case PLATFORM_PROFILE_COOL:
12976e9b8992SJorge Lopez 		tp =  HP_THERMAL_PROFILE_COOL;
12986e9b8992SJorge Lopez 		break;
12996e9b8992SJorge Lopez 	case PLATFORM_PROFILE_QUIET:
13006e9b8992SJorge Lopez 		tp = HP_THERMAL_PROFILE_QUIET;
13016e9b8992SJorge Lopez 		break;
13026e9b8992SJorge Lopez 	default:
13036e9b8992SJorge Lopez 		return -EOPNOTSUPP;
13046e9b8992SJorge Lopez 	}
13056e9b8992SJorge Lopez 
13066e9b8992SJorge Lopez 	err = thermal_profile_set(tp);
13076e9b8992SJorge Lopez 	if (err)
13086e9b8992SJorge Lopez 		return err;
13096e9b8992SJorge Lopez 
13106e9b8992SJorge Lopez 	return 0;
13116e9b8992SJorge Lopez }
13126e9b8992SJorge Lopez 
is_victus_thermal_profile(void)13132515e542SSungHwan Jung static bool is_victus_thermal_profile(void)
13142515e542SSungHwan Jung {
13152515e542SSungHwan Jung 	const char *board_name = dmi_get_system_info(DMI_BOARD_NAME);
13162515e542SSungHwan Jung 
13172515e542SSungHwan Jung 	if (!board_name)
13182515e542SSungHwan Jung 		return false;
13192515e542SSungHwan Jung 
13202515e542SSungHwan Jung 	return match_string(victus_thermal_profile_boards,
13212515e542SSungHwan Jung 			    ARRAY_SIZE(victus_thermal_profile_boards),
13222515e542SSungHwan Jung 			    board_name) >= 0;
13232515e542SSungHwan Jung }
13242515e542SSungHwan Jung 
platform_profile_victus_get(struct platform_profile_handler * pprof,enum platform_profile_option * profile)13252515e542SSungHwan Jung static int platform_profile_victus_get(struct platform_profile_handler *pprof,
13262515e542SSungHwan Jung 				     enum platform_profile_option *profile)
13272515e542SSungHwan Jung {
13282515e542SSungHwan Jung 	int tp;
13292515e542SSungHwan Jung 
13302515e542SSungHwan Jung 	tp = omen_thermal_profile_get();
13312515e542SSungHwan Jung 	if (tp < 0)
13322515e542SSungHwan Jung 		return tp;
13332515e542SSungHwan Jung 
13342515e542SSungHwan Jung 	switch (tp) {
13352515e542SSungHwan Jung 	case HP_VICTUS_THERMAL_PROFILE_PERFORMANCE:
13362515e542SSungHwan Jung 		*profile = PLATFORM_PROFILE_PERFORMANCE;
13372515e542SSungHwan Jung 		break;
13382515e542SSungHwan Jung 	case HP_VICTUS_THERMAL_PROFILE_DEFAULT:
13392515e542SSungHwan Jung 		*profile = PLATFORM_PROFILE_BALANCED;
13402515e542SSungHwan Jung 		break;
13412515e542SSungHwan Jung 	case HP_VICTUS_THERMAL_PROFILE_QUIET:
13422515e542SSungHwan Jung 		*profile = PLATFORM_PROFILE_QUIET;
13432515e542SSungHwan Jung 		break;
13442515e542SSungHwan Jung 	default:
13452515e542SSungHwan Jung 		return -EOPNOTSUPP;
13462515e542SSungHwan Jung 	}
13472515e542SSungHwan Jung 
13482515e542SSungHwan Jung 	return 0;
13492515e542SSungHwan Jung }
13502515e542SSungHwan Jung 
platform_profile_victus_set(struct platform_profile_handler * pprof,enum platform_profile_option profile)13512515e542SSungHwan Jung static int platform_profile_victus_set(struct platform_profile_handler *pprof,
13522515e542SSungHwan Jung 				     enum platform_profile_option profile)
13532515e542SSungHwan Jung {
13542515e542SSungHwan Jung 	int err, tp;
13552515e542SSungHwan Jung 
13562515e542SSungHwan Jung 	switch (profile) {
13572515e542SSungHwan Jung 	case PLATFORM_PROFILE_PERFORMANCE:
13582515e542SSungHwan Jung 		tp = HP_VICTUS_THERMAL_PROFILE_PERFORMANCE;
13592515e542SSungHwan Jung 		break;
13602515e542SSungHwan Jung 	case PLATFORM_PROFILE_BALANCED:
13612515e542SSungHwan Jung 		tp = HP_VICTUS_THERMAL_PROFILE_DEFAULT;
13622515e542SSungHwan Jung 		break;
13632515e542SSungHwan Jung 	case PLATFORM_PROFILE_QUIET:
13642515e542SSungHwan Jung 		tp = HP_VICTUS_THERMAL_PROFILE_QUIET;
13652515e542SSungHwan Jung 		break;
13662515e542SSungHwan Jung 	default:
13672515e542SSungHwan Jung 		return -EOPNOTSUPP;
13682515e542SSungHwan Jung 	}
13692515e542SSungHwan Jung 
13702515e542SSungHwan Jung 	err = omen_thermal_profile_set(tp);
13712515e542SSungHwan Jung 	if (err < 0)
13722515e542SSungHwan Jung 		return err;
13732515e542SSungHwan Jung 
13742515e542SSungHwan Jung 	return 0;
13752515e542SSungHwan Jung }
13762515e542SSungHwan Jung 
thermal_profile_setup(void)13776e9b8992SJorge Lopez static int thermal_profile_setup(void)
13786e9b8992SJorge Lopez {
13796e9b8992SJorge Lopez 	int err, tp;
13806e9b8992SJorge Lopez 
13816e9b8992SJorge Lopez 	if (is_omen_thermal_profile()) {
13826e9b8992SJorge Lopez 		tp = omen_thermal_profile_get();
13836e9b8992SJorge Lopez 		if (tp < 0)
13846e9b8992SJorge Lopez 			return tp;
13856e9b8992SJorge Lopez 
13866e9b8992SJorge Lopez 		/*
13876e9b8992SJorge Lopez 		 * call thermal profile write command to ensure that the
13886e9b8992SJorge Lopez 		 * firmware correctly sets the OEM variables
13896e9b8992SJorge Lopez 		 */
13906e9b8992SJorge Lopez 
13916e9b8992SJorge Lopez 		err = omen_thermal_profile_set(tp);
13926e9b8992SJorge Lopez 		if (err < 0)
13936e9b8992SJorge Lopez 			return err;
13946e9b8992SJorge Lopez 
13956e9b8992SJorge Lopez 		platform_profile_handler.profile_get = platform_profile_omen_get;
13966e9b8992SJorge Lopez 		platform_profile_handler.profile_set = platform_profile_omen_set;
13972515e542SSungHwan Jung 
13982515e542SSungHwan Jung 		set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices);
13992515e542SSungHwan Jung 	} else if (is_victus_thermal_profile()) {
14002515e542SSungHwan Jung 		tp = omen_thermal_profile_get();
14012515e542SSungHwan Jung 		if (tp < 0)
14022515e542SSungHwan Jung 			return tp;
14032515e542SSungHwan Jung 
14042515e542SSungHwan Jung 		/*
14052515e542SSungHwan Jung 		 * call thermal profile write command to ensure that the
14062515e542SSungHwan Jung 		 * firmware correctly sets the OEM variables
14072515e542SSungHwan Jung 		 */
14082515e542SSungHwan Jung 		err = omen_thermal_profile_set(tp);
14092515e542SSungHwan Jung 		if (err < 0)
14102515e542SSungHwan Jung 			return err;
14112515e542SSungHwan Jung 
14122515e542SSungHwan Jung 		platform_profile_handler.profile_get = platform_profile_victus_get;
14132515e542SSungHwan Jung 		platform_profile_handler.profile_set = platform_profile_victus_set;
14142515e542SSungHwan Jung 
14152515e542SSungHwan Jung 		set_bit(PLATFORM_PROFILE_QUIET, platform_profile_handler.choices);
14166e9b8992SJorge Lopez 	} else {
14176e9b8992SJorge Lopez 		tp = thermal_profile_get();
14186e9b8992SJorge Lopez 
14196e9b8992SJorge Lopez 		if (tp < 0)
14206e9b8992SJorge Lopez 			return tp;
14216e9b8992SJorge Lopez 
14226e9b8992SJorge Lopez 		/*
14236e9b8992SJorge Lopez 		 * call thermal profile write command to ensure that the
14246e9b8992SJorge Lopez 		 * firmware correctly sets the OEM variables for the DPTF
14256e9b8992SJorge Lopez 		 */
14266e9b8992SJorge Lopez 		err = thermal_profile_set(tp);
14276e9b8992SJorge Lopez 		if (err)
14286e9b8992SJorge Lopez 			return err;
14296e9b8992SJorge Lopez 
14306e9b8992SJorge Lopez 		platform_profile_handler.profile_get = hp_wmi_platform_profile_get;
14316e9b8992SJorge Lopez 		platform_profile_handler.profile_set = hp_wmi_platform_profile_set;
14326e9b8992SJorge Lopez 
14336e9b8992SJorge Lopez 		set_bit(PLATFORM_PROFILE_QUIET, platform_profile_handler.choices);
14342515e542SSungHwan Jung 		set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices);
14356e9b8992SJorge Lopez 	}
14366e9b8992SJorge Lopez 
14376e9b8992SJorge Lopez 	set_bit(PLATFORM_PROFILE_BALANCED, platform_profile_handler.choices);
14386e9b8992SJorge Lopez 	set_bit(PLATFORM_PROFILE_PERFORMANCE, platform_profile_handler.choices);
14396e9b8992SJorge Lopez 
14406e9b8992SJorge Lopez 	err = platform_profile_register(&platform_profile_handler);
14416e9b8992SJorge Lopez 	if (err)
14426e9b8992SJorge Lopez 		return err;
14436e9b8992SJorge Lopez 
14446e9b8992SJorge Lopez 	platform_profile_support = true;
14456e9b8992SJorge Lopez 
14466e9b8992SJorge Lopez 	return 0;
14476e9b8992SJorge Lopez }
14486e9b8992SJorge Lopez 
14496e9b8992SJorge Lopez static int hp_wmi_hwmon_init(void);
14506e9b8992SJorge Lopez 
hp_wmi_bios_setup(struct platform_device * device)14516e9b8992SJorge Lopez static int __init hp_wmi_bios_setup(struct platform_device *device)
14526e9b8992SJorge Lopez {
14536e9b8992SJorge Lopez 	int err;
14546e9b8992SJorge Lopez 	/* clear detected rfkill devices */
14556e9b8992SJorge Lopez 	wifi_rfkill = NULL;
14566e9b8992SJorge Lopez 	bluetooth_rfkill = NULL;
14576e9b8992SJorge Lopez 	wwan_rfkill = NULL;
14586e9b8992SJorge Lopez 	rfkill2_count = 0;
14596e9b8992SJorge Lopez 
14606e9b8992SJorge Lopez 	/*
14616e9b8992SJorge Lopez 	 * In pre-2009 BIOS, command 1Bh return 0x4 to indicate that
14626e9b8992SJorge Lopez 	 * BIOS no longer controls the power for the wireless
14636e9b8992SJorge Lopez 	 * devices. All features supported by this command will no
14646e9b8992SJorge Lopez 	 * longer be supported.
14656e9b8992SJorge Lopez 	 */
14666e9b8992SJorge Lopez 	if (!hp_wmi_bios_2009_later()) {
14676e9b8992SJorge Lopez 		if (hp_wmi_rfkill_setup(device))
14686e9b8992SJorge Lopez 			hp_wmi_rfkill2_setup(device);
14696e9b8992SJorge Lopez 	}
14706e9b8992SJorge Lopez 
14716e9b8992SJorge Lopez 	err = hp_wmi_hwmon_init();
14726e9b8992SJorge Lopez 
14736e9b8992SJorge Lopez 	if (err < 0)
14746e9b8992SJorge Lopez 		return err;
14756e9b8992SJorge Lopez 
14766e9b8992SJorge Lopez 	thermal_profile_setup();
14776e9b8992SJorge Lopez 
14786e9b8992SJorge Lopez 	return 0;
14796e9b8992SJorge Lopez }
14806e9b8992SJorge Lopez 
hp_wmi_bios_remove(struct platform_device * device)14816e9b8992SJorge Lopez static int __exit hp_wmi_bios_remove(struct platform_device *device)
14826e9b8992SJorge Lopez {
14836e9b8992SJorge Lopez 	int i;
14846e9b8992SJorge Lopez 
14856e9b8992SJorge Lopez 	for (i = 0; i < rfkill2_count; i++) {
14866e9b8992SJorge Lopez 		rfkill_unregister(rfkill2[i].rfkill);
14876e9b8992SJorge Lopez 		rfkill_destroy(rfkill2[i].rfkill);
14886e9b8992SJorge Lopez 	}
14896e9b8992SJorge Lopez 
14906e9b8992SJorge Lopez 	if (wifi_rfkill) {
14916e9b8992SJorge Lopez 		rfkill_unregister(wifi_rfkill);
14926e9b8992SJorge Lopez 		rfkill_destroy(wifi_rfkill);
14936e9b8992SJorge Lopez 	}
14946e9b8992SJorge Lopez 	if (bluetooth_rfkill) {
14956e9b8992SJorge Lopez 		rfkill_unregister(bluetooth_rfkill);
14966e9b8992SJorge Lopez 		rfkill_destroy(bluetooth_rfkill);
14976e9b8992SJorge Lopez 	}
14986e9b8992SJorge Lopez 	if (wwan_rfkill) {
14996e9b8992SJorge Lopez 		rfkill_unregister(wwan_rfkill);
15006e9b8992SJorge Lopez 		rfkill_destroy(wwan_rfkill);
15016e9b8992SJorge Lopez 	}
15026e9b8992SJorge Lopez 
15036e9b8992SJorge Lopez 	if (platform_profile_support)
15046e9b8992SJorge Lopez 		platform_profile_remove();
15056e9b8992SJorge Lopez 
15066e9b8992SJorge Lopez 	return 0;
15076e9b8992SJorge Lopez }
15086e9b8992SJorge Lopez 
hp_wmi_resume_handler(struct device * device)15096e9b8992SJorge Lopez static int hp_wmi_resume_handler(struct device *device)
15106e9b8992SJorge Lopez {
15116e9b8992SJorge Lopez 	/*
15126e9b8992SJorge Lopez 	 * Hardware state may have changed while suspended, so trigger
15136e9b8992SJorge Lopez 	 * input events for the current state. As this is a switch,
15146e9b8992SJorge Lopez 	 * the input layer will only actually pass it on if the state
15156e9b8992SJorge Lopez 	 * changed.
15166e9b8992SJorge Lopez 	 */
15176e9b8992SJorge Lopez 	if (hp_wmi_input_dev) {
15186e9b8992SJorge Lopez 		if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
15196e9b8992SJorge Lopez 			input_report_switch(hp_wmi_input_dev, SW_DOCK,
15206e9b8992SJorge Lopez 					    hp_wmi_get_dock_state());
15216e9b8992SJorge Lopez 		if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
15226e9b8992SJorge Lopez 			input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
15236e9b8992SJorge Lopez 					    hp_wmi_get_tablet_mode());
15246e9b8992SJorge Lopez 		input_sync(hp_wmi_input_dev);
15256e9b8992SJorge Lopez 	}
15266e9b8992SJorge Lopez 
15276e9b8992SJorge Lopez 	if (rfkill2_count)
15286e9b8992SJorge Lopez 		hp_wmi_rfkill2_refresh();
15296e9b8992SJorge Lopez 
15306e9b8992SJorge Lopez 	if (wifi_rfkill)
15316e9b8992SJorge Lopez 		rfkill_set_states(wifi_rfkill,
15326e9b8992SJorge Lopez 				  hp_wmi_get_sw_state(HPWMI_WIFI),
15336e9b8992SJorge Lopez 				  hp_wmi_get_hw_state(HPWMI_WIFI));
15346e9b8992SJorge Lopez 	if (bluetooth_rfkill)
15356e9b8992SJorge Lopez 		rfkill_set_states(bluetooth_rfkill,
15366e9b8992SJorge Lopez 				  hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
15376e9b8992SJorge Lopez 				  hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
15386e9b8992SJorge Lopez 	if (wwan_rfkill)
15396e9b8992SJorge Lopez 		rfkill_set_states(wwan_rfkill,
15406e9b8992SJorge Lopez 				  hp_wmi_get_sw_state(HPWMI_WWAN),
15416e9b8992SJorge Lopez 				  hp_wmi_get_hw_state(HPWMI_WWAN));
15426e9b8992SJorge Lopez 
15436e9b8992SJorge Lopez 	return 0;
15446e9b8992SJorge Lopez }
15456e9b8992SJorge Lopez 
15466e9b8992SJorge Lopez static const struct dev_pm_ops hp_wmi_pm_ops = {
15476e9b8992SJorge Lopez 	.resume  = hp_wmi_resume_handler,
15486e9b8992SJorge Lopez 	.restore  = hp_wmi_resume_handler,
15496e9b8992SJorge Lopez };
15506e9b8992SJorge Lopez 
1551*5b44abbcSUwe Kleine-König /*
1552*5b44abbcSUwe Kleine-König  * hp_wmi_bios_remove() lives in .exit.text. For drivers registered via
1553*5b44abbcSUwe Kleine-König  * module_platform_driver_probe() this is ok because they cannot get unbound at
1554*5b44abbcSUwe Kleine-König  * runtime. So mark the driver struct with __refdata to prevent modpost
1555*5b44abbcSUwe Kleine-König  * triggering a section mismatch warning.
1556*5b44abbcSUwe Kleine-König  */
1557*5b44abbcSUwe Kleine-König static struct platform_driver hp_wmi_driver __refdata = {
15586e9b8992SJorge Lopez 	.driver = {
15596e9b8992SJorge Lopez 		.name = "hp-wmi",
15606e9b8992SJorge Lopez 		.pm = &hp_wmi_pm_ops,
15616e9b8992SJorge Lopez 		.dev_groups = hp_wmi_groups,
15626e9b8992SJorge Lopez 	},
15636e9b8992SJorge Lopez 	.remove = __exit_p(hp_wmi_bios_remove),
15646e9b8992SJorge Lopez };
15656e9b8992SJorge Lopez 
hp_wmi_hwmon_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)15666e9b8992SJorge Lopez static umode_t hp_wmi_hwmon_is_visible(const void *data,
15676e9b8992SJorge Lopez 				       enum hwmon_sensor_types type,
15686e9b8992SJorge Lopez 				       u32 attr, int channel)
15696e9b8992SJorge Lopez {
15706e9b8992SJorge Lopez 	switch (type) {
15716e9b8992SJorge Lopez 	case hwmon_pwm:
15726e9b8992SJorge Lopez 		return 0644;
15736e9b8992SJorge Lopez 	case hwmon_fan:
15746e9b8992SJorge Lopez 		if (hp_wmi_get_fan_speed(channel) >= 0)
15756e9b8992SJorge Lopez 			return 0444;
15766e9b8992SJorge Lopez 		break;
15776e9b8992SJorge Lopez 	default:
15786e9b8992SJorge Lopez 		return 0;
15796e9b8992SJorge Lopez 	}
15806e9b8992SJorge Lopez 
15816e9b8992SJorge Lopez 	return 0;
15826e9b8992SJorge Lopez }
15836e9b8992SJorge Lopez 
hp_wmi_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)15846e9b8992SJorge Lopez static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
15856e9b8992SJorge Lopez 			     u32 attr, int channel, long *val)
15866e9b8992SJorge Lopez {
15876e9b8992SJorge Lopez 	int ret;
15886e9b8992SJorge Lopez 
15896e9b8992SJorge Lopez 	switch (type) {
15906e9b8992SJorge Lopez 	case hwmon_fan:
15916e9b8992SJorge Lopez 		ret = hp_wmi_get_fan_speed(channel);
15926e9b8992SJorge Lopez 
15936e9b8992SJorge Lopez 		if (ret < 0)
15946e9b8992SJorge Lopez 			return ret;
15956e9b8992SJorge Lopez 		*val = ret;
15966e9b8992SJorge Lopez 		return 0;
15976e9b8992SJorge Lopez 	case hwmon_pwm:
15986e9b8992SJorge Lopez 		switch (hp_wmi_fan_speed_max_get()) {
15996e9b8992SJorge Lopez 		case 0:
16006e9b8992SJorge Lopez 			/* 0 is automatic fan, which is 2 for hwmon */
16016e9b8992SJorge Lopez 			*val = 2;
16026e9b8992SJorge Lopez 			return 0;
16036e9b8992SJorge Lopez 		case 1:
16046e9b8992SJorge Lopez 			/* 1 is max fan, which is 0
16056e9b8992SJorge Lopez 			 * (no fan speed control) for hwmon
16066e9b8992SJorge Lopez 			 */
16076e9b8992SJorge Lopez 			*val = 0;
16086e9b8992SJorge Lopez 			return 0;
16096e9b8992SJorge Lopez 		default:
16106e9b8992SJorge Lopez 			/* shouldn't happen */
16116e9b8992SJorge Lopez 			return -ENODATA;
16126e9b8992SJorge Lopez 		}
16136e9b8992SJorge Lopez 	default:
16146e9b8992SJorge Lopez 		return -EINVAL;
16156e9b8992SJorge Lopez 	}
16166e9b8992SJorge Lopez }
16176e9b8992SJorge Lopez 
hp_wmi_hwmon_write(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long val)16186e9b8992SJorge Lopez static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
16196e9b8992SJorge Lopez 			      u32 attr, int channel, long val)
16206e9b8992SJorge Lopez {
16216e9b8992SJorge Lopez 	switch (type) {
16226e9b8992SJorge Lopez 	case hwmon_pwm:
16236e9b8992SJorge Lopez 		switch (val) {
16246e9b8992SJorge Lopez 		case 0:
16256e9b8992SJorge Lopez 			/* 0 is no fan speed control (max), which is 1 for us */
16266e9b8992SJorge Lopez 			return hp_wmi_fan_speed_max_set(1);
16276e9b8992SJorge Lopez 		case 2:
16286e9b8992SJorge Lopez 			/* 2 is automatic speed control, which is 0 for us */
16296e9b8992SJorge Lopez 			return hp_wmi_fan_speed_max_set(0);
16306e9b8992SJorge Lopez 		default:
16316e9b8992SJorge Lopez 			/* we don't support manual fan speed control */
16326e9b8992SJorge Lopez 			return -EINVAL;
16336e9b8992SJorge Lopez 		}
16346e9b8992SJorge Lopez 	default:
16356e9b8992SJorge Lopez 		return -EOPNOTSUPP;
16366e9b8992SJorge Lopez 	}
16376e9b8992SJorge Lopez }
16386e9b8992SJorge Lopez 
16391180bdfdSKrzysztof Kozlowski static const struct hwmon_channel_info * const info[] = {
16406e9b8992SJorge Lopez 	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT),
16416e9b8992SJorge Lopez 	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_ENABLE),
16426e9b8992SJorge Lopez 	NULL
16436e9b8992SJorge Lopez };
16446e9b8992SJorge Lopez 
16456e9b8992SJorge Lopez static const struct hwmon_ops ops = {
16466e9b8992SJorge Lopez 	.is_visible = hp_wmi_hwmon_is_visible,
16476e9b8992SJorge Lopez 	.read = hp_wmi_hwmon_read,
16486e9b8992SJorge Lopez 	.write = hp_wmi_hwmon_write,
16496e9b8992SJorge Lopez };
16506e9b8992SJorge Lopez 
16516e9b8992SJorge Lopez static const struct hwmon_chip_info chip_info = {
16526e9b8992SJorge Lopez 	.ops = &ops,
16536e9b8992SJorge Lopez 	.info = info,
16546e9b8992SJorge Lopez };
16556e9b8992SJorge Lopez 
hp_wmi_hwmon_init(void)16566e9b8992SJorge Lopez static int hp_wmi_hwmon_init(void)
16576e9b8992SJorge Lopez {
16586e9b8992SJorge Lopez 	struct device *dev = &hp_wmi_platform_dev->dev;
16596e9b8992SJorge Lopez 	struct device *hwmon;
16606e9b8992SJorge Lopez 
16616e9b8992SJorge Lopez 	hwmon = devm_hwmon_device_register_with_info(dev, "hp", &hp_wmi_driver,
16626e9b8992SJorge Lopez 						     &chip_info, NULL);
16636e9b8992SJorge Lopez 
16646e9b8992SJorge Lopez 	if (IS_ERR(hwmon)) {
16656e9b8992SJorge Lopez 		dev_err(dev, "Could not register hp hwmon device\n");
16666e9b8992SJorge Lopez 		return PTR_ERR(hwmon);
16676e9b8992SJorge Lopez 	}
16686e9b8992SJorge Lopez 
16696e9b8992SJorge Lopez 	return 0;
16706e9b8992SJorge Lopez }
16716e9b8992SJorge Lopez 
hp_wmi_init(void)16726e9b8992SJorge Lopez static int __init hp_wmi_init(void)
16736e9b8992SJorge Lopez {
16746e9b8992SJorge Lopez 	int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
16756e9b8992SJorge Lopez 	int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
16766e9b8992SJorge Lopez 	int err, tmp = 0;
16776e9b8992SJorge Lopez 
16786e9b8992SJorge Lopez 	if (!bios_capable && !event_capable)
16796e9b8992SJorge Lopez 		return -ENODEV;
16806e9b8992SJorge Lopez 
16816e9b8992SJorge Lopez 	if (hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_READ, &tmp,
16826e9b8992SJorge Lopez 				 sizeof(tmp), sizeof(tmp)) == HPWMI_RET_INVALID_PARAMETERS)
16836e9b8992SJorge Lopez 		zero_insize_support = true;
16846e9b8992SJorge Lopez 
16856e9b8992SJorge Lopez 	if (event_capable) {
16866e9b8992SJorge Lopez 		err = hp_wmi_input_setup();
16876e9b8992SJorge Lopez 		if (err)
16886e9b8992SJorge Lopez 			return err;
16896e9b8992SJorge Lopez 	}
16906e9b8992SJorge Lopez 
16916e9b8992SJorge Lopez 	if (bios_capable) {
16926e9b8992SJorge Lopez 		hp_wmi_platform_dev =
16936e9b8992SJorge Lopez 			platform_device_register_simple("hp-wmi", PLATFORM_DEVID_NONE, NULL, 0);
16946e9b8992SJorge Lopez 		if (IS_ERR(hp_wmi_platform_dev)) {
16956e9b8992SJorge Lopez 			err = PTR_ERR(hp_wmi_platform_dev);
16966e9b8992SJorge Lopez 			goto err_destroy_input;
16976e9b8992SJorge Lopez 		}
16986e9b8992SJorge Lopez 
16996e9b8992SJorge Lopez 		err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup);
17006e9b8992SJorge Lopez 		if (err)
17016e9b8992SJorge Lopez 			goto err_unregister_device;
17026e9b8992SJorge Lopez 	}
17036e9b8992SJorge Lopez 
17046e9b8992SJorge Lopez 	return 0;
17056e9b8992SJorge Lopez 
17066e9b8992SJorge Lopez err_unregister_device:
17076e9b8992SJorge Lopez 	platform_device_unregister(hp_wmi_platform_dev);
17086e9b8992SJorge Lopez err_destroy_input:
17096e9b8992SJorge Lopez 	if (event_capable)
17106e9b8992SJorge Lopez 		hp_wmi_input_destroy();
17116e9b8992SJorge Lopez 
17126e9b8992SJorge Lopez 	return err;
17136e9b8992SJorge Lopez }
17146e9b8992SJorge Lopez module_init(hp_wmi_init);
17156e9b8992SJorge Lopez 
hp_wmi_exit(void)17166e9b8992SJorge Lopez static void __exit hp_wmi_exit(void)
17176e9b8992SJorge Lopez {
17186e9b8992SJorge Lopez 	if (wmi_has_guid(HPWMI_EVENT_GUID))
17196e9b8992SJorge Lopez 		hp_wmi_input_destroy();
17206e9b8992SJorge Lopez 
1721604915f1SJonathan Singer 	if (camera_shutter_input_dev)
1722604915f1SJonathan Singer 		input_unregister_device(camera_shutter_input_dev);
1723604915f1SJonathan Singer 
17246e9b8992SJorge Lopez 	if (hp_wmi_platform_dev) {
17256e9b8992SJorge Lopez 		platform_device_unregister(hp_wmi_platform_dev);
17266e9b8992SJorge Lopez 		platform_driver_unregister(&hp_wmi_driver);
17276e9b8992SJorge Lopez 	}
17286e9b8992SJorge Lopez }
17296e9b8992SJorge Lopez module_exit(hp_wmi_exit);
1730