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