1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
219d337dfSJohannes Berg /*
319d337dfSJohannes Berg * Input layer to RF Kill interface connector
419d337dfSJohannes Berg *
519d337dfSJohannes Berg * Copyright (c) 2007 Dmitry Torokhov
619d337dfSJohannes Berg * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
719d337dfSJohannes Berg *
819d337dfSJohannes Berg * If you ever run into a situation in which you have a SW_ type rfkill
919d337dfSJohannes Berg * input device, then you can revive code that was removed in the patch
1019d337dfSJohannes Berg * "rfkill-input: remove unused code".
1119d337dfSJohannes Berg */
1219d337dfSJohannes Berg
1319d337dfSJohannes Berg #include <linux/input.h>
1419d337dfSJohannes Berg #include <linux/slab.h>
15d9b93842SPaul Gortmaker #include <linux/moduleparam.h>
1619d337dfSJohannes Berg #include <linux/workqueue.h>
1719d337dfSJohannes Berg #include <linux/init.h>
1819d337dfSJohannes Berg #include <linux/rfkill.h>
1919d337dfSJohannes Berg #include <linux/sched.h>
2019d337dfSJohannes Berg
2119d337dfSJohannes Berg #include "rfkill.h"
2219d337dfSJohannes Berg
2319d337dfSJohannes Berg enum rfkill_input_master_mode {
2419d337dfSJohannes Berg RFKILL_INPUT_MASTER_UNLOCK = 0,
2519d337dfSJohannes Berg RFKILL_INPUT_MASTER_RESTORE = 1,
2619d337dfSJohannes Berg RFKILL_INPUT_MASTER_UNBLOCKALL = 2,
2719d337dfSJohannes Berg NUM_RFKILL_INPUT_MASTER_MODES
2819d337dfSJohannes Berg };
2919d337dfSJohannes Berg
3019d337dfSJohannes Berg /* Delay (in ms) between consecutive switch ops */
3119d337dfSJohannes Berg #define RFKILL_OPS_DELAY 200
3219d337dfSJohannes Berg
3319d337dfSJohannes Berg static enum rfkill_input_master_mode rfkill_master_switch_mode =
3419d337dfSJohannes Berg RFKILL_INPUT_MASTER_UNBLOCKALL;
3519d337dfSJohannes Berg module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0);
3619d337dfSJohannes Berg MODULE_PARM_DESC(master_switch_mode,
3719d337dfSJohannes Berg "SW_RFKILL_ALL ON should: 0=do nothing (only unlock); 1=restore; 2=unblock all");
3819d337dfSJohannes Berg
39*ed7247f3SGuobin Huang static DEFINE_SPINLOCK(rfkill_op_lock);
4019d337dfSJohannes Berg static bool rfkill_op_pending;
4119d337dfSJohannes Berg static unsigned long rfkill_sw_pending[BITS_TO_LONGS(NUM_RFKILL_TYPES)];
4219d337dfSJohannes Berg static unsigned long rfkill_sw_state[BITS_TO_LONGS(NUM_RFKILL_TYPES)];
4319d337dfSJohannes Berg
4419d337dfSJohannes Berg enum rfkill_sched_op {
4519d337dfSJohannes Berg RFKILL_GLOBAL_OP_EPO = 0,
4619d337dfSJohannes Berg RFKILL_GLOBAL_OP_RESTORE,
4719d337dfSJohannes Berg RFKILL_GLOBAL_OP_UNLOCK,
4819d337dfSJohannes Berg RFKILL_GLOBAL_OP_UNBLOCK,
4919d337dfSJohannes Berg };
5019d337dfSJohannes Berg
5119d337dfSJohannes Berg static enum rfkill_sched_op rfkill_master_switch_op;
5219d337dfSJohannes Berg static enum rfkill_sched_op rfkill_op;
5319d337dfSJohannes Berg
__rfkill_handle_global_op(enum rfkill_sched_op op)5419d337dfSJohannes Berg static void __rfkill_handle_global_op(enum rfkill_sched_op op)
5519d337dfSJohannes Berg {
5619d337dfSJohannes Berg unsigned int i;
5719d337dfSJohannes Berg
5819d337dfSJohannes Berg switch (op) {
5919d337dfSJohannes Berg case RFKILL_GLOBAL_OP_EPO:
6019d337dfSJohannes Berg rfkill_epo();
6119d337dfSJohannes Berg break;
6219d337dfSJohannes Berg case RFKILL_GLOBAL_OP_RESTORE:
6319d337dfSJohannes Berg rfkill_restore_states();
6419d337dfSJohannes Berg break;
6519d337dfSJohannes Berg case RFKILL_GLOBAL_OP_UNLOCK:
6619d337dfSJohannes Berg rfkill_remove_epo_lock();
6719d337dfSJohannes Berg break;
6819d337dfSJohannes Berg case RFKILL_GLOBAL_OP_UNBLOCK:
6919d337dfSJohannes Berg rfkill_remove_epo_lock();
7019d337dfSJohannes Berg for (i = 0; i < NUM_RFKILL_TYPES; i++)
7119d337dfSJohannes Berg rfkill_switch_all(i, false);
7219d337dfSJohannes Berg break;
7319d337dfSJohannes Berg default:
7419d337dfSJohannes Berg /* memory corruption or bug, fail safely */
7519d337dfSJohannes Berg rfkill_epo();
7619d337dfSJohannes Berg WARN(1, "Unknown requested operation %d! "
7719d337dfSJohannes Berg "rfkill Emergency Power Off activated\n",
7819d337dfSJohannes Berg op);
7919d337dfSJohannes Berg }
8019d337dfSJohannes Berg }
8119d337dfSJohannes Berg
__rfkill_handle_normal_op(const enum rfkill_type type,const bool complement)8219d337dfSJohannes Berg static void __rfkill_handle_normal_op(const enum rfkill_type type,
8319d337dfSJohannes Berg const bool complement)
8419d337dfSJohannes Berg {
8519d337dfSJohannes Berg bool blocked;
8619d337dfSJohannes Berg
8719d337dfSJohannes Berg blocked = rfkill_get_global_sw_state(type);
8819d337dfSJohannes Berg if (complement)
8919d337dfSJohannes Berg blocked = !blocked;
9019d337dfSJohannes Berg
9119d337dfSJohannes Berg rfkill_switch_all(type, blocked);
9219d337dfSJohannes Berg }
9319d337dfSJohannes Berg
rfkill_op_handler(struct work_struct * work)9419d337dfSJohannes Berg static void rfkill_op_handler(struct work_struct *work)
9519d337dfSJohannes Berg {
9619d337dfSJohannes Berg unsigned int i;
9719d337dfSJohannes Berg bool c;
9819d337dfSJohannes Berg
9919d337dfSJohannes Berg spin_lock_irq(&rfkill_op_lock);
10019d337dfSJohannes Berg do {
10119d337dfSJohannes Berg if (rfkill_op_pending) {
10219d337dfSJohannes Berg enum rfkill_sched_op op = rfkill_op;
10319d337dfSJohannes Berg rfkill_op_pending = false;
10419d337dfSJohannes Berg memset(rfkill_sw_pending, 0,
10519d337dfSJohannes Berg sizeof(rfkill_sw_pending));
10619d337dfSJohannes Berg spin_unlock_irq(&rfkill_op_lock);
10719d337dfSJohannes Berg
10819d337dfSJohannes Berg __rfkill_handle_global_op(op);
10919d337dfSJohannes Berg
11019d337dfSJohannes Berg spin_lock_irq(&rfkill_op_lock);
11119d337dfSJohannes Berg
11219d337dfSJohannes Berg /*
11319d337dfSJohannes Berg * handle global ops first -- during unlocked period
11419d337dfSJohannes Berg * we might have gotten a new global op.
11519d337dfSJohannes Berg */
11619d337dfSJohannes Berg if (rfkill_op_pending)
11719d337dfSJohannes Berg continue;
11819d337dfSJohannes Berg }
11919d337dfSJohannes Berg
12019d337dfSJohannes Berg if (rfkill_is_epo_lock_active())
12119d337dfSJohannes Berg continue;
12219d337dfSJohannes Berg
12319d337dfSJohannes Berg for (i = 0; i < NUM_RFKILL_TYPES; i++) {
12419d337dfSJohannes Berg if (__test_and_clear_bit(i, rfkill_sw_pending)) {
12519d337dfSJohannes Berg c = __test_and_clear_bit(i, rfkill_sw_state);
12619d337dfSJohannes Berg spin_unlock_irq(&rfkill_op_lock);
12719d337dfSJohannes Berg
12819d337dfSJohannes Berg __rfkill_handle_normal_op(i, c);
12919d337dfSJohannes Berg
13019d337dfSJohannes Berg spin_lock_irq(&rfkill_op_lock);
13119d337dfSJohannes Berg }
13219d337dfSJohannes Berg }
13319d337dfSJohannes Berg } while (rfkill_op_pending);
13419d337dfSJohannes Berg spin_unlock_irq(&rfkill_op_lock);
13519d337dfSJohannes Berg }
13619d337dfSJohannes Berg
13719d337dfSJohannes Berg static DECLARE_DELAYED_WORK(rfkill_op_work, rfkill_op_handler);
13819d337dfSJohannes Berg static unsigned long rfkill_last_scheduled;
13919d337dfSJohannes Berg
rfkill_ratelimit(const unsigned long last)14019d337dfSJohannes Berg static unsigned long rfkill_ratelimit(const unsigned long last)
14119d337dfSJohannes Berg {
14219d337dfSJohannes Berg const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY);
143a02cec21SEric Dumazet return time_after(jiffies, last + delay) ? 0 : delay;
14419d337dfSJohannes Berg }
14519d337dfSJohannes Berg
rfkill_schedule_ratelimited(void)14619d337dfSJohannes Berg static void rfkill_schedule_ratelimited(void)
14719d337dfSJohannes Berg {
148ba0c96cdSTejun Heo if (schedule_delayed_work(&rfkill_op_work,
149ba0c96cdSTejun Heo rfkill_ratelimit(rfkill_last_scheduled)))
15019d337dfSJohannes Berg rfkill_last_scheduled = jiffies;
15119d337dfSJohannes Berg }
15219d337dfSJohannes Berg
rfkill_schedule_global_op(enum rfkill_sched_op op)15319d337dfSJohannes Berg static void rfkill_schedule_global_op(enum rfkill_sched_op op)
15419d337dfSJohannes Berg {
15519d337dfSJohannes Berg unsigned long flags;
15619d337dfSJohannes Berg
15719d337dfSJohannes Berg spin_lock_irqsave(&rfkill_op_lock, flags);
15819d337dfSJohannes Berg rfkill_op = op;
15919d337dfSJohannes Berg rfkill_op_pending = true;
16019d337dfSJohannes Berg if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) {
16119d337dfSJohannes Berg /* bypass the limiter for EPO */
16241f63c53STejun Heo mod_delayed_work(system_wq, &rfkill_op_work, 0);
16319d337dfSJohannes Berg rfkill_last_scheduled = jiffies;
16419d337dfSJohannes Berg } else
16519d337dfSJohannes Berg rfkill_schedule_ratelimited();
16619d337dfSJohannes Berg spin_unlock_irqrestore(&rfkill_op_lock, flags);
16719d337dfSJohannes Berg }
16819d337dfSJohannes Berg
rfkill_schedule_toggle(enum rfkill_type type)16919d337dfSJohannes Berg static void rfkill_schedule_toggle(enum rfkill_type type)
17019d337dfSJohannes Berg {
17119d337dfSJohannes Berg unsigned long flags;
17219d337dfSJohannes Berg
17319d337dfSJohannes Berg if (rfkill_is_epo_lock_active())
17419d337dfSJohannes Berg return;
17519d337dfSJohannes Berg
17619d337dfSJohannes Berg spin_lock_irqsave(&rfkill_op_lock, flags);
17719d337dfSJohannes Berg if (!rfkill_op_pending) {
17819d337dfSJohannes Berg __set_bit(type, rfkill_sw_pending);
17919d337dfSJohannes Berg __change_bit(type, rfkill_sw_state);
18019d337dfSJohannes Berg rfkill_schedule_ratelimited();
18119d337dfSJohannes Berg }
18219d337dfSJohannes Berg spin_unlock_irqrestore(&rfkill_op_lock, flags);
18319d337dfSJohannes Berg }
18419d337dfSJohannes Berg
rfkill_schedule_evsw_rfkillall(int state)18519d337dfSJohannes Berg static void rfkill_schedule_evsw_rfkillall(int state)
18619d337dfSJohannes Berg {
18719d337dfSJohannes Berg if (state)
18819d337dfSJohannes Berg rfkill_schedule_global_op(rfkill_master_switch_op);
18919d337dfSJohannes Berg else
19019d337dfSJohannes Berg rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO);
19119d337dfSJohannes Berg }
19219d337dfSJohannes Berg
rfkill_event(struct input_handle * handle,unsigned int type,unsigned int code,int data)19319d337dfSJohannes Berg static void rfkill_event(struct input_handle *handle, unsigned int type,
19419d337dfSJohannes Berg unsigned int code, int data)
19519d337dfSJohannes Berg {
19619d337dfSJohannes Berg if (type == EV_KEY && data == 1) {
19719d337dfSJohannes Berg switch (code) {
19819d337dfSJohannes Berg case KEY_WLAN:
19919d337dfSJohannes Berg rfkill_schedule_toggle(RFKILL_TYPE_WLAN);
20019d337dfSJohannes Berg break;
20119d337dfSJohannes Berg case KEY_BLUETOOTH:
20219d337dfSJohannes Berg rfkill_schedule_toggle(RFKILL_TYPE_BLUETOOTH);
20319d337dfSJohannes Berg break;
20419d337dfSJohannes Berg case KEY_UWB:
20519d337dfSJohannes Berg rfkill_schedule_toggle(RFKILL_TYPE_UWB);
20619d337dfSJohannes Berg break;
20719d337dfSJohannes Berg case KEY_WIMAX:
20819d337dfSJohannes Berg rfkill_schedule_toggle(RFKILL_TYPE_WIMAX);
20919d337dfSJohannes Berg break;
2103082a2b7SMatthew Garrett case KEY_RFKILL:
2113082a2b7SMatthew Garrett rfkill_schedule_toggle(RFKILL_TYPE_ALL);
2123082a2b7SMatthew Garrett break;
21319d337dfSJohannes Berg }
21419d337dfSJohannes Berg } else if (type == EV_SW && code == SW_RFKILL_ALL)
21519d337dfSJohannes Berg rfkill_schedule_evsw_rfkillall(data);
21619d337dfSJohannes Berg }
21719d337dfSJohannes Berg
rfkill_connect(struct input_handler * handler,struct input_dev * dev,const struct input_device_id * id)21819d337dfSJohannes Berg static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
21919d337dfSJohannes Berg const struct input_device_id *id)
22019d337dfSJohannes Berg {
22119d337dfSJohannes Berg struct input_handle *handle;
22219d337dfSJohannes Berg int error;
22319d337dfSJohannes Berg
22419d337dfSJohannes Berg handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
22519d337dfSJohannes Berg if (!handle)
22619d337dfSJohannes Berg return -ENOMEM;
22719d337dfSJohannes Berg
22819d337dfSJohannes Berg handle->dev = dev;
22919d337dfSJohannes Berg handle->handler = handler;
23019d337dfSJohannes Berg handle->name = "rfkill";
23119d337dfSJohannes Berg
23219d337dfSJohannes Berg /* causes rfkill_start() to be called */
23319d337dfSJohannes Berg error = input_register_handle(handle);
23419d337dfSJohannes Berg if (error)
23519d337dfSJohannes Berg goto err_free_handle;
23619d337dfSJohannes Berg
23719d337dfSJohannes Berg error = input_open_device(handle);
23819d337dfSJohannes Berg if (error)
23919d337dfSJohannes Berg goto err_unregister_handle;
24019d337dfSJohannes Berg
24119d337dfSJohannes Berg return 0;
24219d337dfSJohannes Berg
24319d337dfSJohannes Berg err_unregister_handle:
24419d337dfSJohannes Berg input_unregister_handle(handle);
24519d337dfSJohannes Berg err_free_handle:
24619d337dfSJohannes Berg kfree(handle);
24719d337dfSJohannes Berg return error;
24819d337dfSJohannes Berg }
24919d337dfSJohannes Berg
rfkill_start(struct input_handle * handle)25019d337dfSJohannes Berg static void rfkill_start(struct input_handle *handle)
25119d337dfSJohannes Berg {
25219d337dfSJohannes Berg /*
25319d337dfSJohannes Berg * Take event_lock to guard against configuration changes, we
25419d337dfSJohannes Berg * should be able to deal with concurrency with rfkill_event()
25519d337dfSJohannes Berg * just fine (which event_lock will also avoid).
25619d337dfSJohannes Berg */
25719d337dfSJohannes Berg spin_lock_irq(&handle->dev->event_lock);
25819d337dfSJohannes Berg
25919d337dfSJohannes Berg if (test_bit(EV_SW, handle->dev->evbit) &&
26019d337dfSJohannes Berg test_bit(SW_RFKILL_ALL, handle->dev->swbit))
26119d337dfSJohannes Berg rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL,
26219d337dfSJohannes Berg handle->dev->sw));
26319d337dfSJohannes Berg
26419d337dfSJohannes Berg spin_unlock_irq(&handle->dev->event_lock);
26519d337dfSJohannes Berg }
26619d337dfSJohannes Berg
rfkill_disconnect(struct input_handle * handle)26719d337dfSJohannes Berg static void rfkill_disconnect(struct input_handle *handle)
26819d337dfSJohannes Berg {
26919d337dfSJohannes Berg input_close_device(handle);
27019d337dfSJohannes Berg input_unregister_handle(handle);
27119d337dfSJohannes Berg kfree(handle);
27219d337dfSJohannes Berg }
27319d337dfSJohannes Berg
27419d337dfSJohannes Berg static const struct input_device_id rfkill_ids[] = {
27519d337dfSJohannes Berg {
27619d337dfSJohannes Berg .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
27719d337dfSJohannes Berg .evbit = { BIT_MASK(EV_KEY) },
27819d337dfSJohannes Berg .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) },
27919d337dfSJohannes Berg },
28019d337dfSJohannes Berg {
28119d337dfSJohannes Berg .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
28219d337dfSJohannes Berg .evbit = { BIT_MASK(EV_KEY) },
28319d337dfSJohannes Berg .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) },
28419d337dfSJohannes Berg },
28519d337dfSJohannes Berg {
28619d337dfSJohannes Berg .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
28719d337dfSJohannes Berg .evbit = { BIT_MASK(EV_KEY) },
28819d337dfSJohannes Berg .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) },
28919d337dfSJohannes Berg },
29019d337dfSJohannes Berg {
29119d337dfSJohannes Berg .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
29219d337dfSJohannes Berg .evbit = { BIT_MASK(EV_KEY) },
29319d337dfSJohannes Berg .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
29419d337dfSJohannes Berg },
29519d337dfSJohannes Berg {
2963082a2b7SMatthew Garrett .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
2973082a2b7SMatthew Garrett .evbit = { BIT_MASK(EV_KEY) },
2983082a2b7SMatthew Garrett .keybit = { [BIT_WORD(KEY_RFKILL)] = BIT_MASK(KEY_RFKILL) },
2993082a2b7SMatthew Garrett },
3003082a2b7SMatthew Garrett {
30119d337dfSJohannes Berg .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
30219d337dfSJohannes Berg .evbit = { BIT(EV_SW) },
30319d337dfSJohannes Berg .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) },
30419d337dfSJohannes Berg },
30519d337dfSJohannes Berg { }
30619d337dfSJohannes Berg };
30719d337dfSJohannes Berg
30819d337dfSJohannes Berg static struct input_handler rfkill_handler = {
30919d337dfSJohannes Berg .name = "rfkill",
31019d337dfSJohannes Berg .event = rfkill_event,
31119d337dfSJohannes Berg .connect = rfkill_connect,
31219d337dfSJohannes Berg .start = rfkill_start,
31319d337dfSJohannes Berg .disconnect = rfkill_disconnect,
31419d337dfSJohannes Berg .id_table = rfkill_ids,
31519d337dfSJohannes Berg };
31619d337dfSJohannes Berg
rfkill_handler_init(void)31719d337dfSJohannes Berg int __init rfkill_handler_init(void)
31819d337dfSJohannes Berg {
31919d337dfSJohannes Berg switch (rfkill_master_switch_mode) {
32019d337dfSJohannes Berg case RFKILL_INPUT_MASTER_UNBLOCKALL:
32119d337dfSJohannes Berg rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNBLOCK;
32219d337dfSJohannes Berg break;
32319d337dfSJohannes Berg case RFKILL_INPUT_MASTER_RESTORE:
32419d337dfSJohannes Berg rfkill_master_switch_op = RFKILL_GLOBAL_OP_RESTORE;
32519d337dfSJohannes Berg break;
32619d337dfSJohannes Berg case RFKILL_INPUT_MASTER_UNLOCK:
32719d337dfSJohannes Berg rfkill_master_switch_op = RFKILL_GLOBAL_OP_UNLOCK;
32819d337dfSJohannes Berg break;
32919d337dfSJohannes Berg default:
33019d337dfSJohannes Berg return -EINVAL;
33119d337dfSJohannes Berg }
33219d337dfSJohannes Berg
33319d337dfSJohannes Berg /* Avoid delay at first schedule */
33419d337dfSJohannes Berg rfkill_last_scheduled =
33519d337dfSJohannes Berg jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1;
33619d337dfSJohannes Berg return input_register_handler(&rfkill_handler);
33719d337dfSJohannes Berg }
33819d337dfSJohannes Berg
rfkill_handler_exit(void)33919d337dfSJohannes Berg void __exit rfkill_handler_exit(void)
34019d337dfSJohannes Berg {
34119d337dfSJohannes Berg input_unregister_handler(&rfkill_handler);
34219d337dfSJohannes Berg cancel_delayed_work_sync(&rfkill_op_work);
34319d337dfSJohannes Berg }
344