18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Input layer to RF Kill interface connector 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2007 Dmitry Torokhov 68c2ecf20Sopenharmony_ci * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * If you ever run into a situation in which you have a SW_ type rfkill 98c2ecf20Sopenharmony_ci * input device, then you can revive code that was removed in the patch 108c2ecf20Sopenharmony_ci * "rfkill-input: remove unused code". 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/input.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 168c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/rfkill.h> 198c2ecf20Sopenharmony_ci#include <linux/sched.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "rfkill.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cienum rfkill_input_master_mode { 248c2ecf20Sopenharmony_ci RFKILL_INPUT_MASTER_UNLOCK = 0, 258c2ecf20Sopenharmony_ci RFKILL_INPUT_MASTER_RESTORE = 1, 268c2ecf20Sopenharmony_ci RFKILL_INPUT_MASTER_UNBLOCKALL = 2, 278c2ecf20Sopenharmony_ci NUM_RFKILL_INPUT_MASTER_MODES 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Delay (in ms) between consecutive switch ops */ 318c2ecf20Sopenharmony_ci#define RFKILL_OPS_DELAY 200 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic enum rfkill_input_master_mode rfkill_master_switch_mode = 348c2ecf20Sopenharmony_ci RFKILL_INPUT_MASTER_UNBLOCKALL; 358c2ecf20Sopenharmony_cimodule_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0); 368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(master_switch_mode, 378c2ecf20Sopenharmony_ci "SW_RFKILL_ALL ON should: 0=do nothing (only unlock); 1=restore; 2=unblock all"); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic spinlock_t rfkill_op_lock; 408c2ecf20Sopenharmony_cistatic bool rfkill_op_pending; 418c2ecf20Sopenharmony_cistatic unsigned long rfkill_sw_pending[BITS_TO_LONGS(NUM_RFKILL_TYPES)]; 428c2ecf20Sopenharmony_cistatic unsigned long rfkill_sw_state[BITS_TO_LONGS(NUM_RFKILL_TYPES)]; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cienum rfkill_sched_op { 458c2ecf20Sopenharmony_ci RFKILL_GLOBAL_OP_EPO = 0, 468c2ecf20Sopenharmony_ci RFKILL_GLOBAL_OP_RESTORE, 478c2ecf20Sopenharmony_ci RFKILL_GLOBAL_OP_UNLOCK, 488c2ecf20Sopenharmony_ci RFKILL_GLOBAL_OP_UNBLOCK, 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic enum rfkill_sched_op rfkill_master_switch_op; 528c2ecf20Sopenharmony_cistatic enum rfkill_sched_op rfkill_op; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void __rfkill_handle_global_op(enum rfkill_sched_op op) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci unsigned int i; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci switch (op) { 598c2ecf20Sopenharmony_ci case RFKILL_GLOBAL_OP_EPO: 608c2ecf20Sopenharmony_ci rfkill_epo(); 618c2ecf20Sopenharmony_ci break; 628c2ecf20Sopenharmony_ci case RFKILL_GLOBAL_OP_RESTORE: 638c2ecf20Sopenharmony_ci rfkill_restore_states(); 648c2ecf20Sopenharmony_ci break; 658c2ecf20Sopenharmony_ci case RFKILL_GLOBAL_OP_UNLOCK: 668c2ecf20Sopenharmony_ci rfkill_remove_epo_lock(); 678c2ecf20Sopenharmony_ci break; 688c2ecf20Sopenharmony_ci case RFKILL_GLOBAL_OP_UNBLOCK: 698c2ecf20Sopenharmony_ci rfkill_remove_epo_lock(); 708c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RFKILL_TYPES; i++) 718c2ecf20Sopenharmony_ci rfkill_switch_all(i, false); 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci default: 748c2ecf20Sopenharmony_ci /* memory corruption or bug, fail safely */ 758c2ecf20Sopenharmony_ci rfkill_epo(); 768c2ecf20Sopenharmony_ci WARN(1, "Unknown requested operation %d! " 778c2ecf20Sopenharmony_ci "rfkill Emergency Power Off activated\n", 788c2ecf20Sopenharmony_ci op); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic void __rfkill_handle_normal_op(const enum rfkill_type type, 838c2ecf20Sopenharmony_ci const bool complement) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci bool blocked; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci blocked = rfkill_get_global_sw_state(type); 888c2ecf20Sopenharmony_ci if (complement) 898c2ecf20Sopenharmony_ci blocked = !blocked; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci rfkill_switch_all(type, blocked); 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void rfkill_op_handler(struct work_struct *work) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci unsigned int i; 978c2ecf20Sopenharmony_ci bool c; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci spin_lock_irq(&rfkill_op_lock); 1008c2ecf20Sopenharmony_ci do { 1018c2ecf20Sopenharmony_ci if (rfkill_op_pending) { 1028c2ecf20Sopenharmony_ci enum rfkill_sched_op op = rfkill_op; 1038c2ecf20Sopenharmony_ci rfkill_op_pending = false; 1048c2ecf20Sopenharmony_ci memset(rfkill_sw_pending, 0, 1058c2ecf20Sopenharmony_ci sizeof(rfkill_sw_pending)); 1068c2ecf20Sopenharmony_ci spin_unlock_irq(&rfkill_op_lock); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci __rfkill_handle_global_op(op); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci spin_lock_irq(&rfkill_op_lock); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* 1138c2ecf20Sopenharmony_ci * handle global ops first -- during unlocked period 1148c2ecf20Sopenharmony_ci * we might have gotten a new global op. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci if (rfkill_op_pending) 1178c2ecf20Sopenharmony_ci continue; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (rfkill_is_epo_lock_active()) 1218c2ecf20Sopenharmony_ci continue; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RFKILL_TYPES; i++) { 1248c2ecf20Sopenharmony_ci if (__test_and_clear_bit(i, rfkill_sw_pending)) { 1258c2ecf20Sopenharmony_ci c = __test_and_clear_bit(i, rfkill_sw_state); 1268c2ecf20Sopenharmony_ci spin_unlock_irq(&rfkill_op_lock); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci __rfkill_handle_normal_op(i, c); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci spin_lock_irq(&rfkill_op_lock); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci } while (rfkill_op_pending); 1348c2ecf20Sopenharmony_ci spin_unlock_irq(&rfkill_op_lock); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic DECLARE_DELAYED_WORK(rfkill_op_work, rfkill_op_handler); 1388c2ecf20Sopenharmony_cistatic unsigned long rfkill_last_scheduled; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic unsigned long rfkill_ratelimit(const unsigned long last) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY); 1438c2ecf20Sopenharmony_ci return time_after(jiffies, last + delay) ? 0 : delay; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic void rfkill_schedule_ratelimited(void) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci if (schedule_delayed_work(&rfkill_op_work, 1498c2ecf20Sopenharmony_ci rfkill_ratelimit(rfkill_last_scheduled))) 1508c2ecf20Sopenharmony_ci rfkill_last_scheduled = jiffies; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic void rfkill_schedule_global_op(enum rfkill_sched_op op) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci unsigned long flags; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci spin_lock_irqsave(&rfkill_op_lock, flags); 1588c2ecf20Sopenharmony_ci rfkill_op = op; 1598c2ecf20Sopenharmony_ci rfkill_op_pending = true; 1608c2ecf20Sopenharmony_ci if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) { 1618c2ecf20Sopenharmony_ci /* bypass the limiter for EPO */ 1628c2ecf20Sopenharmony_ci mod_delayed_work(system_wq, &rfkill_op_work, 0); 1638c2ecf20Sopenharmony_ci rfkill_last_scheduled = jiffies; 1648c2ecf20Sopenharmony_ci } else 1658c2ecf20Sopenharmony_ci rfkill_schedule_ratelimited(); 1668c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rfkill_op_lock, flags); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void rfkill_schedule_toggle(enum rfkill_type type) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci unsigned long flags; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (rfkill_is_epo_lock_active()) 1748c2ecf20Sopenharmony_ci return; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci spin_lock_irqsave(&rfkill_op_lock, flags); 1778c2ecf20Sopenharmony_ci if (!rfkill_op_pending) { 1788c2ecf20Sopenharmony_ci __set_bit(type, rfkill_sw_pending); 1798c2ecf20Sopenharmony_ci __change_bit(type, rfkill_sw_state); 1808c2ecf20Sopenharmony_ci rfkill_schedule_ratelimited(); 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rfkill_op_lock, flags); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic void rfkill_schedule_evsw_rfkillall(int state) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci if (state) 1888c2ecf20Sopenharmony_ci rfkill_schedule_global_op(rfkill_master_switch_op); 1898c2ecf20Sopenharmony_ci else 1908c2ecf20Sopenharmony_ci rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic void rfkill_event(struct input_handle *handle, unsigned int type, 1948c2ecf20Sopenharmony_ci unsigned int code, int data) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci if (type == EV_KEY && data == 1) { 1978c2ecf20Sopenharmony_ci switch (code) { 1988c2ecf20Sopenharmony_ci case KEY_WLAN: 1998c2ecf20Sopenharmony_ci rfkill_schedule_toggle(RFKILL_TYPE_WLAN); 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci case KEY_BLUETOOTH: 2028c2ecf20Sopenharmony_ci rfkill_schedule_toggle(RFKILL_TYPE_BLUETOOTH); 2038c2ecf20Sopenharmony_ci break; 2048c2ecf20Sopenharmony_ci case KEY_UWB: 2058c2ecf20Sopenharmony_ci rfkill_schedule_toggle(RFKILL_TYPE_UWB); 2068c2ecf20Sopenharmony_ci break; 2078c2ecf20Sopenharmony_ci case KEY_WIMAX: 2088c2ecf20Sopenharmony_ci rfkill_schedule_toggle(RFKILL_TYPE_WIMAX); 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case KEY_RFKILL: 2118c2ecf20Sopenharmony_ci rfkill_schedule_toggle(RFKILL_TYPE_ALL); 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci } else if (type == EV_SW && code == SW_RFKILL_ALL) 2158c2ecf20Sopenharmony_ci rfkill_schedule_evsw_rfkillall(data); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int rfkill_connect(struct input_handler *handler, struct input_dev *dev, 2198c2ecf20Sopenharmony_ci const struct input_device_id *id) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct input_handle *handle; 2228c2ecf20Sopenharmony_ci int error; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); 2258c2ecf20Sopenharmony_ci if (!handle) 2268c2ecf20Sopenharmony_ci return -ENOMEM; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci handle->dev = dev; 2298c2ecf20Sopenharmony_ci handle->handler = handler; 2308c2ecf20Sopenharmony_ci handle->name = "rfkill"; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* causes rfkill_start() to be called */ 2338c2ecf20Sopenharmony_ci error = input_register_handle(handle); 2348c2ecf20Sopenharmony_ci if (error) 2358c2ecf20Sopenharmony_ci goto err_free_handle; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci error = input_open_device(handle); 2388c2ecf20Sopenharmony_ci if (error) 2398c2ecf20Sopenharmony_ci goto err_unregister_handle; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return 0; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci err_unregister_handle: 2448c2ecf20Sopenharmony_ci input_unregister_handle(handle); 2458c2ecf20Sopenharmony_ci err_free_handle: 2468c2ecf20Sopenharmony_ci kfree(handle); 2478c2ecf20Sopenharmony_ci return error; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void rfkill_start(struct input_handle *handle) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * Take event_lock to guard against configuration changes, we 2548c2ecf20Sopenharmony_ci * should be able to deal with concurrency with rfkill_event() 2558c2ecf20Sopenharmony_ci * just fine (which event_lock will also avoid). 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci spin_lock_irq(&handle->dev->event_lock); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (test_bit(EV_SW, handle->dev->evbit) && 2608c2ecf20Sopenharmony_ci test_bit(SW_RFKILL_ALL, handle->dev->swbit)) 2618c2ecf20Sopenharmony_ci rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL, 2628c2ecf20Sopenharmony_ci handle->dev->sw)); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci spin_unlock_irq(&handle->dev->event_lock); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic void rfkill_disconnect(struct input_handle *handle) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci input_close_device(handle); 2708c2ecf20Sopenharmony_ci input_unregister_handle(handle); 2718c2ecf20Sopenharmony_ci kfree(handle); 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic const struct input_device_id rfkill_ids[] = { 2758c2ecf20Sopenharmony_ci { 2768c2ecf20Sopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, 2778c2ecf20Sopenharmony_ci .evbit = { BIT_MASK(EV_KEY) }, 2788c2ecf20Sopenharmony_ci .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) }, 2798c2ecf20Sopenharmony_ci }, 2808c2ecf20Sopenharmony_ci { 2818c2ecf20Sopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, 2828c2ecf20Sopenharmony_ci .evbit = { BIT_MASK(EV_KEY) }, 2838c2ecf20Sopenharmony_ci .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) }, 2848c2ecf20Sopenharmony_ci }, 2858c2ecf20Sopenharmony_ci { 2868c2ecf20Sopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, 2878c2ecf20Sopenharmony_ci .evbit = { BIT_MASK(EV_KEY) }, 2888c2ecf20Sopenharmony_ci .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) }, 2898c2ecf20Sopenharmony_ci }, 2908c2ecf20Sopenharmony_ci { 2918c2ecf20Sopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, 2928c2ecf20Sopenharmony_ci .evbit = { BIT_MASK(EV_KEY) }, 2938c2ecf20Sopenharmony_ci .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, 2948c2ecf20Sopenharmony_ci }, 2958c2ecf20Sopenharmony_ci { 2968c2ecf20Sopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, 2978c2ecf20Sopenharmony_ci .evbit = { BIT_MASK(EV_KEY) }, 2988c2ecf20Sopenharmony_ci .keybit = { [BIT_WORD(KEY_RFKILL)] = BIT_MASK(KEY_RFKILL) }, 2998c2ecf20Sopenharmony_ci }, 3008c2ecf20Sopenharmony_ci { 3018c2ecf20Sopenharmony_ci .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT, 3028c2ecf20Sopenharmony_ci .evbit = { BIT(EV_SW) }, 3038c2ecf20Sopenharmony_ci .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) }, 3048c2ecf20Sopenharmony_ci }, 3058c2ecf20Sopenharmony_ci { } 3068c2ecf20Sopenharmony_ci}; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic struct input_handler rfkill_handler = { 3098c2ecf20Sopenharmony_ci .name = "rfkill", 3108c2ecf20Sopenharmony_ci .event = rfkill_event, 3118c2ecf20Sopenharmony_ci .connect = rfkill_connect, 3128c2ecf20Sopenharmony_ci .start = rfkill_start, 3138c2ecf20Sopenharmony_ci .disconnect = rfkill_disconnect, 3148c2ecf20Sopenharmony_ci .id_table = rfkill_ids, 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ciint __init rfkill_handler_init(void) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci switch (rfkill_master_switch_mode) { 3208c2ecf20Sopenharmony_ci case RFKILL_INPUT_MASTER_UNBLOCKALL: 3218c2ecf20Sopenharmony_ci rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNBLOCK; 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci case RFKILL_INPUT_MASTER_RESTORE: 3248c2ecf20Sopenharmony_ci rfkill_master_switch_op = RFKILL_GLOBAL_OP_RESTORE; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case RFKILL_INPUT_MASTER_UNLOCK: 3278c2ecf20Sopenharmony_ci rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNLOCK; 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci default: 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci spin_lock_init(&rfkill_op_lock); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* Avoid delay at first schedule */ 3368c2ecf20Sopenharmony_ci rfkill_last_scheduled = 3378c2ecf20Sopenharmony_ci jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1; 3388c2ecf20Sopenharmony_ci return input_register_handler(&rfkill_handler); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_civoid __exit rfkill_handler_exit(void) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci input_unregister_handler(&rfkill_handler); 3448c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&rfkill_op_work); 3458c2ecf20Sopenharmony_ci} 346