aboutsummaryrefslogtreecommitdiffstats
path: root/net/rfkill/rfkill-input.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/rfkill/rfkill-input.c')
-rw-r--r--net/rfkill/rfkill-input.c98
1 files changed, 74 insertions, 24 deletions
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index e4b051dbed61..8aa822730145 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -30,39 +30,62 @@ struct rfkill_task {
30 spinlock_t lock; /* for accessing last and desired state */ 30 spinlock_t lock; /* for accessing last and desired state */
31 unsigned long last; /* last schedule */ 31 unsigned long last; /* last schedule */
32 enum rfkill_state desired_state; /* on/off */ 32 enum rfkill_state desired_state; /* on/off */
33 enum rfkill_state current_state; /* on/off */
34}; 33};
35 34
36static void rfkill_task_handler(struct work_struct *work) 35static void rfkill_task_handler(struct work_struct *work)
37{ 36{
38 struct rfkill_task *task = container_of(work, struct rfkill_task, work); 37 struct rfkill_task *task = container_of(work, struct rfkill_task, work);
39 enum rfkill_state state;
40 38
41 mutex_lock(&task->mutex); 39 mutex_lock(&task->mutex);
42 40
43 /* 41 rfkill_switch_all(task->type, task->desired_state);
44 * Use temp variable to fetch desired state to keep it
45 * consistent even if rfkill_schedule_toggle() runs in
46 * another thread or interrupts us.
47 */
48 state = task->desired_state;
49 42
50 if (state != task->current_state) { 43 mutex_unlock(&task->mutex);
51 rfkill_switch_all(task->type, state); 44}
52 task->current_state = state; 45
46static void rfkill_task_epo_handler(struct work_struct *work)
47{
48 rfkill_epo();
49}
50
51static DECLARE_WORK(epo_work, rfkill_task_epo_handler);
52
53static void rfkill_schedule_epo(void)
54{
55 schedule_work(&epo_work);
56}
57
58static void rfkill_schedule_set(struct rfkill_task *task,
59 enum rfkill_state desired_state)
60{
61 unsigned long flags;
62
63 if (unlikely(work_pending(&epo_work)))
64 return;
65
66 spin_lock_irqsave(&task->lock, flags);
67
68 if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
69 task->desired_state = desired_state;
70 task->last = jiffies;
71 schedule_work(&task->work);
53 } 72 }
54 73
55 mutex_unlock(&task->mutex); 74 spin_unlock_irqrestore(&task->lock, flags);
56} 75}
57 76
58static void rfkill_schedule_toggle(struct rfkill_task *task) 77static void rfkill_schedule_toggle(struct rfkill_task *task)
59{ 78{
60 unsigned long flags; 79 unsigned long flags;
61 80
81 if (unlikely(work_pending(&epo_work)))
82 return;
83
62 spin_lock_irqsave(&task->lock, flags); 84 spin_lock_irqsave(&task->lock, flags);
63 85
64 if (time_after(jiffies, task->last + msecs_to_jiffies(200))) { 86 if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
65 task->desired_state = !task->desired_state; 87 task->desired_state =
88 rfkill_state_complement(task->desired_state);
66 task->last = jiffies; 89 task->last = jiffies;
67 schedule_work(&task->work); 90 schedule_work(&task->work);
68 } 91 }
@@ -70,26 +93,26 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
70 spin_unlock_irqrestore(&task->lock, flags); 93 spin_unlock_irqrestore(&task->lock, flags);
71} 94}
72 95
73#define DEFINE_RFKILL_TASK(n, t) \ 96#define DEFINE_RFKILL_TASK(n, t) \
74 struct rfkill_task n = { \ 97 struct rfkill_task n = { \
75 .work = __WORK_INITIALIZER(n.work, \ 98 .work = __WORK_INITIALIZER(n.work, \
76 rfkill_task_handler), \ 99 rfkill_task_handler), \
77 .type = t, \ 100 .type = t, \
78 .mutex = __MUTEX_INITIALIZER(n.mutex), \ 101 .mutex = __MUTEX_INITIALIZER(n.mutex), \
79 .lock = __SPIN_LOCK_UNLOCKED(n.lock), \ 102 .lock = __SPIN_LOCK_UNLOCKED(n.lock), \
80 .desired_state = RFKILL_STATE_ON, \ 103 .desired_state = RFKILL_STATE_UNBLOCKED, \
81 .current_state = RFKILL_STATE_ON, \
82 } 104 }
83 105
84static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); 106static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
85static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH); 107static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
86static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB); 108static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
87static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX); 109static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
110static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
88 111
89static void rfkill_event(struct input_handle *handle, unsigned int type, 112static void rfkill_event(struct input_handle *handle, unsigned int type,
90 unsigned int code, int down) 113 unsigned int code, int data)
91{ 114{
92 if (type == EV_KEY && down == 1) { 115 if (type == EV_KEY && data == 1) {
93 switch (code) { 116 switch (code) {
94 case KEY_WLAN: 117 case KEY_WLAN:
95 rfkill_schedule_toggle(&rfkill_wlan); 118 rfkill_schedule_toggle(&rfkill_wlan);
@@ -106,6 +129,28 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
106 default: 129 default:
107 break; 130 break;
108 } 131 }
132 } else if (type == EV_SW) {
133 switch (code) {
134 case SW_RFKILL_ALL:
135 /* EVERY radio type. data != 0 means radios ON */
136 /* handle EPO (emergency power off) through shortcut */
137 if (data) {
138 rfkill_schedule_set(&rfkill_wwan,
139 RFKILL_STATE_UNBLOCKED);
140 rfkill_schedule_set(&rfkill_wimax,
141 RFKILL_STATE_UNBLOCKED);
142 rfkill_schedule_set(&rfkill_uwb,
143 RFKILL_STATE_UNBLOCKED);
144 rfkill_schedule_set(&rfkill_bt,
145 RFKILL_STATE_UNBLOCKED);
146 rfkill_schedule_set(&rfkill_wlan,
147 RFKILL_STATE_UNBLOCKED);
148 } else
149 rfkill_schedule_epo();
150 break;
151 default:
152 break;
153 }
109 } 154 }
110} 155}
111 156
@@ -168,6 +213,11 @@ static const struct input_device_id rfkill_ids[] = {
168 .evbit = { BIT_MASK(EV_KEY) }, 213 .evbit = { BIT_MASK(EV_KEY) },
169 .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) }, 214 .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
170 }, 215 },
216 {
217 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
218 .evbit = { BIT(EV_SW) },
219 .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) },
220 },
171 { } 221 { }
172}; 222};
173 223