rfkill: add master_switch_mode and EPO lock to rfkill and rfkill-input
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / net / rfkill / rfkill-input.c
blob4ea4e68b59040a0480f025c470aae905fbac6c33
1 /*
2 * Input layer to RF Kill interface connector
4 * Copyright (c) 2007 Dmitry Torokhov
5 */
7 /*
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published
10 * by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/input.h>
15 #include <linux/slab.h>
16 #include <linux/workqueue.h>
17 #include <linux/init.h>
18 #include <linux/rfkill.h>
20 #include "rfkill-input.h"
22 MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
23 MODULE_DESCRIPTION("Input layer to RF switch connector");
24 MODULE_LICENSE("GPL");
26 enum rfkill_input_master_mode {
27 RFKILL_INPUT_MASTER_DONOTHING = 0,
28 RFKILL_INPUT_MASTER_RESTORE = 1,
29 RFKILL_INPUT_MASTER_UNBLOCKALL = 2,
30 RFKILL_INPUT_MASTER_MAX, /* marker */
33 static enum rfkill_input_master_mode rfkill_master_switch_mode =
34 RFKILL_INPUT_MASTER_UNBLOCKALL;
35 module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0);
36 MODULE_PARM_DESC(master_switch_mode,
37 "SW_RFKILL_ALL ON should: 0=do nothing; 1=restore; 2=unblock all");
39 enum rfkill_global_sched_op {
40 RFKILL_GLOBAL_OP_EPO = 0,
41 RFKILL_GLOBAL_OP_RESTORE,
42 RFKILL_GLOBAL_OP_UNLOCK,
43 RFKILL_GLOBAL_OP_UNBLOCK,
47 * Currently, the code marked with RFKILL_NEED_SWSET is inactive.
48 * If handling of EV_SW SW_WLAN/WWAN/BLUETOOTH/etc is needed in the
49 * future, when such events are added, that code will be necessary.
52 struct rfkill_task {
53 struct work_struct work;
55 /* ensures that task is serialized */
56 struct mutex mutex;
58 /* protects everything below */
59 spinlock_t lock;
61 /* pending regular switch operations (1=pending) */
62 unsigned long sw_pending[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
64 #ifdef RFKILL_NEED_SWSET
65 /* set operation pending (1=pending) */
66 unsigned long sw_setpending[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
68 /* desired state for pending set operation (1=unblock) */
69 unsigned long sw_newstate[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
70 #endif
72 /* should the state be complemented (1=yes) */
73 unsigned long sw_togglestate[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
75 bool global_op_pending;
76 enum rfkill_global_sched_op op;
79 static void __rfkill_handle_global_op(enum rfkill_global_sched_op op)
81 unsigned int i;
83 switch (op) {
84 case RFKILL_GLOBAL_OP_EPO:
85 rfkill_epo();
86 break;
87 case RFKILL_GLOBAL_OP_RESTORE:
88 rfkill_restore_states();
89 break;
90 case RFKILL_GLOBAL_OP_UNLOCK:
91 rfkill_remove_epo_lock();
92 break;
93 case RFKILL_GLOBAL_OP_UNBLOCK:
94 rfkill_remove_epo_lock();
95 for (i = 0; i < RFKILL_TYPE_MAX; i++)
96 rfkill_switch_all(i, RFKILL_STATE_UNBLOCKED);
97 break;
98 default:
99 /* memory corruption or bug, fail safely */
100 rfkill_epo();
101 WARN(1, "Unknown requested operation %d! "
102 "rfkill Emergency Power Off activated\n",
103 op);
107 #ifdef RFKILL_NEED_SWSET
108 static void __rfkill_handle_normal_op(const enum rfkill_type type,
109 const bool sp, const bool s, const bool c)
111 enum rfkill_state state;
113 if (sp)
114 state = (s) ? RFKILL_STATE_UNBLOCKED :
115 RFKILL_STATE_SOFT_BLOCKED;
116 else
117 state = rfkill_get_global_state(type);
119 if (c)
120 state = rfkill_state_complement(state);
122 rfkill_switch_all(type, state);
124 #else
125 static void __rfkill_handle_normal_op(const enum rfkill_type type,
126 const bool c)
128 enum rfkill_state state;
130 state = rfkill_get_global_state(type);
131 if (c)
132 state = rfkill_state_complement(state);
134 rfkill_switch_all(type, state);
136 #endif
138 static void rfkill_task_handler(struct work_struct *work)
140 struct rfkill_task *task =
141 container_of(work, struct rfkill_task, work);
142 bool doit = true;
144 mutex_lock(&task->mutex);
146 spin_lock_irq(&task->lock);
147 while (doit) {
148 if (task->global_op_pending) {
149 enum rfkill_global_sched_op op = task->op;
150 task->global_op_pending = false;
151 memset(task->sw_pending, 0, sizeof(task->sw_pending));
152 spin_unlock_irq(&task->lock);
154 __rfkill_handle_global_op(op);
156 /* make sure we do at least one pass with
157 * !task->global_op_pending */
158 spin_lock_irq(&task->lock);
159 continue;
160 } else if (!rfkill_is_epo_lock_active()) {
161 unsigned int i = 0;
163 while (!task->global_op_pending &&
164 i < RFKILL_TYPE_MAX) {
165 if (test_and_clear_bit(i, task->sw_pending)) {
166 bool c;
167 #ifdef RFKILL_NEED_SWSET
168 bool sp, s;
169 sp = test_and_clear_bit(i,
170 task->sw_setpending);
171 s = test_bit(i, task->sw_newstate);
172 #endif
173 c = test_and_clear_bit(i,
174 task->sw_togglestate);
175 spin_unlock_irq(&task->lock);
177 #ifdef RFKILL_NEED_SWSET
178 __rfkill_handle_normal_op(i, sp, s, c);
179 #else
180 __rfkill_handle_normal_op(i, c);
181 #endif
183 spin_lock_irq(&task->lock);
185 i++;
188 doit = task->global_op_pending;
190 spin_unlock_irq(&task->lock);
192 mutex_unlock(&task->mutex);
195 static struct rfkill_task rfkill_task = {
196 .work = __WORK_INITIALIZER(rfkill_task.work,
197 rfkill_task_handler),
198 .mutex = __MUTEX_INITIALIZER(rfkill_task.mutex),
199 .lock = __SPIN_LOCK_UNLOCKED(rfkill_task.lock),
202 static void rfkill_schedule_global_op(enum rfkill_global_sched_op op)
204 unsigned long flags;
206 spin_lock_irqsave(&rfkill_task.lock, flags);
207 rfkill_task.op = op;
208 rfkill_task.global_op_pending = true;
209 schedule_work(&rfkill_task.work);
210 spin_unlock_irqrestore(&rfkill_task.lock, flags);
213 #ifdef RFKILL_NEED_SWSET
214 /* Use this if you need to add EV_SW SW_WLAN/WWAN/BLUETOOTH/etc handling */
216 static void rfkill_schedule_set(enum rfkill_type type,
217 enum rfkill_state desired_state)
219 unsigned long flags;
221 if (rfkill_is_epo_lock_active())
222 return;
224 spin_lock_irqsave(&rfkill_task.lock, flags);
225 if (!rfkill_task.global_op_pending) {
226 set_bit(type, rfkill_task.sw_pending);
227 set_bit(type, rfkill_task.sw_setpending);
228 clear_bit(type, rfkill_task.sw_togglestate);
229 if (desired_state)
230 set_bit(type, rfkill_task.sw_newstate);
231 else
232 clear_bit(type, rfkill_task.sw_newstate);
233 schedule_work(&rfkill_task.work);
235 spin_unlock_irqrestore(&rfkill_task.lock, flags);
237 #endif
239 static void rfkill_schedule_toggle(enum rfkill_type type)
241 unsigned long flags;
243 if (rfkill_is_epo_lock_active())
244 return;
246 spin_lock_irqsave(&rfkill_task.lock, flags);
247 if (!rfkill_task.global_op_pending) {
248 set_bit(type, rfkill_task.sw_pending);
249 change_bit(type, rfkill_task.sw_togglestate);
250 schedule_work(&rfkill_task.work);
252 spin_unlock_irqrestore(&rfkill_task.lock, flags);
255 static void rfkill_schedule_evsw_rfkillall(int state)
257 if (state) {
258 switch (rfkill_master_switch_mode) {
259 case RFKILL_INPUT_MASTER_UNBLOCKALL:
260 rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNBLOCK);
261 break;
262 case RFKILL_INPUT_MASTER_RESTORE:
263 rfkill_schedule_global_op(RFKILL_GLOBAL_OP_RESTORE);
264 break;
265 case RFKILL_INPUT_MASTER_DONOTHING:
266 rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNLOCK);
267 break;
268 default:
269 /* memory corruption or driver bug! fail safely */
270 rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO);
271 WARN(1, "Unknown rfkill_master_switch_mode (%d), "
272 "driver bug or memory corruption detected!\n",
273 rfkill_master_switch_mode);
274 break;
276 } else
277 rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO);
280 static void rfkill_event(struct input_handle *handle, unsigned int type,
281 unsigned int code, int data)
283 if (type == EV_KEY && data == 1) {
284 enum rfkill_type t;
286 switch (code) {
287 case KEY_WLAN:
288 t = RFKILL_TYPE_WLAN;
289 break;
290 case KEY_BLUETOOTH:
291 t = RFKILL_TYPE_BLUETOOTH;
292 break;
293 case KEY_UWB:
294 t = RFKILL_TYPE_UWB;
295 break;
296 case KEY_WIMAX:
297 t = RFKILL_TYPE_WIMAX;
298 break;
299 default:
300 return;
302 rfkill_schedule_toggle(t);
303 return;
304 } else if (type == EV_SW) {
305 switch (code) {
306 case SW_RFKILL_ALL:
307 rfkill_schedule_evsw_rfkillall(data);
308 return;
309 default:
310 return;
315 static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
316 const struct input_device_id *id)
318 struct input_handle *handle;
319 int error;
321 handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
322 if (!handle)
323 return -ENOMEM;
325 handle->dev = dev;
326 handle->handler = handler;
327 handle->name = "rfkill";
329 /* causes rfkill_start() to be called */
330 error = input_register_handle(handle);
331 if (error)
332 goto err_free_handle;
334 error = input_open_device(handle);
335 if (error)
336 goto err_unregister_handle;
338 return 0;
340 err_unregister_handle:
341 input_unregister_handle(handle);
342 err_free_handle:
343 kfree(handle);
344 return error;
347 static void rfkill_start(struct input_handle *handle)
349 /* Take event_lock to guard against configuration changes, we
350 * should be able to deal with concurrency with rfkill_event()
351 * just fine (which event_lock will also avoid). */
352 spin_lock_irq(&handle->dev->event_lock);
354 if (test_bit(EV_SW, handle->dev->evbit)) {
355 if (test_bit(SW_RFKILL_ALL, handle->dev->swbit))
356 rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL,
357 handle->dev->sw));
358 /* add resync for further EV_SW events here */
361 spin_unlock_irq(&handle->dev->event_lock);
364 static void rfkill_disconnect(struct input_handle *handle)
366 input_close_device(handle);
367 input_unregister_handle(handle);
368 kfree(handle);
371 static const struct input_device_id rfkill_ids[] = {
373 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
374 .evbit = { BIT_MASK(EV_KEY) },
375 .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) },
378 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
379 .evbit = { BIT_MASK(EV_KEY) },
380 .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) },
383 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
384 .evbit = { BIT_MASK(EV_KEY) },
385 .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) },
388 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
389 .evbit = { BIT_MASK(EV_KEY) },
390 .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
393 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
394 .evbit = { BIT(EV_SW) },
395 .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) },
400 static struct input_handler rfkill_handler = {
401 .event = rfkill_event,
402 .connect = rfkill_connect,
403 .disconnect = rfkill_disconnect,
404 .start = rfkill_start,
405 .name = "rfkill",
406 .id_table = rfkill_ids,
409 static int __init rfkill_handler_init(void)
411 if (rfkill_master_switch_mode >= RFKILL_INPUT_MASTER_MAX)
412 return -EINVAL;
414 return input_register_handler(&rfkill_handler);
417 static void __exit rfkill_handler_exit(void)
419 input_unregister_handler(&rfkill_handler);
420 flush_scheduled_work();
421 rfkill_remove_epo_lock();
424 module_init(rfkill_handler_init);
425 module_exit(rfkill_handler_exit);