18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * HP WMI hotkeys 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Red Hat <mjg@redhat.com> 68c2ecf20Sopenharmony_ci * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Portions based on wistron_btns.c: 98c2ecf20Sopenharmony_ci * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 108c2ecf20Sopenharmony_ci * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> 118c2ecf20Sopenharmony_ci * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/init.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/types.h> 218c2ecf20Sopenharmony_ci#include <linux/input.h> 228c2ecf20Sopenharmony_ci#include <linux/input/sparse-keymap.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 248c2ecf20Sopenharmony_ci#include <linux/acpi.h> 258c2ecf20Sopenharmony_ci#include <linux/rfkill.h> 268c2ecf20Sopenharmony_ci#include <linux/string.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciMODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>"); 298c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HP laptop WMI hotkeys driver"); 308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ciMODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C"); 338c2ecf20Sopenharmony_ciMODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int enable_tablet_mode_sw = -1; 368c2ecf20Sopenharmony_cimodule_param(enable_tablet_mode_sw, int, 0444); 378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable_tablet_mode_sw, "Enable SW_TABLET_MODE reporting (-1=auto, 0=no, 1=yes)"); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C" 408c2ecf20Sopenharmony_ci#define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cienum hp_wmi_radio { 438c2ecf20Sopenharmony_ci HPWMI_WIFI = 0x0, 448c2ecf20Sopenharmony_ci HPWMI_BLUETOOTH = 0x1, 458c2ecf20Sopenharmony_ci HPWMI_WWAN = 0x2, 468c2ecf20Sopenharmony_ci HPWMI_GPS = 0x3, 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cienum hp_wmi_event_ids { 508c2ecf20Sopenharmony_ci HPWMI_DOCK_EVENT = 0x01, 518c2ecf20Sopenharmony_ci HPWMI_PARK_HDD = 0x02, 528c2ecf20Sopenharmony_ci HPWMI_SMART_ADAPTER = 0x03, 538c2ecf20Sopenharmony_ci HPWMI_BEZEL_BUTTON = 0x04, 548c2ecf20Sopenharmony_ci HPWMI_WIRELESS = 0x05, 558c2ecf20Sopenharmony_ci HPWMI_CPU_BATTERY_THROTTLE = 0x06, 568c2ecf20Sopenharmony_ci HPWMI_LOCK_SWITCH = 0x07, 578c2ecf20Sopenharmony_ci HPWMI_LID_SWITCH = 0x08, 588c2ecf20Sopenharmony_ci HPWMI_SCREEN_ROTATION = 0x09, 598c2ecf20Sopenharmony_ci HPWMI_COOLSENSE_SYSTEM_MOBILE = 0x0A, 608c2ecf20Sopenharmony_ci HPWMI_COOLSENSE_SYSTEM_HOT = 0x0B, 618c2ecf20Sopenharmony_ci HPWMI_PROXIMITY_SENSOR = 0x0C, 628c2ecf20Sopenharmony_ci HPWMI_BACKLIT_KB_BRIGHTNESS = 0x0D, 638c2ecf20Sopenharmony_ci HPWMI_PEAKSHIFT_PERIOD = 0x0F, 648c2ecf20Sopenharmony_ci HPWMI_BATTERY_CHARGE_PERIOD = 0x10, 658c2ecf20Sopenharmony_ci HPWMI_SANITIZATION_MODE = 0x17, 668c2ecf20Sopenharmony_ci HPWMI_SMART_EXPERIENCE_APP = 0x21, 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct bios_args { 708c2ecf20Sopenharmony_ci u32 signature; 718c2ecf20Sopenharmony_ci u32 command; 728c2ecf20Sopenharmony_ci u32 commandtype; 738c2ecf20Sopenharmony_ci u32 datasize; 748c2ecf20Sopenharmony_ci u8 data[128]; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cienum hp_wmi_commandtype { 788c2ecf20Sopenharmony_ci HPWMI_DISPLAY_QUERY = 0x01, 798c2ecf20Sopenharmony_ci HPWMI_HDDTEMP_QUERY = 0x02, 808c2ecf20Sopenharmony_ci HPWMI_ALS_QUERY = 0x03, 818c2ecf20Sopenharmony_ci HPWMI_HARDWARE_QUERY = 0x04, 828c2ecf20Sopenharmony_ci HPWMI_WIRELESS_QUERY = 0x05, 838c2ecf20Sopenharmony_ci HPWMI_BATTERY_QUERY = 0x07, 848c2ecf20Sopenharmony_ci HPWMI_BIOS_QUERY = 0x09, 858c2ecf20Sopenharmony_ci HPWMI_FEATURE_QUERY = 0x0b, 868c2ecf20Sopenharmony_ci HPWMI_HOTKEY_QUERY = 0x0c, 878c2ecf20Sopenharmony_ci HPWMI_FEATURE2_QUERY = 0x0d, 888c2ecf20Sopenharmony_ci HPWMI_WIRELESS2_QUERY = 0x1b, 898c2ecf20Sopenharmony_ci HPWMI_POSTCODEERROR_QUERY = 0x2a, 908c2ecf20Sopenharmony_ci HPWMI_THERMAL_POLICY_QUERY = 0x4c, 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cienum hp_wmi_command { 948c2ecf20Sopenharmony_ci HPWMI_READ = 0x01, 958c2ecf20Sopenharmony_ci HPWMI_WRITE = 0x02, 968c2ecf20Sopenharmony_ci HPWMI_ODM = 0x03, 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cienum hp_wmi_hardware_mask { 1008c2ecf20Sopenharmony_ci HPWMI_DOCK_MASK = 0x01, 1018c2ecf20Sopenharmony_ci HPWMI_TABLET_MASK = 0x04, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistruct bios_return { 1058c2ecf20Sopenharmony_ci u32 sigpass; 1068c2ecf20Sopenharmony_ci u32 return_code; 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cienum hp_return_value { 1108c2ecf20Sopenharmony_ci HPWMI_RET_WRONG_SIGNATURE = 0x02, 1118c2ecf20Sopenharmony_ci HPWMI_RET_UNKNOWN_COMMAND = 0x03, 1128c2ecf20Sopenharmony_ci HPWMI_RET_UNKNOWN_CMDTYPE = 0x04, 1138c2ecf20Sopenharmony_ci HPWMI_RET_INVALID_PARAMETERS = 0x05, 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cienum hp_wireless2_bits { 1178c2ecf20Sopenharmony_ci HPWMI_POWER_STATE = 0x01, 1188c2ecf20Sopenharmony_ci HPWMI_POWER_SOFT = 0x02, 1198c2ecf20Sopenharmony_ci HPWMI_POWER_BIOS = 0x04, 1208c2ecf20Sopenharmony_ci HPWMI_POWER_HARD = 0x08, 1218c2ecf20Sopenharmony_ci HPWMI_POWER_FW_OR_HW = HPWMI_POWER_BIOS | HPWMI_POWER_HARD, 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define IS_HWBLOCKED(x) ((x & HPWMI_POWER_FW_OR_HW) != HPWMI_POWER_FW_OR_HW) 1258c2ecf20Sopenharmony_ci#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct bios_rfkill2_device_state { 1288c2ecf20Sopenharmony_ci u8 radio_type; 1298c2ecf20Sopenharmony_ci u8 bus_type; 1308c2ecf20Sopenharmony_ci u16 vendor_id; 1318c2ecf20Sopenharmony_ci u16 product_id; 1328c2ecf20Sopenharmony_ci u16 subsys_vendor_id; 1338c2ecf20Sopenharmony_ci u16 subsys_product_id; 1348c2ecf20Sopenharmony_ci u8 rfkill_id; 1358c2ecf20Sopenharmony_ci u8 power; 1368c2ecf20Sopenharmony_ci u8 unknown[4]; 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 7 devices fit into the 128 byte buffer */ 1408c2ecf20Sopenharmony_ci#define HPWMI_MAX_RFKILL2_DEVICES 7 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistruct bios_rfkill2_state { 1438c2ecf20Sopenharmony_ci u8 unknown[7]; 1448c2ecf20Sopenharmony_ci u8 count; 1458c2ecf20Sopenharmony_ci u8 pad[8]; 1468c2ecf20Sopenharmony_ci struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES]; 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic const struct key_entry hp_wmi_keymap[] = { 1508c2ecf20Sopenharmony_ci { KE_KEY, 0x02, { KEY_BRIGHTNESSUP } }, 1518c2ecf20Sopenharmony_ci { KE_KEY, 0x03, { KEY_BRIGHTNESSDOWN } }, 1528c2ecf20Sopenharmony_ci { KE_KEY, 0x20e6, { KEY_PROG1 } }, 1538c2ecf20Sopenharmony_ci { KE_KEY, 0x20e8, { KEY_MEDIA } }, 1548c2ecf20Sopenharmony_ci { KE_KEY, 0x2142, { KEY_MEDIA } }, 1558c2ecf20Sopenharmony_ci { KE_KEY, 0x213b, { KEY_INFO } }, 1568c2ecf20Sopenharmony_ci { KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } }, 1578c2ecf20Sopenharmony_ci { KE_KEY, 0x216a, { KEY_SETUP } }, 1588c2ecf20Sopenharmony_ci { KE_KEY, 0x231b, { KEY_HELP } }, 1598c2ecf20Sopenharmony_ci { KE_END, 0 } 1608c2ecf20Sopenharmony_ci}; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic struct input_dev *hp_wmi_input_dev; 1638c2ecf20Sopenharmony_cistatic struct platform_device *hp_wmi_platform_dev; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic struct rfkill *wifi_rfkill; 1668c2ecf20Sopenharmony_cistatic struct rfkill *bluetooth_rfkill; 1678c2ecf20Sopenharmony_cistatic struct rfkill *wwan_rfkill; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistruct rfkill2_device { 1708c2ecf20Sopenharmony_ci u8 id; 1718c2ecf20Sopenharmony_ci int num; 1728c2ecf20Sopenharmony_ci struct rfkill *rfkill; 1738c2ecf20Sopenharmony_ci}; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic int rfkill2_count; 1768c2ecf20Sopenharmony_cistatic struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* map output size to the corresponding WMI method id */ 1798c2ecf20Sopenharmony_cistatic inline int encode_outsize_for_pvsz(int outsize) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci if (outsize > 4096) 1828c2ecf20Sopenharmony_ci return -EINVAL; 1838c2ecf20Sopenharmony_ci if (outsize > 1024) 1848c2ecf20Sopenharmony_ci return 5; 1858c2ecf20Sopenharmony_ci if (outsize > 128) 1868c2ecf20Sopenharmony_ci return 4; 1878c2ecf20Sopenharmony_ci if (outsize > 4) 1888c2ecf20Sopenharmony_ci return 3; 1898c2ecf20Sopenharmony_ci if (outsize > 0) 1908c2ecf20Sopenharmony_ci return 2; 1918c2ecf20Sopenharmony_ci return 1; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci/* 1958c2ecf20Sopenharmony_ci * hp_wmi_perform_query 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * query: The commandtype (enum hp_wmi_commandtype) 1988c2ecf20Sopenharmony_ci * write: The command (enum hp_wmi_command) 1998c2ecf20Sopenharmony_ci * buffer: Buffer used as input and/or output 2008c2ecf20Sopenharmony_ci * insize: Size of input buffer 2018c2ecf20Sopenharmony_ci * outsize: Size of output buffer 2028c2ecf20Sopenharmony_ci * 2038c2ecf20Sopenharmony_ci * returns zero on success 2048c2ecf20Sopenharmony_ci * an HP WMI query specific error code (which is positive) 2058c2ecf20Sopenharmony_ci * -EINVAL if the query was not successful at all 2068c2ecf20Sopenharmony_ci * -EINVAL if the output buffer size exceeds buffersize 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * Note: The buffersize must at least be the maximum of the input and output 2098c2ecf20Sopenharmony_ci * size. E.g. Battery info query is defined to have 1 byte input 2108c2ecf20Sopenharmony_ci * and 128 byte output. The caller would do: 2118c2ecf20Sopenharmony_ci * buffer = kzalloc(128, GFP_KERNEL); 2128c2ecf20Sopenharmony_ci * ret = hp_wmi_perform_query(HPWMI_BATTERY_QUERY, HPWMI_READ, buffer, 1, 128) 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_cistatic int hp_wmi_perform_query(int query, enum hp_wmi_command command, 2158c2ecf20Sopenharmony_ci void *buffer, int insize, int outsize) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci int mid; 2188c2ecf20Sopenharmony_ci struct bios_return *bios_return; 2198c2ecf20Sopenharmony_ci int actual_outsize; 2208c2ecf20Sopenharmony_ci union acpi_object *obj; 2218c2ecf20Sopenharmony_ci struct bios_args args = { 2228c2ecf20Sopenharmony_ci .signature = 0x55434553, 2238c2ecf20Sopenharmony_ci .command = command, 2248c2ecf20Sopenharmony_ci .commandtype = query, 2258c2ecf20Sopenharmony_ci .datasize = insize, 2268c2ecf20Sopenharmony_ci .data = { 0 }, 2278c2ecf20Sopenharmony_ci }; 2288c2ecf20Sopenharmony_ci struct acpi_buffer input = { sizeof(struct bios_args), &args }; 2298c2ecf20Sopenharmony_ci struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 2308c2ecf20Sopenharmony_ci int ret = 0; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci mid = encode_outsize_for_pvsz(outsize); 2338c2ecf20Sopenharmony_ci if (WARN_ON(mid < 0)) 2348c2ecf20Sopenharmony_ci return mid; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (WARN_ON(insize > sizeof(args.data))) 2378c2ecf20Sopenharmony_ci return -EINVAL; 2388c2ecf20Sopenharmony_ci memcpy(&args.data[0], buffer, insize); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci wmi_evaluate_method(HPWMI_BIOS_GUID, 0, mid, &input, &output); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci obj = output.pointer; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (!obj) 2458c2ecf20Sopenharmony_ci return -EINVAL; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (obj->type != ACPI_TYPE_BUFFER) { 2488c2ecf20Sopenharmony_ci ret = -EINVAL; 2498c2ecf20Sopenharmony_ci goto out_free; 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci bios_return = (struct bios_return *)obj->buffer.pointer; 2538c2ecf20Sopenharmony_ci ret = bios_return->return_code; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (ret) { 2568c2ecf20Sopenharmony_ci if (ret != HPWMI_RET_UNKNOWN_COMMAND && 2578c2ecf20Sopenharmony_ci ret != HPWMI_RET_UNKNOWN_CMDTYPE) 2588c2ecf20Sopenharmony_ci pr_warn("query 0x%x returned error 0x%x\n", query, ret); 2598c2ecf20Sopenharmony_ci goto out_free; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* Ignore output data of zero size */ 2638c2ecf20Sopenharmony_ci if (!outsize) 2648c2ecf20Sopenharmony_ci goto out_free; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); 2678c2ecf20Sopenharmony_ci memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); 2688c2ecf20Sopenharmony_ci memset(buffer + actual_outsize, 0, outsize - actual_outsize); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ciout_free: 2718c2ecf20Sopenharmony_ci kfree(obj); 2728c2ecf20Sopenharmony_ci return ret; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic int hp_wmi_read_int(int query) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int val = 0, ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci ret = hp_wmi_perform_query(query, HPWMI_READ, &val, 2808c2ecf20Sopenharmony_ci sizeof(val), sizeof(val)); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (ret) 2838c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EINVAL; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return val; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic int hp_wmi_hw_state(int mask) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (state < 0) 2938c2ecf20Sopenharmony_ci return state; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return !!(state & mask); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int __init hp_wmi_bios_2008_later(void) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci int state = 0; 3018c2ecf20Sopenharmony_ci int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, HPWMI_READ, &state, 3028c2ecf20Sopenharmony_ci sizeof(state), sizeof(state)); 3038c2ecf20Sopenharmony_ci if (!ret) 3048c2ecf20Sopenharmony_ci return 1; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic int __init hp_wmi_bios_2009_later(void) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci u8 state[128]; 3128c2ecf20Sopenharmony_ci int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state, 3138c2ecf20Sopenharmony_ci sizeof(state), sizeof(state)); 3148c2ecf20Sopenharmony_ci if (!ret) 3158c2ecf20Sopenharmony_ci return 1; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int __init hp_wmi_enable_hotkeys(void) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci int value = 0x6e; 3238c2ecf20Sopenharmony_ci int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, HPWMI_WRITE, &value, 3248c2ecf20Sopenharmony_ci sizeof(value), 0); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return ret <= 0 ? ret : -EINVAL; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int hp_wmi_set_block(void *data, bool blocked) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci enum hp_wmi_radio r = (enum hp_wmi_radio) data; 3328c2ecf20Sopenharmony_ci int query = BIT(r + 8) | ((!blocked) << r); 3338c2ecf20Sopenharmony_ci int ret; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, 3368c2ecf20Sopenharmony_ci &query, sizeof(query), 0); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return ret <= 0 ? ret : -EINVAL; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic const struct rfkill_ops hp_wmi_rfkill_ops = { 3428c2ecf20Sopenharmony_ci .set_block = hp_wmi_set_block, 3438c2ecf20Sopenharmony_ci}; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic bool hp_wmi_get_sw_state(enum hp_wmi_radio r) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci int mask = 0x200 << (r * 8); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* TBD: Pass error */ 3528c2ecf20Sopenharmony_ci WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY"); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return !(wireless & mask); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic bool hp_wmi_get_hw_state(enum hp_wmi_radio r) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci int mask = 0x800 << (r * 8); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* TBD: Pass error */ 3648c2ecf20Sopenharmony_ci WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY"); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return !(wireless & mask); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int hp_wmi_rfkill2_set_block(void *data, bool blocked) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci int rfkill_id = (int)(long)data; 3728c2ecf20Sopenharmony_ci char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked }; 3738c2ecf20Sopenharmony_ci int ret; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ret = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_WRITE, 3768c2ecf20Sopenharmony_ci buffer, sizeof(buffer), 0); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return ret <= 0 ? ret : -EINVAL; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic const struct rfkill_ops hp_wmi_rfkill2_ops = { 3828c2ecf20Sopenharmony_ci .set_block = hp_wmi_rfkill2_set_block, 3838c2ecf20Sopenharmony_ci}; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int hp_wmi_rfkill2_refresh(void) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct bios_rfkill2_state state; 3888c2ecf20Sopenharmony_ci int err, i; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state, 3918c2ecf20Sopenharmony_ci sizeof(state), sizeof(state)); 3928c2ecf20Sopenharmony_ci if (err) 3938c2ecf20Sopenharmony_ci return err; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci for (i = 0; i < rfkill2_count; i++) { 3968c2ecf20Sopenharmony_ci int num = rfkill2[i].num; 3978c2ecf20Sopenharmony_ci struct bios_rfkill2_device_state *devstate; 3988c2ecf20Sopenharmony_ci devstate = &state.device[num]; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (num >= state.count || 4018c2ecf20Sopenharmony_ci devstate->rfkill_id != rfkill2[i].id) { 4028c2ecf20Sopenharmony_ci pr_warn("power configuration of the wireless devices unexpectedly changed\n"); 4038c2ecf20Sopenharmony_ci continue; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci rfkill_set_states(rfkill2[i].rfkill, 4078c2ecf20Sopenharmony_ci IS_SWBLOCKED(devstate->power), 4088c2ecf20Sopenharmony_ci IS_HWBLOCKED(devstate->power)); 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci return 0; 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cistatic ssize_t display_show(struct device *dev, struct device_attribute *attr, 4158c2ecf20Sopenharmony_ci char *buf) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY); 4188c2ecf20Sopenharmony_ci if (value < 0) 4198c2ecf20Sopenharmony_ci return value; 4208c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", value); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic ssize_t hddtemp_show(struct device *dev, struct device_attribute *attr, 4248c2ecf20Sopenharmony_ci char *buf) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY); 4278c2ecf20Sopenharmony_ci if (value < 0) 4288c2ecf20Sopenharmony_ci return value; 4298c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", value); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic ssize_t als_show(struct device *dev, struct device_attribute *attr, 4338c2ecf20Sopenharmony_ci char *buf) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci int value = hp_wmi_read_int(HPWMI_ALS_QUERY); 4368c2ecf20Sopenharmony_ci if (value < 0) 4378c2ecf20Sopenharmony_ci return value; 4388c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", value); 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic ssize_t dock_show(struct device *dev, struct device_attribute *attr, 4428c2ecf20Sopenharmony_ci char *buf) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci int value = hp_wmi_hw_state(HPWMI_DOCK_MASK); 4458c2ecf20Sopenharmony_ci if (value < 0) 4468c2ecf20Sopenharmony_ci return value; 4478c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", value); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic ssize_t tablet_show(struct device *dev, struct device_attribute *attr, 4518c2ecf20Sopenharmony_ci char *buf) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci int value = hp_wmi_hw_state(HPWMI_TABLET_MASK); 4548c2ecf20Sopenharmony_ci if (value < 0) 4558c2ecf20Sopenharmony_ci return value; 4568c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", value); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic ssize_t postcode_show(struct device *dev, struct device_attribute *attr, 4608c2ecf20Sopenharmony_ci char *buf) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci /* Get the POST error code of previous boot failure. */ 4638c2ecf20Sopenharmony_ci int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY); 4648c2ecf20Sopenharmony_ci if (value < 0) 4658c2ecf20Sopenharmony_ci return value; 4668c2ecf20Sopenharmony_ci return sprintf(buf, "0x%x\n", value); 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic ssize_t als_store(struct device *dev, struct device_attribute *attr, 4708c2ecf20Sopenharmony_ci const char *buf, size_t count) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci u32 tmp; 4738c2ecf20Sopenharmony_ci int ret; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci ret = kstrtou32(buf, 10, &tmp); 4768c2ecf20Sopenharmony_ci if (ret) 4778c2ecf20Sopenharmony_ci return ret; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_WRITE, &tmp, 4808c2ecf20Sopenharmony_ci sizeof(tmp), sizeof(tmp)); 4818c2ecf20Sopenharmony_ci if (ret) 4828c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EINVAL; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return count; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_cistatic ssize_t postcode_store(struct device *dev, struct device_attribute *attr, 4888c2ecf20Sopenharmony_ci const char *buf, size_t count) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci u32 tmp = 1; 4918c2ecf20Sopenharmony_ci bool clear; 4928c2ecf20Sopenharmony_ci int ret; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci ret = kstrtobool(buf, &clear); 4958c2ecf20Sopenharmony_ci if (ret) 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (clear == false) 4998c2ecf20Sopenharmony_ci return -EINVAL; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* Clear the POST error code. It is kept until until cleared. */ 5028c2ecf20Sopenharmony_ci ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp, 5038c2ecf20Sopenharmony_ci sizeof(tmp), sizeof(tmp)); 5048c2ecf20Sopenharmony_ci if (ret) 5058c2ecf20Sopenharmony_ci return ret < 0 ? ret : -EINVAL; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return count; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(display); 5118c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(hddtemp); 5128c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(als); 5138c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(dock); 5148c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(tablet); 5158c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RW(postcode); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic struct attribute *hp_wmi_attrs[] = { 5188c2ecf20Sopenharmony_ci &dev_attr_display.attr, 5198c2ecf20Sopenharmony_ci &dev_attr_hddtemp.attr, 5208c2ecf20Sopenharmony_ci &dev_attr_als.attr, 5218c2ecf20Sopenharmony_ci &dev_attr_dock.attr, 5228c2ecf20Sopenharmony_ci &dev_attr_tablet.attr, 5238c2ecf20Sopenharmony_ci &dev_attr_postcode.attr, 5248c2ecf20Sopenharmony_ci NULL, 5258c2ecf20Sopenharmony_ci}; 5268c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(hp_wmi); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic void hp_wmi_notify(u32 value, void *context) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 5318c2ecf20Sopenharmony_ci u32 event_id, event_data; 5328c2ecf20Sopenharmony_ci union acpi_object *obj; 5338c2ecf20Sopenharmony_ci acpi_status status; 5348c2ecf20Sopenharmony_ci u32 *location; 5358c2ecf20Sopenharmony_ci int key_code; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci status = wmi_get_event_data(value, &response); 5388c2ecf20Sopenharmony_ci if (status != AE_OK) { 5398c2ecf20Sopenharmony_ci pr_info("bad event status 0x%x\n", status); 5408c2ecf20Sopenharmony_ci return; 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci obj = (union acpi_object *)response.pointer; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!obj) 5468c2ecf20Sopenharmony_ci return; 5478c2ecf20Sopenharmony_ci if (obj->type != ACPI_TYPE_BUFFER) { 5488c2ecf20Sopenharmony_ci pr_info("Unknown response received %d\n", obj->type); 5498c2ecf20Sopenharmony_ci kfree(obj); 5508c2ecf20Sopenharmony_ci return; 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* 5548c2ecf20Sopenharmony_ci * Depending on ACPI version the concatenation of id and event data 5558c2ecf20Sopenharmony_ci * inside _WED function will result in a 8 or 16 byte buffer. 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_ci location = (u32 *)obj->buffer.pointer; 5588c2ecf20Sopenharmony_ci if (obj->buffer.length == 8) { 5598c2ecf20Sopenharmony_ci event_id = *location; 5608c2ecf20Sopenharmony_ci event_data = *(location + 1); 5618c2ecf20Sopenharmony_ci } else if (obj->buffer.length == 16) { 5628c2ecf20Sopenharmony_ci event_id = *location; 5638c2ecf20Sopenharmony_ci event_data = *(location + 2); 5648c2ecf20Sopenharmony_ci } else { 5658c2ecf20Sopenharmony_ci pr_info("Unknown buffer length %d\n", obj->buffer.length); 5668c2ecf20Sopenharmony_ci kfree(obj); 5678c2ecf20Sopenharmony_ci return; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci kfree(obj); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci switch (event_id) { 5728c2ecf20Sopenharmony_ci case HPWMI_DOCK_EVENT: 5738c2ecf20Sopenharmony_ci if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit)) 5748c2ecf20Sopenharmony_ci input_report_switch(hp_wmi_input_dev, SW_DOCK, 5758c2ecf20Sopenharmony_ci hp_wmi_hw_state(HPWMI_DOCK_MASK)); 5768c2ecf20Sopenharmony_ci if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit)) 5778c2ecf20Sopenharmony_ci input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 5788c2ecf20Sopenharmony_ci hp_wmi_hw_state(HPWMI_TABLET_MASK)); 5798c2ecf20Sopenharmony_ci input_sync(hp_wmi_input_dev); 5808c2ecf20Sopenharmony_ci break; 5818c2ecf20Sopenharmony_ci case HPWMI_PARK_HDD: 5828c2ecf20Sopenharmony_ci break; 5838c2ecf20Sopenharmony_ci case HPWMI_SMART_ADAPTER: 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci case HPWMI_BEZEL_BUTTON: 5868c2ecf20Sopenharmony_ci key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY); 5878c2ecf20Sopenharmony_ci if (key_code < 0) 5888c2ecf20Sopenharmony_ci break; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (!sparse_keymap_report_event(hp_wmi_input_dev, 5918c2ecf20Sopenharmony_ci key_code, 1, true)) 5928c2ecf20Sopenharmony_ci pr_info("Unknown key code - 0x%x\n", key_code); 5938c2ecf20Sopenharmony_ci break; 5948c2ecf20Sopenharmony_ci case HPWMI_WIRELESS: 5958c2ecf20Sopenharmony_ci if (rfkill2_count) { 5968c2ecf20Sopenharmony_ci hp_wmi_rfkill2_refresh(); 5978c2ecf20Sopenharmony_ci break; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (wifi_rfkill) 6018c2ecf20Sopenharmony_ci rfkill_set_states(wifi_rfkill, 6028c2ecf20Sopenharmony_ci hp_wmi_get_sw_state(HPWMI_WIFI), 6038c2ecf20Sopenharmony_ci hp_wmi_get_hw_state(HPWMI_WIFI)); 6048c2ecf20Sopenharmony_ci if (bluetooth_rfkill) 6058c2ecf20Sopenharmony_ci rfkill_set_states(bluetooth_rfkill, 6068c2ecf20Sopenharmony_ci hp_wmi_get_sw_state(HPWMI_BLUETOOTH), 6078c2ecf20Sopenharmony_ci hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); 6088c2ecf20Sopenharmony_ci if (wwan_rfkill) 6098c2ecf20Sopenharmony_ci rfkill_set_states(wwan_rfkill, 6108c2ecf20Sopenharmony_ci hp_wmi_get_sw_state(HPWMI_WWAN), 6118c2ecf20Sopenharmony_ci hp_wmi_get_hw_state(HPWMI_WWAN)); 6128c2ecf20Sopenharmony_ci break; 6138c2ecf20Sopenharmony_ci case HPWMI_CPU_BATTERY_THROTTLE: 6148c2ecf20Sopenharmony_ci pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n"); 6158c2ecf20Sopenharmony_ci break; 6168c2ecf20Sopenharmony_ci case HPWMI_LOCK_SWITCH: 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci case HPWMI_LID_SWITCH: 6198c2ecf20Sopenharmony_ci break; 6208c2ecf20Sopenharmony_ci case HPWMI_SCREEN_ROTATION: 6218c2ecf20Sopenharmony_ci break; 6228c2ecf20Sopenharmony_ci case HPWMI_COOLSENSE_SYSTEM_MOBILE: 6238c2ecf20Sopenharmony_ci break; 6248c2ecf20Sopenharmony_ci case HPWMI_COOLSENSE_SYSTEM_HOT: 6258c2ecf20Sopenharmony_ci break; 6268c2ecf20Sopenharmony_ci case HPWMI_PROXIMITY_SENSOR: 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci case HPWMI_BACKLIT_KB_BRIGHTNESS: 6298c2ecf20Sopenharmony_ci break; 6308c2ecf20Sopenharmony_ci case HPWMI_PEAKSHIFT_PERIOD: 6318c2ecf20Sopenharmony_ci break; 6328c2ecf20Sopenharmony_ci case HPWMI_BATTERY_CHARGE_PERIOD: 6338c2ecf20Sopenharmony_ci break; 6348c2ecf20Sopenharmony_ci case HPWMI_SANITIZATION_MODE: 6358c2ecf20Sopenharmony_ci break; 6368c2ecf20Sopenharmony_ci case HPWMI_SMART_EXPERIENCE_APP: 6378c2ecf20Sopenharmony_ci break; 6388c2ecf20Sopenharmony_ci default: 6398c2ecf20Sopenharmony_ci pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data); 6408c2ecf20Sopenharmony_ci break; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic int __init hp_wmi_input_setup(void) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci acpi_status status; 6478c2ecf20Sopenharmony_ci int err, val; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci hp_wmi_input_dev = input_allocate_device(); 6508c2ecf20Sopenharmony_ci if (!hp_wmi_input_dev) 6518c2ecf20Sopenharmony_ci return -ENOMEM; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci hp_wmi_input_dev->name = "HP WMI hotkeys"; 6548c2ecf20Sopenharmony_ci hp_wmi_input_dev->phys = "wmi/input0"; 6558c2ecf20Sopenharmony_ci hp_wmi_input_dev->id.bustype = BUS_HOST; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci __set_bit(EV_SW, hp_wmi_input_dev->evbit); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* Dock */ 6608c2ecf20Sopenharmony_ci val = hp_wmi_hw_state(HPWMI_DOCK_MASK); 6618c2ecf20Sopenharmony_ci if (!(val < 0)) { 6628c2ecf20Sopenharmony_ci __set_bit(SW_DOCK, hp_wmi_input_dev->swbit); 6638c2ecf20Sopenharmony_ci input_report_switch(hp_wmi_input_dev, SW_DOCK, val); 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci /* Tablet mode */ 6678c2ecf20Sopenharmony_ci if (enable_tablet_mode_sw > 0) { 6688c2ecf20Sopenharmony_ci val = hp_wmi_hw_state(HPWMI_TABLET_MASK); 6698c2ecf20Sopenharmony_ci if (val >= 0) { 6708c2ecf20Sopenharmony_ci __set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit); 6718c2ecf20Sopenharmony_ci input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val); 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL); 6768c2ecf20Sopenharmony_ci if (err) 6778c2ecf20Sopenharmony_ci goto err_free_dev; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* Set initial hardware state */ 6808c2ecf20Sopenharmony_ci input_sync(hp_wmi_input_dev); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later()) 6838c2ecf20Sopenharmony_ci hp_wmi_enable_hotkeys(); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL); 6868c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 6878c2ecf20Sopenharmony_ci err = -EIO; 6888c2ecf20Sopenharmony_ci goto err_free_dev; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci err = input_register_device(hp_wmi_input_dev); 6928c2ecf20Sopenharmony_ci if (err) 6938c2ecf20Sopenharmony_ci goto err_uninstall_notifier; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return 0; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci err_uninstall_notifier: 6988c2ecf20Sopenharmony_ci wmi_remove_notify_handler(HPWMI_EVENT_GUID); 6998c2ecf20Sopenharmony_ci err_free_dev: 7008c2ecf20Sopenharmony_ci input_free_device(hp_wmi_input_dev); 7018c2ecf20Sopenharmony_ci return err; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic void hp_wmi_input_destroy(void) 7058c2ecf20Sopenharmony_ci{ 7068c2ecf20Sopenharmony_ci wmi_remove_notify_handler(HPWMI_EVENT_GUID); 7078c2ecf20Sopenharmony_ci input_unregister_device(hp_wmi_input_dev); 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic int __init hp_wmi_rfkill_setup(struct platform_device *device) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci int err, wireless; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY); 7158c2ecf20Sopenharmony_ci if (wireless < 0) 7168c2ecf20Sopenharmony_ci return wireless; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &wireless, 7198c2ecf20Sopenharmony_ci sizeof(wireless), 0); 7208c2ecf20Sopenharmony_ci if (err) 7218c2ecf20Sopenharmony_ci return err; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (wireless & 0x1) { 7248c2ecf20Sopenharmony_ci wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, 7258c2ecf20Sopenharmony_ci RFKILL_TYPE_WLAN, 7268c2ecf20Sopenharmony_ci &hp_wmi_rfkill_ops, 7278c2ecf20Sopenharmony_ci (void *) HPWMI_WIFI); 7288c2ecf20Sopenharmony_ci if (!wifi_rfkill) 7298c2ecf20Sopenharmony_ci return -ENOMEM; 7308c2ecf20Sopenharmony_ci rfkill_init_sw_state(wifi_rfkill, 7318c2ecf20Sopenharmony_ci hp_wmi_get_sw_state(HPWMI_WIFI)); 7328c2ecf20Sopenharmony_ci rfkill_set_hw_state(wifi_rfkill, 7338c2ecf20Sopenharmony_ci hp_wmi_get_hw_state(HPWMI_WIFI)); 7348c2ecf20Sopenharmony_ci err = rfkill_register(wifi_rfkill); 7358c2ecf20Sopenharmony_ci if (err) 7368c2ecf20Sopenharmony_ci goto register_wifi_error; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (wireless & 0x2) { 7408c2ecf20Sopenharmony_ci bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, 7418c2ecf20Sopenharmony_ci RFKILL_TYPE_BLUETOOTH, 7428c2ecf20Sopenharmony_ci &hp_wmi_rfkill_ops, 7438c2ecf20Sopenharmony_ci (void *) HPWMI_BLUETOOTH); 7448c2ecf20Sopenharmony_ci if (!bluetooth_rfkill) { 7458c2ecf20Sopenharmony_ci err = -ENOMEM; 7468c2ecf20Sopenharmony_ci goto register_bluetooth_error; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci rfkill_init_sw_state(bluetooth_rfkill, 7498c2ecf20Sopenharmony_ci hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); 7508c2ecf20Sopenharmony_ci rfkill_set_hw_state(bluetooth_rfkill, 7518c2ecf20Sopenharmony_ci hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); 7528c2ecf20Sopenharmony_ci err = rfkill_register(bluetooth_rfkill); 7538c2ecf20Sopenharmony_ci if (err) 7548c2ecf20Sopenharmony_ci goto register_bluetooth_error; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci if (wireless & 0x4) { 7588c2ecf20Sopenharmony_ci wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, 7598c2ecf20Sopenharmony_ci RFKILL_TYPE_WWAN, 7608c2ecf20Sopenharmony_ci &hp_wmi_rfkill_ops, 7618c2ecf20Sopenharmony_ci (void *) HPWMI_WWAN); 7628c2ecf20Sopenharmony_ci if (!wwan_rfkill) { 7638c2ecf20Sopenharmony_ci err = -ENOMEM; 7648c2ecf20Sopenharmony_ci goto register_wwan_error; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci rfkill_init_sw_state(wwan_rfkill, 7678c2ecf20Sopenharmony_ci hp_wmi_get_sw_state(HPWMI_WWAN)); 7688c2ecf20Sopenharmony_ci rfkill_set_hw_state(wwan_rfkill, 7698c2ecf20Sopenharmony_ci hp_wmi_get_hw_state(HPWMI_WWAN)); 7708c2ecf20Sopenharmony_ci err = rfkill_register(wwan_rfkill); 7718c2ecf20Sopenharmony_ci if (err) 7728c2ecf20Sopenharmony_ci goto register_wwan_error; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci return 0; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ciregister_wwan_error: 7788c2ecf20Sopenharmony_ci rfkill_destroy(wwan_rfkill); 7798c2ecf20Sopenharmony_ci wwan_rfkill = NULL; 7808c2ecf20Sopenharmony_ci if (bluetooth_rfkill) 7818c2ecf20Sopenharmony_ci rfkill_unregister(bluetooth_rfkill); 7828c2ecf20Sopenharmony_ciregister_bluetooth_error: 7838c2ecf20Sopenharmony_ci rfkill_destroy(bluetooth_rfkill); 7848c2ecf20Sopenharmony_ci bluetooth_rfkill = NULL; 7858c2ecf20Sopenharmony_ci if (wifi_rfkill) 7868c2ecf20Sopenharmony_ci rfkill_unregister(wifi_rfkill); 7878c2ecf20Sopenharmony_ciregister_wifi_error: 7888c2ecf20Sopenharmony_ci rfkill_destroy(wifi_rfkill); 7898c2ecf20Sopenharmony_ci wifi_rfkill = NULL; 7908c2ecf20Sopenharmony_ci return err; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int __init hp_wmi_rfkill2_setup(struct platform_device *device) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci struct bios_rfkill2_state state; 7968c2ecf20Sopenharmony_ci int err, i; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state, 7998c2ecf20Sopenharmony_ci sizeof(state), sizeof(state)); 8008c2ecf20Sopenharmony_ci if (err) 8018c2ecf20Sopenharmony_ci return err < 0 ? err : -EINVAL; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (state.count > HPWMI_MAX_RFKILL2_DEVICES) { 8048c2ecf20Sopenharmony_ci pr_warn("unable to parse 0x1b query output\n"); 8058c2ecf20Sopenharmony_ci return -EINVAL; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci for (i = 0; i < state.count; i++) { 8098c2ecf20Sopenharmony_ci struct rfkill *rfkill; 8108c2ecf20Sopenharmony_ci enum rfkill_type type; 8118c2ecf20Sopenharmony_ci char *name; 8128c2ecf20Sopenharmony_ci switch (state.device[i].radio_type) { 8138c2ecf20Sopenharmony_ci case HPWMI_WIFI: 8148c2ecf20Sopenharmony_ci type = RFKILL_TYPE_WLAN; 8158c2ecf20Sopenharmony_ci name = "hp-wifi"; 8168c2ecf20Sopenharmony_ci break; 8178c2ecf20Sopenharmony_ci case HPWMI_BLUETOOTH: 8188c2ecf20Sopenharmony_ci type = RFKILL_TYPE_BLUETOOTH; 8198c2ecf20Sopenharmony_ci name = "hp-bluetooth"; 8208c2ecf20Sopenharmony_ci break; 8218c2ecf20Sopenharmony_ci case HPWMI_WWAN: 8228c2ecf20Sopenharmony_ci type = RFKILL_TYPE_WWAN; 8238c2ecf20Sopenharmony_ci name = "hp-wwan"; 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci case HPWMI_GPS: 8268c2ecf20Sopenharmony_ci type = RFKILL_TYPE_GPS; 8278c2ecf20Sopenharmony_ci name = "hp-gps"; 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci default: 8308c2ecf20Sopenharmony_ci pr_warn("unknown device type 0x%x\n", 8318c2ecf20Sopenharmony_ci state.device[i].radio_type); 8328c2ecf20Sopenharmony_ci continue; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci if (!state.device[i].vendor_id) { 8368c2ecf20Sopenharmony_ci pr_warn("zero device %d while %d reported\n", 8378c2ecf20Sopenharmony_ci i, state.count); 8388c2ecf20Sopenharmony_ci continue; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci rfkill = rfkill_alloc(name, &device->dev, type, 8428c2ecf20Sopenharmony_ci &hp_wmi_rfkill2_ops, (void *)(long)i); 8438c2ecf20Sopenharmony_ci if (!rfkill) { 8448c2ecf20Sopenharmony_ci err = -ENOMEM; 8458c2ecf20Sopenharmony_ci goto fail; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci rfkill2[rfkill2_count].id = state.device[i].rfkill_id; 8498c2ecf20Sopenharmony_ci rfkill2[rfkill2_count].num = i; 8508c2ecf20Sopenharmony_ci rfkill2[rfkill2_count].rfkill = rfkill; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci rfkill_init_sw_state(rfkill, 8538c2ecf20Sopenharmony_ci IS_SWBLOCKED(state.device[i].power)); 8548c2ecf20Sopenharmony_ci rfkill_set_hw_state(rfkill, 8558c2ecf20Sopenharmony_ci IS_HWBLOCKED(state.device[i].power)); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (!(state.device[i].power & HPWMI_POWER_BIOS)) 8588c2ecf20Sopenharmony_ci pr_info("device %s blocked by BIOS\n", name); 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci err = rfkill_register(rfkill); 8618c2ecf20Sopenharmony_ci if (err) { 8628c2ecf20Sopenharmony_ci rfkill_destroy(rfkill); 8638c2ecf20Sopenharmony_ci goto fail; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci rfkill2_count++; 8678c2ecf20Sopenharmony_ci } 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci return 0; 8708c2ecf20Sopenharmony_cifail: 8718c2ecf20Sopenharmony_ci for (; rfkill2_count > 0; rfkill2_count--) { 8728c2ecf20Sopenharmony_ci rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill); 8738c2ecf20Sopenharmony_ci rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill); 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci return err; 8768c2ecf20Sopenharmony_ci} 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_cistatic int thermal_policy_setup(struct platform_device *device) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci int err, tp; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci tp = hp_wmi_read_int(HPWMI_THERMAL_POLICY_QUERY); 8838c2ecf20Sopenharmony_ci if (tp < 0) 8848c2ecf20Sopenharmony_ci return tp; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* 8878c2ecf20Sopenharmony_ci * call thermal policy write command to ensure that the firmware correctly 8888c2ecf20Sopenharmony_ci * sets the OEM variables for the DPTF 8898c2ecf20Sopenharmony_ci */ 8908c2ecf20Sopenharmony_ci err = hp_wmi_perform_query(HPWMI_THERMAL_POLICY_QUERY, HPWMI_WRITE, &tp, 8918c2ecf20Sopenharmony_ci sizeof(tp), 0); 8928c2ecf20Sopenharmony_ci if (err) 8938c2ecf20Sopenharmony_ci return err; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return 0; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic int __init hp_wmi_bios_setup(struct platform_device *device) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci /* clear detected rfkill devices */ 9018c2ecf20Sopenharmony_ci wifi_rfkill = NULL; 9028c2ecf20Sopenharmony_ci bluetooth_rfkill = NULL; 9038c2ecf20Sopenharmony_ci wwan_rfkill = NULL; 9048c2ecf20Sopenharmony_ci rfkill2_count = 0; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* 9078c2ecf20Sopenharmony_ci * In pre-2009 BIOS, command 1Bh return 0x4 to indicate that 9088c2ecf20Sopenharmony_ci * BIOS no longer controls the power for the wireless 9098c2ecf20Sopenharmony_ci * devices. All features supported by this command will no 9108c2ecf20Sopenharmony_ci * longer be supported. 9118c2ecf20Sopenharmony_ci */ 9128c2ecf20Sopenharmony_ci if (!hp_wmi_bios_2009_later()) { 9138c2ecf20Sopenharmony_ci if (hp_wmi_rfkill_setup(device)) 9148c2ecf20Sopenharmony_ci hp_wmi_rfkill2_setup(device); 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci thermal_policy_setup(device); 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci return 0; 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic int __exit hp_wmi_bios_remove(struct platform_device *device) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci int i; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci for (i = 0; i < rfkill2_count; i++) { 9278c2ecf20Sopenharmony_ci rfkill_unregister(rfkill2[i].rfkill); 9288c2ecf20Sopenharmony_ci rfkill_destroy(rfkill2[i].rfkill); 9298c2ecf20Sopenharmony_ci } 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if (wifi_rfkill) { 9328c2ecf20Sopenharmony_ci rfkill_unregister(wifi_rfkill); 9338c2ecf20Sopenharmony_ci rfkill_destroy(wifi_rfkill); 9348c2ecf20Sopenharmony_ci } 9358c2ecf20Sopenharmony_ci if (bluetooth_rfkill) { 9368c2ecf20Sopenharmony_ci rfkill_unregister(bluetooth_rfkill); 9378c2ecf20Sopenharmony_ci rfkill_destroy(bluetooth_rfkill); 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci if (wwan_rfkill) { 9408c2ecf20Sopenharmony_ci rfkill_unregister(wwan_rfkill); 9418c2ecf20Sopenharmony_ci rfkill_destroy(wwan_rfkill); 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int hp_wmi_resume_handler(struct device *device) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci /* 9508c2ecf20Sopenharmony_ci * Hardware state may have changed while suspended, so trigger 9518c2ecf20Sopenharmony_ci * input events for the current state. As this is a switch, 9528c2ecf20Sopenharmony_ci * the input layer will only actually pass it on if the state 9538c2ecf20Sopenharmony_ci * changed. 9548c2ecf20Sopenharmony_ci */ 9558c2ecf20Sopenharmony_ci if (hp_wmi_input_dev) { 9568c2ecf20Sopenharmony_ci if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit)) 9578c2ecf20Sopenharmony_ci input_report_switch(hp_wmi_input_dev, SW_DOCK, 9588c2ecf20Sopenharmony_ci hp_wmi_hw_state(HPWMI_DOCK_MASK)); 9598c2ecf20Sopenharmony_ci if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit)) 9608c2ecf20Sopenharmony_ci input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 9618c2ecf20Sopenharmony_ci hp_wmi_hw_state(HPWMI_TABLET_MASK)); 9628c2ecf20Sopenharmony_ci input_sync(hp_wmi_input_dev); 9638c2ecf20Sopenharmony_ci } 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (rfkill2_count) 9668c2ecf20Sopenharmony_ci hp_wmi_rfkill2_refresh(); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci if (wifi_rfkill) 9698c2ecf20Sopenharmony_ci rfkill_set_states(wifi_rfkill, 9708c2ecf20Sopenharmony_ci hp_wmi_get_sw_state(HPWMI_WIFI), 9718c2ecf20Sopenharmony_ci hp_wmi_get_hw_state(HPWMI_WIFI)); 9728c2ecf20Sopenharmony_ci if (bluetooth_rfkill) 9738c2ecf20Sopenharmony_ci rfkill_set_states(bluetooth_rfkill, 9748c2ecf20Sopenharmony_ci hp_wmi_get_sw_state(HPWMI_BLUETOOTH), 9758c2ecf20Sopenharmony_ci hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); 9768c2ecf20Sopenharmony_ci if (wwan_rfkill) 9778c2ecf20Sopenharmony_ci rfkill_set_states(wwan_rfkill, 9788c2ecf20Sopenharmony_ci hp_wmi_get_sw_state(HPWMI_WWAN), 9798c2ecf20Sopenharmony_ci hp_wmi_get_hw_state(HPWMI_WWAN)); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci return 0; 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistatic const struct dev_pm_ops hp_wmi_pm_ops = { 9858c2ecf20Sopenharmony_ci .resume = hp_wmi_resume_handler, 9868c2ecf20Sopenharmony_ci .restore = hp_wmi_resume_handler, 9878c2ecf20Sopenharmony_ci}; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_cistatic struct platform_driver hp_wmi_driver = { 9908c2ecf20Sopenharmony_ci .driver = { 9918c2ecf20Sopenharmony_ci .name = "hp-wmi", 9928c2ecf20Sopenharmony_ci .pm = &hp_wmi_pm_ops, 9938c2ecf20Sopenharmony_ci .dev_groups = hp_wmi_groups, 9948c2ecf20Sopenharmony_ci }, 9958c2ecf20Sopenharmony_ci .remove = __exit_p(hp_wmi_bios_remove), 9968c2ecf20Sopenharmony_ci}; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic int __init hp_wmi_init(void) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); 10018c2ecf20Sopenharmony_ci int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); 10028c2ecf20Sopenharmony_ci int err; 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_ci if (!bios_capable && !event_capable) 10058c2ecf20Sopenharmony_ci return -ENODEV; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci if (event_capable) { 10088c2ecf20Sopenharmony_ci err = hp_wmi_input_setup(); 10098c2ecf20Sopenharmony_ci if (err) 10108c2ecf20Sopenharmony_ci return err; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (bios_capable) { 10148c2ecf20Sopenharmony_ci hp_wmi_platform_dev = 10158c2ecf20Sopenharmony_ci platform_device_register_simple("hp-wmi", -1, NULL, 0); 10168c2ecf20Sopenharmony_ci if (IS_ERR(hp_wmi_platform_dev)) { 10178c2ecf20Sopenharmony_ci err = PTR_ERR(hp_wmi_platform_dev); 10188c2ecf20Sopenharmony_ci goto err_destroy_input; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup); 10228c2ecf20Sopenharmony_ci if (err) 10238c2ecf20Sopenharmony_ci goto err_unregister_device; 10248c2ecf20Sopenharmony_ci } 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci return 0; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_cierr_unregister_device: 10298c2ecf20Sopenharmony_ci platform_device_unregister(hp_wmi_platform_dev); 10308c2ecf20Sopenharmony_cierr_destroy_input: 10318c2ecf20Sopenharmony_ci if (event_capable) 10328c2ecf20Sopenharmony_ci hp_wmi_input_destroy(); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci return err; 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_cimodule_init(hp_wmi_init); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic void __exit hp_wmi_exit(void) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci if (wmi_has_guid(HPWMI_EVENT_GUID)) 10418c2ecf20Sopenharmony_ci hp_wmi_input_destroy(); 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (hp_wmi_platform_dev) { 10448c2ecf20Sopenharmony_ci platform_device_unregister(hp_wmi_platform_dev); 10458c2ecf20Sopenharmony_ci platform_driver_unregister(&hp_wmi_driver); 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci} 10488c2ecf20Sopenharmony_cimodule_exit(hp_wmi_exit); 1049