Merge branch 'docs' of git://git.lwn.net/linux-2.6
[linux-2.6] / net / rfkill / rfkill-input.c
1 /*
2  * Input layer to RF Kill interface connector
3  *
4  * Copyright (c) 2007 Dmitry Torokhov
5  */
6
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.
11  */
12
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>
19 #include <linux/sched.h>
20
21 #include "rfkill-input.h"
22
23 MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
24 MODULE_DESCRIPTION("Input layer to RF switch connector");
25 MODULE_LICENSE("GPL");
26
27 struct rfkill_task {
28         struct work_struct work;
29         enum rfkill_type type;
30         struct mutex mutex; /* ensures that task is serialized */
31         spinlock_t lock; /* for accessing last and desired state */
32         unsigned long last; /* last schedule */
33         enum rfkill_state desired_state; /* on/off */
34 };
35
36 static void rfkill_task_handler(struct work_struct *work)
37 {
38         struct rfkill_task *task = container_of(work, struct rfkill_task, work);
39
40         mutex_lock(&task->mutex);
41
42         rfkill_switch_all(task->type, task->desired_state);
43
44         mutex_unlock(&task->mutex);
45 }
46
47 static void rfkill_task_epo_handler(struct work_struct *work)
48 {
49         rfkill_epo();
50 }
51
52 static DECLARE_WORK(epo_work, rfkill_task_epo_handler);
53
54 static void rfkill_schedule_epo(void)
55 {
56         schedule_work(&epo_work);
57 }
58
59 static void rfkill_schedule_set(struct rfkill_task *task,
60                                 enum rfkill_state desired_state)
61 {
62         unsigned long flags;
63
64         if (unlikely(work_pending(&epo_work)))
65                 return;
66
67         spin_lock_irqsave(&task->lock, flags);
68
69         if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
70                 task->desired_state = desired_state;
71                 task->last = jiffies;
72                 schedule_work(&task->work);
73         }
74
75         spin_unlock_irqrestore(&task->lock, flags);
76 }
77
78 static void rfkill_schedule_toggle(struct rfkill_task *task)
79 {
80         unsigned long flags;
81
82         if (unlikely(work_pending(&epo_work)))
83                 return;
84
85         spin_lock_irqsave(&task->lock, flags);
86
87         if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
88                 task->desired_state =
89                                 rfkill_state_complement(task->desired_state);
90                 task->last = jiffies;
91                 schedule_work(&task->work);
92         }
93
94         spin_unlock_irqrestore(&task->lock, flags);
95 }
96
97 #define DEFINE_RFKILL_TASK(n, t)                                \
98         struct rfkill_task n = {                                \
99                 .work = __WORK_INITIALIZER(n.work,              \
100                                 rfkill_task_handler),           \
101                 .type = t,                                      \
102                 .mutex = __MUTEX_INITIALIZER(n.mutex),          \
103                 .lock = __SPIN_LOCK_UNLOCKED(n.lock),           \
104                 .desired_state = RFKILL_STATE_UNBLOCKED,        \
105         }
106
107 static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
108 static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
109 static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
110 static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
111 static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
112
113 static void rfkill_schedule_evsw_rfkillall(int state)
114 {
115         /* EVERY radio type. state != 0 means radios ON */
116         /* handle EPO (emergency power off) through shortcut */
117         if (state) {
118                 rfkill_schedule_set(&rfkill_wwan,
119                                     RFKILL_STATE_UNBLOCKED);
120                 rfkill_schedule_set(&rfkill_wimax,
121                                     RFKILL_STATE_UNBLOCKED);
122                 rfkill_schedule_set(&rfkill_uwb,
123                                     RFKILL_STATE_UNBLOCKED);
124                 rfkill_schedule_set(&rfkill_bt,
125                                     RFKILL_STATE_UNBLOCKED);
126                 rfkill_schedule_set(&rfkill_wlan,
127                                     RFKILL_STATE_UNBLOCKED);
128         } else
129                 rfkill_schedule_epo();
130 }
131
132 static void rfkill_event(struct input_handle *handle, unsigned int type,
133                         unsigned int code, int data)
134 {
135         if (type == EV_KEY && data == 1) {
136                 switch (code) {
137                 case KEY_WLAN:
138                         rfkill_schedule_toggle(&rfkill_wlan);
139                         break;
140                 case KEY_BLUETOOTH:
141                         rfkill_schedule_toggle(&rfkill_bt);
142                         break;
143                 case KEY_UWB:
144                         rfkill_schedule_toggle(&rfkill_uwb);
145                         break;
146                 case KEY_WIMAX:
147                         rfkill_schedule_toggle(&rfkill_wimax);
148                         break;
149                 default:
150                         break;
151                 }
152         } else if (type == EV_SW) {
153                 switch (code) {
154                 case SW_RFKILL_ALL:
155                         rfkill_schedule_evsw_rfkillall(data);
156                         break;
157                 default:
158                         break;
159                 }
160         }
161 }
162
163 static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
164                           const struct input_device_id *id)
165 {
166         struct input_handle *handle;
167         int error;
168
169         handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
170         if (!handle)
171                 return -ENOMEM;
172
173         handle->dev = dev;
174         handle->handler = handler;
175         handle->name = "rfkill";
176
177         /* causes rfkill_start() to be called */
178         error = input_register_handle(handle);
179         if (error)
180                 goto err_free_handle;
181
182         error = input_open_device(handle);
183         if (error)
184                 goto err_unregister_handle;
185
186         return 0;
187
188  err_unregister_handle:
189         input_unregister_handle(handle);
190  err_free_handle:
191         kfree(handle);
192         return error;
193 }
194
195 static void rfkill_start(struct input_handle *handle)
196 {
197         /* Take event_lock to guard against configuration changes, we
198          * should be able to deal with concurrency with rfkill_event()
199          * just fine (which event_lock will also avoid). */
200         spin_lock_irq(&handle->dev->event_lock);
201
202         if (test_bit(EV_SW, handle->dev->evbit)) {
203                 if (test_bit(SW_RFKILL_ALL, handle->dev->swbit))
204                         rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL,
205                                                         handle->dev->sw));
206                 /* add resync for further EV_SW events here */
207         }
208
209         spin_unlock_irq(&handle->dev->event_lock);
210 }
211
212 static void rfkill_disconnect(struct input_handle *handle)
213 {
214         input_close_device(handle);
215         input_unregister_handle(handle);
216         kfree(handle);
217 }
218
219 static const struct input_device_id rfkill_ids[] = {
220         {
221                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
222                 .evbit = { BIT_MASK(EV_KEY) },
223                 .keybit = { [BIT_WORD(KEY_WLAN)] = BIT_MASK(KEY_WLAN) },
224         },
225         {
226                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
227                 .evbit = { BIT_MASK(EV_KEY) },
228                 .keybit = { [BIT_WORD(KEY_BLUETOOTH)] = BIT_MASK(KEY_BLUETOOTH) },
229         },
230         {
231                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
232                 .evbit = { BIT_MASK(EV_KEY) },
233                 .keybit = { [BIT_WORD(KEY_UWB)] = BIT_MASK(KEY_UWB) },
234         },
235         {
236                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
237                 .evbit = { BIT_MASK(EV_KEY) },
238                 .keybit = { [BIT_WORD(KEY_WIMAX)] = BIT_MASK(KEY_WIMAX) },
239         },
240         {
241                 .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_SWBIT,
242                 .evbit = { BIT(EV_SW) },
243                 .swbit = { [BIT_WORD(SW_RFKILL_ALL)] = BIT_MASK(SW_RFKILL_ALL) },
244         },
245         { }
246 };
247
248 static struct input_handler rfkill_handler = {
249         .event =        rfkill_event,
250         .connect =      rfkill_connect,
251         .disconnect =   rfkill_disconnect,
252         .start =        rfkill_start,
253         .name =         "rfkill",
254         .id_table =     rfkill_ids,
255 };
256
257 static int __init rfkill_handler_init(void)
258 {
259         return input_register_handler(&rfkill_handler);
260 }
261
262 static void __exit rfkill_handler_exit(void)
263 {
264         input_unregister_handler(&rfkill_handler);
265         flush_scheduled_work();
266 }
267
268 module_init(rfkill_handler_init);
269 module_exit(rfkill_handler_exit);