at v2.6.28-rc2 269 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#include <linux/sched.h> 20 21#include "rfkill-input.h" 22 23MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); 24MODULE_DESCRIPTION("Input layer to RF switch connector"); 25MODULE_LICENSE("GPL"); 26 27struct 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 36static 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 47static void rfkill_task_epo_handler(struct work_struct *work) 48{ 49 rfkill_epo(); 50} 51 52static DECLARE_WORK(epo_work, rfkill_task_epo_handler); 53 54static void rfkill_schedule_epo(void) 55{ 56 schedule_work(&epo_work); 57} 58 59static 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 78static 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 107static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); 108static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH); 109static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB); 110static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX); 111static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN); 112 113static 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 132static 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 163static 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 195static 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 212static void rfkill_disconnect(struct input_handle *handle) 213{ 214 input_close_device(handle); 215 input_unregister_handle(handle); 216 kfree(handle); 217} 218 219static 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 248static 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 257static int __init rfkill_handler_init(void) 258{ 259 return input_register_handler(&rfkill_handler); 260} 261 262static void __exit rfkill_handler_exit(void) 263{ 264 input_unregister_handler(&rfkill_handler); 265 flush_scheduled_work(); 266} 267 268module_init(rfkill_handler_init); 269module_exit(rfkill_handler_exit);