Blame view
net/rfkill/core.c
31 KB
19d337dff rfkill: rewrite |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/* * Copyright (C) 2006 - 2007 Ivo van Doorn * Copyright (C) 2007 Dmitry Torokhov * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License |
8232f1f3d rfkill: Fix FSF a... |
17 |
* along with this program; if not, see <http://www.gnu.org/licenses/>. |
19d337dff rfkill: rewrite |
18 19 20 21 22 23 24 25 26 27 |
*/ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/workqueue.h> #include <linux/capability.h> #include <linux/list.h> #include <linux/mutex.h> #include <linux/rfkill.h> |
a99bbaf5e headers: remove s... |
28 |
#include <linux/sched.h> |
19d337dff rfkill: rewrite |
29 |
#include <linux/spinlock.h> |
51990e825 device.h: cleanup... |
30 |
#include <linux/device.h> |
c64fb0162 rfkill: create us... |
31 32 33 34 |
#include <linux/miscdevice.h> #include <linux/wait.h> #include <linux/poll.h> #include <linux/fs.h> |
5a0e3ad6a include cleanup: ... |
35 |
#include <linux/slab.h> |
19d337dff rfkill: rewrite |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
#include "rfkill.h" #define POLL_INTERVAL (5 * HZ) #define RFKILL_BLOCK_HW BIT(0) #define RFKILL_BLOCK_SW BIT(1) #define RFKILL_BLOCK_SW_PREV BIT(2) #define RFKILL_BLOCK_ANY (RFKILL_BLOCK_HW |\ RFKILL_BLOCK_SW |\ RFKILL_BLOCK_SW_PREV) #define RFKILL_BLOCK_SW_SETCALL BIT(31) struct rfkill { spinlock_t lock; |
19d337dff rfkill: rewrite |
51 52 53 |
enum rfkill_type type; unsigned long state; |
c64fb0162 rfkill: create us... |
54 |
u32 idx; |
19d337dff rfkill: rewrite |
55 |
bool registered; |
b3fa1329e rfkill: remove se... |
56 |
bool persistent; |
dd21dfc64 rfkill: disentang... |
57 58 |
bool polling_paused; bool suspended; |
19d337dff rfkill: rewrite |
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
const struct rfkill_ops *ops; void *data; #ifdef CONFIG_RFKILL_LEDS struct led_trigger led_trigger; const char *ledtrigname; #endif struct device dev; struct list_head node; struct delayed_work poll_work; struct work_struct uevent_work; struct work_struct sync_work; |
b7bb11000 rfkill: copy the ... |
74 |
char name[]; |
19d337dff rfkill: rewrite |
75 76 |
}; #define to_rfkill(d) container_of(d, struct rfkill, dev) |
c64fb0162 rfkill: create us... |
77 78 79 80 81 82 83 84 85 86 87 88 |
struct rfkill_int_event { struct list_head list; struct rfkill_event ev; }; struct rfkill_data { struct list_head list; struct list_head events; struct mutex mtx; wait_queue_head_t read_wait; bool input_handler; }; |
19d337dff rfkill: rewrite |
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>"); MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); MODULE_DESCRIPTION("RF switch support"); MODULE_LICENSE("GPL"); /* * The locking here should be made much smarter, we currently have * a bit of a stupid situation because drivers might want to register * the rfkill struct under their own lock, and take this lock during * rfkill method calls -- which will cause an AB-BA deadlock situation. * * To fix that, we need to rework this code here to be mostly lock-free * and only use the mutex for list manipulations, not to protect the * various other global variables. Then we can avoid holding the mutex * around driver operations, and all is happy. */ static LIST_HEAD(rfkill_list); /* list of registered rf switches */ static DEFINE_MUTEX(rfkill_global_mutex); |
c64fb0162 rfkill: create us... |
110 |
static LIST_HEAD(rfkill_fds); /* list of open fds of /dev/rfkill */ |
19d337dff rfkill: rewrite |
111 112 113 114 115 116 117 |
static unsigned int rfkill_default_state = 1; module_param_named(default_state, rfkill_default_state, uint, 0444); MODULE_PARM_DESC(default_state, "Default initial state for all radio types, 0 = radio off"); static struct { |
b3fa1329e rfkill: remove se... |
118 |
bool cur, sav; |
19d337dff rfkill: rewrite |
119 |
} rfkill_global_states[NUM_RFKILL_TYPES]; |
19d337dff rfkill: rewrite |
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
static bool rfkill_epo_lock_active; #ifdef CONFIG_RFKILL_LEDS static void rfkill_led_trigger_event(struct rfkill *rfkill) { struct led_trigger *trigger; if (!rfkill->registered) return; trigger = &rfkill->led_trigger; if (rfkill->state & RFKILL_BLOCK_ANY) led_trigger_event(trigger, LED_OFF); else led_trigger_event(trigger, LED_FULL); } static void rfkill_led_trigger_activate(struct led_classdev *led) { struct rfkill *rfkill; rfkill = container_of(led->trigger, struct rfkill, led_trigger); rfkill_led_trigger_event(rfkill); } |
06d7de831 Revert "rfkill: r... |
147 148 149 150 151 152 153 154 155 156 157 158 159 |
const char *rfkill_get_led_trigger_name(struct rfkill *rfkill) { return rfkill->led_trigger.name; } EXPORT_SYMBOL(rfkill_get_led_trigger_name); void rfkill_set_led_trigger_name(struct rfkill *rfkill, const char *name) { BUG_ON(!rfkill); rfkill->ledtrigname = name; } EXPORT_SYMBOL(rfkill_set_led_trigger_name); |
19d337dff rfkill: rewrite |
160 161 162 163 164 165 166 167 168 169 170 171 |
static int rfkill_led_trigger_register(struct rfkill *rfkill) { rfkill->led_trigger.name = rfkill->ledtrigname ? : dev_name(&rfkill->dev); rfkill->led_trigger.activate = rfkill_led_trigger_activate; return led_trigger_register(&rfkill->led_trigger); } static void rfkill_led_trigger_unregister(struct rfkill *rfkill) { led_trigger_unregister(&rfkill->led_trigger); } |
9b8e34e21 rfkill: Add rfkil... |
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
static struct led_trigger rfkill_any_led_trigger; static struct work_struct rfkill_any_work; static void rfkill_any_led_trigger_worker(struct work_struct *work) { enum led_brightness brightness = LED_OFF; struct rfkill *rfkill; mutex_lock(&rfkill_global_mutex); list_for_each_entry(rfkill, &rfkill_list, node) { if (!(rfkill->state & RFKILL_BLOCK_ANY)) { brightness = LED_FULL; break; } } mutex_unlock(&rfkill_global_mutex); led_trigger_event(&rfkill_any_led_trigger, brightness); } static void rfkill_any_led_trigger_event(void) { schedule_work(&rfkill_any_work); } static void rfkill_any_led_trigger_activate(struct led_classdev *led_cdev) { rfkill_any_led_trigger_event(); } static int rfkill_any_led_trigger_register(void) { INIT_WORK(&rfkill_any_work, rfkill_any_led_trigger_worker); rfkill_any_led_trigger.name = "rfkill-any"; rfkill_any_led_trigger.activate = rfkill_any_led_trigger_activate; return led_trigger_register(&rfkill_any_led_trigger); } static void rfkill_any_led_trigger_unregister(void) { led_trigger_unregister(&rfkill_any_led_trigger); cancel_work_sync(&rfkill_any_work); } |
19d337dff rfkill: rewrite |
216 217 218 219 220 221 222 223 224 225 226 227 228 |
#else static void rfkill_led_trigger_event(struct rfkill *rfkill) { } static inline int rfkill_led_trigger_register(struct rfkill *rfkill) { return 0; } static inline void rfkill_led_trigger_unregister(struct rfkill *rfkill) { } |
9b8e34e21 rfkill: Add rfkil... |
229 230 231 232 233 234 235 236 237 238 239 240 241 |
static void rfkill_any_led_trigger_event(void) { } static int rfkill_any_led_trigger_register(void) { return 0; } static void rfkill_any_led_trigger_unregister(void) { } |
19d337dff rfkill: rewrite |
242 |
#endif /* CONFIG_RFKILL_LEDS */ |
c64fb0162 rfkill: create us... |
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
static void rfkill_fill_event(struct rfkill_event *ev, struct rfkill *rfkill, enum rfkill_operation op) { unsigned long flags; ev->idx = rfkill->idx; ev->type = rfkill->type; ev->op = op; spin_lock_irqsave(&rfkill->lock, flags); ev->hard = !!(rfkill->state & RFKILL_BLOCK_HW); ev->soft = !!(rfkill->state & (RFKILL_BLOCK_SW | RFKILL_BLOCK_SW_PREV)); spin_unlock_irqrestore(&rfkill->lock, flags); } static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op) { struct rfkill_data *data; struct rfkill_int_event *ev; list_for_each_entry(data, &rfkill_fds, list) { ev = kzalloc(sizeof(*ev), GFP_KERNEL); if (!ev) continue; rfkill_fill_event(&ev->ev, rfkill, op); mutex_lock(&data->mtx); list_add_tail(&ev->list, &data->events); mutex_unlock(&data->mtx); wake_up_interruptible(&data->read_wait); } } static void rfkill_event(struct rfkill *rfkill) |
19d337dff rfkill: rewrite |
277 |
{ |
06d5caf47 rfkill: don't res... |
278 |
if (!rfkill->registered) |
19d337dff rfkill: rewrite |
279 280 281 |
return; kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); |
c64fb0162 rfkill: create us... |
282 283 284 |
/* also send event to /dev/rfkill */ rfkill_send_events(rfkill, RFKILL_OP_CHANGE); |
19d337dff rfkill: rewrite |
285 |
} |
19d337dff rfkill: rewrite |
286 287 288 289 290 291 292 293 294 295 296 297 |
/** * rfkill_set_block - wrapper for set_block method * * @rfkill: the rfkill struct to use * @blocked: the new software state * * Calls the set_block method (when applicable) and handles notifications * etc. as well. */ static void rfkill_set_block(struct rfkill *rfkill, bool blocked) { unsigned long flags; |
eab48345c rfkill: prevent u... |
298 |
bool prev, curr; |
19d337dff rfkill: rewrite |
299 |
int err; |
7fa20a7f6 rfkill: rfkill_se... |
300 301 |
if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP)) return; |
19d337dff rfkill: rewrite |
302 303 304 305 306 307 308 309 310 |
/* * Some platforms (...!) generate input events which affect the * _hard_ kill state -- whenever something tries to change the * current software state query the hardware state too. */ if (rfkill->ops->query) rfkill->ops->query(rfkill, rfkill->data); spin_lock_irqsave(&rfkill->lock, flags); |
eab48345c rfkill: prevent u... |
311 |
prev = rfkill->state & RFKILL_BLOCK_SW; |
f3e7fae24 rfkill: use varia... |
312 |
if (prev) |
19d337dff rfkill: rewrite |
313 314 315 316 317 318 319 320 321 322 323 |
rfkill->state |= RFKILL_BLOCK_SW_PREV; else rfkill->state &= ~RFKILL_BLOCK_SW_PREV; if (blocked) rfkill->state |= RFKILL_BLOCK_SW; else rfkill->state &= ~RFKILL_BLOCK_SW; rfkill->state |= RFKILL_BLOCK_SW_SETCALL; spin_unlock_irqrestore(&rfkill->lock, flags); |
19d337dff rfkill: rewrite |
324 325 326 327 328 |
err = rfkill->ops->set_block(rfkill->data, blocked); spin_lock_irqsave(&rfkill->lock, flags); if (err) { /* |
3ff707d66 rfkill: Improve d... |
329 330 |
* Failed -- reset status to _PREV, which may be different * from what we have set _PREV to earlier in this function |
19d337dff rfkill: rewrite |
331 332 333 334 335 336 337 338 339 |
* if rfkill_set_sw_state was invoked. */ if (rfkill->state & RFKILL_BLOCK_SW_PREV) rfkill->state |= RFKILL_BLOCK_SW; else rfkill->state &= ~RFKILL_BLOCK_SW; } rfkill->state &= ~RFKILL_BLOCK_SW_SETCALL; rfkill->state &= ~RFKILL_BLOCK_SW_PREV; |
eab48345c rfkill: prevent u... |
340 |
curr = rfkill->state & RFKILL_BLOCK_SW; |
19d337dff rfkill: rewrite |
341 342 343 |
spin_unlock_irqrestore(&rfkill->lock, flags); rfkill_led_trigger_event(rfkill); |
9b8e34e21 rfkill: Add rfkil... |
344 |
rfkill_any_led_trigger_event(); |
eab48345c rfkill: prevent u... |
345 346 347 |
if (prev != curr) rfkill_event(rfkill); |
19d337dff rfkill: rewrite |
348 |
} |
9487bd6b9 rfkill: Factor rf... |
349 350 351 352 353 354 355 356 357 358 359 360 |
static void rfkill_update_global_state(enum rfkill_type type, bool blocked) { int i; if (type != RFKILL_TYPE_ALL) { rfkill_global_states[type].cur = blocked; return; } for (i = 0; i < NUM_RFKILL_TYPES; i++) rfkill_global_states[i].cur = blocked; } |
c64fb0162 rfkill: create us... |
361 362 |
#ifdef CONFIG_RFKILL_INPUT static atomic_t rfkill_input_disabled = ATOMIC_INIT(0); |
19d337dff rfkill: rewrite |
363 364 365 |
/** * __rfkill_switch_all - Toggle state of all switches of given type * @type: type of interfaces to be affected |
2f29fed3f net: rfkill: kern... |
366 |
* @blocked: the new state |
19d337dff rfkill: rewrite |
367 368 |
* * This function sets the state of all switches of given type, |
e2a35e892 rfkill: Remove ob... |
369 |
* unless a specific switch is suspended. |
19d337dff rfkill: rewrite |
370 371 372 373 374 375 |
* * Caller must have acquired rfkill_global_mutex. */ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) { struct rfkill *rfkill; |
9487bd6b9 rfkill: Factor rf... |
376 |
rfkill_update_global_state(type, blocked); |
19d337dff rfkill: rewrite |
377 |
list_for_each_entry(rfkill, &rfkill_list, node) { |
27e49ca95 rfkill: Add the c... |
378 |
if (rfkill->type != type && type != RFKILL_TYPE_ALL) |
19d337dff rfkill: rewrite |
379 380 381 382 383 384 385 386 387 |
continue; rfkill_set_block(rfkill, blocked); } } /** * rfkill_switch_all - Toggle state of all switches of given type * @type: type of interfaces to be affected |
2f29fed3f net: rfkill: kern... |
388 |
* @blocked: the new state |
19d337dff rfkill: rewrite |
389 390 391 392 393 394 395 396 |
* * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). * Please refer to __rfkill_switch_all() for details. * * Does nothing if the EPO lock is active. */ void rfkill_switch_all(enum rfkill_type type, bool blocked) { |
c64fb0162 rfkill: create us... |
397 398 |
if (atomic_read(&rfkill_input_disabled)) return; |
19d337dff rfkill: rewrite |
399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 |
mutex_lock(&rfkill_global_mutex); if (!rfkill_epo_lock_active) __rfkill_switch_all(type, blocked); mutex_unlock(&rfkill_global_mutex); } /** * rfkill_epo - emergency power off all transmitters * * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex. * * The global state before the EPO is saved and can be restored later * using rfkill_restore_states(). */ void rfkill_epo(void) { struct rfkill *rfkill; int i; |
c64fb0162 rfkill: create us... |
420 421 |
if (atomic_read(&rfkill_input_disabled)) return; |
19d337dff rfkill: rewrite |
422 423 424 425 426 427 428 |
mutex_lock(&rfkill_global_mutex); rfkill_epo_lock_active = true; list_for_each_entry(rfkill, &rfkill_list, node) rfkill_set_block(rfkill, true); for (i = 0; i < NUM_RFKILL_TYPES; i++) { |
b3fa1329e rfkill: remove se... |
429 |
rfkill_global_states[i].sav = rfkill_global_states[i].cur; |
19d337dff rfkill: rewrite |
430 431 |
rfkill_global_states[i].cur = true; } |
c64fb0162 rfkill: create us... |
432 |
|
19d337dff rfkill: rewrite |
433 434 435 436 437 438 439 440 441 442 443 444 445 |
mutex_unlock(&rfkill_global_mutex); } /** * rfkill_restore_states - restore global states * * Restore (and sync switches to) the global state from the * states in rfkill_default_states. This can undo the effects of * a call to rfkill_epo(). */ void rfkill_restore_states(void) { int i; |
c64fb0162 rfkill: create us... |
446 447 |
if (atomic_read(&rfkill_input_disabled)) return; |
19d337dff rfkill: rewrite |
448 449 450 451 |
mutex_lock(&rfkill_global_mutex); rfkill_epo_lock_active = false; for (i = 0; i < NUM_RFKILL_TYPES; i++) |
b3fa1329e rfkill: remove se... |
452 |
__rfkill_switch_all(i, rfkill_global_states[i].sav); |
19d337dff rfkill: rewrite |
453 454 455 456 457 458 459 460 461 462 463 |
mutex_unlock(&rfkill_global_mutex); } /** * rfkill_remove_epo_lock - unlock state changes * * Used by rfkill-input manually unlock state changes, when * the EPO switch is deactivated. */ void rfkill_remove_epo_lock(void) { |
c64fb0162 rfkill: create us... |
464 465 |
if (atomic_read(&rfkill_input_disabled)) return; |
19d337dff rfkill: rewrite |
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 |
mutex_lock(&rfkill_global_mutex); rfkill_epo_lock_active = false; mutex_unlock(&rfkill_global_mutex); } /** * rfkill_is_epo_lock_active - returns true EPO is active * * Returns 0 (false) if there is NOT an active EPO contidion, * and 1 (true) if there is an active EPO contition, which * locks all radios in one of the BLOCKED states. * * Can be called in atomic context. */ bool rfkill_is_epo_lock_active(void) { return rfkill_epo_lock_active; } /** * rfkill_get_global_sw_state - returns global state for a type * @type: the type to get the global state of * * Returns the current global state for a given wireless * device type. */ bool rfkill_get_global_sw_state(const enum rfkill_type type) { return rfkill_global_states[type].cur; } |
c64fb0162 rfkill: create us... |
496 |
#endif |
19d337dff rfkill: rewrite |
497 |
|
19d337dff rfkill: rewrite |
498 499 |
bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked) { |
1926e260d rfkill: remove/in... |
500 501 502 503 |
unsigned long flags; bool ret, prev; BUG_ON(!rfkill); |
19d337dff rfkill: rewrite |
504 |
|
1926e260d rfkill: remove/in... |
505 506 507 508 509 510 511 512 |
spin_lock_irqsave(&rfkill->lock, flags); prev = !!(rfkill->state & RFKILL_BLOCK_HW); if (blocked) rfkill->state |= RFKILL_BLOCK_HW; else rfkill->state &= ~RFKILL_BLOCK_HW; ret = !!(rfkill->state & RFKILL_BLOCK_ANY); spin_unlock_irqrestore(&rfkill->lock, flags); |
19d337dff rfkill: rewrite |
513 |
|
1926e260d rfkill: remove/in... |
514 |
rfkill_led_trigger_event(rfkill); |
9b8e34e21 rfkill: Add rfkil... |
515 |
rfkill_any_led_trigger_event(); |
19d337dff rfkill: rewrite |
516 |
|
74204f8fa rfkill: simplify ... |
517 |
if (rfkill->registered && prev != blocked) |
19d337dff rfkill: rewrite |
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 |
schedule_work(&rfkill->uevent_work); return ret; } EXPORT_SYMBOL(rfkill_set_hw_state); static void __rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) { u32 bit = RFKILL_BLOCK_SW; /* if in a ops->set_block right now, use other bit */ if (rfkill->state & RFKILL_BLOCK_SW_SETCALL) bit = RFKILL_BLOCK_SW_PREV; if (blocked) rfkill->state |= bit; else rfkill->state &= ~bit; } bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked) { unsigned long flags; bool prev, hwblock; BUG_ON(!rfkill); spin_lock_irqsave(&rfkill->lock, flags); prev = !!(rfkill->state & RFKILL_BLOCK_SW); __rfkill_set_sw_state(rfkill, blocked); hwblock = !!(rfkill->state & RFKILL_BLOCK_HW); blocked = blocked || hwblock; spin_unlock_irqrestore(&rfkill->lock, flags); |
06d5caf47 rfkill: don't res... |
551 552 |
if (!rfkill->registered) return blocked; |
19d337dff rfkill: rewrite |
553 |
|
06d5caf47 rfkill: don't res... |
554 555 556 557 |
if (prev != blocked && !hwblock) schedule_work(&rfkill->uevent_work); rfkill_led_trigger_event(rfkill); |
9b8e34e21 rfkill: Add rfkil... |
558 |
rfkill_any_led_trigger_event(); |
19d337dff rfkill: rewrite |
559 560 561 562 |
return blocked; } EXPORT_SYMBOL(rfkill_set_sw_state); |
06d5caf47 rfkill: don't res... |
563 564 565 566 567 568 569 570 571 572 573 574 575 |
void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked) { unsigned long flags; BUG_ON(!rfkill); BUG_ON(rfkill->registered); spin_lock_irqsave(&rfkill->lock, flags); __rfkill_set_sw_state(rfkill, blocked); rfkill->persistent = true; spin_unlock_irqrestore(&rfkill->lock, flags); } EXPORT_SYMBOL(rfkill_init_sw_state); |
19d337dff rfkill: rewrite |
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) { unsigned long flags; bool swprev, hwprev; BUG_ON(!rfkill); spin_lock_irqsave(&rfkill->lock, flags); /* * No need to care about prev/setblock ... this is for uevent only * and that will get triggered by rfkill_set_block anyway. */ swprev = !!(rfkill->state & RFKILL_BLOCK_SW); hwprev = !!(rfkill->state & RFKILL_BLOCK_HW); __rfkill_set_sw_state(rfkill, sw); |
48ab3578a rfkill: fix rfkil... |
592 593 594 595 |
if (hw) rfkill->state |= RFKILL_BLOCK_HW; else rfkill->state &= ~RFKILL_BLOCK_HW; |
19d337dff rfkill: rewrite |
596 597 |
spin_unlock_irqrestore(&rfkill->lock, flags); |
b3fa1329e rfkill: remove se... |
598 599 600 601 602 |
if (!rfkill->registered) { rfkill->persistent = true; } else { if (swprev != sw || hwprev != hw) schedule_work(&rfkill->uevent_work); |
19d337dff rfkill: rewrite |
603 |
|
b3fa1329e rfkill: remove se... |
604 |
rfkill_led_trigger_event(rfkill); |
9b8e34e21 rfkill: Add rfkil... |
605 |
rfkill_any_led_trigger_event(); |
b3fa1329e rfkill: remove se... |
606 |
} |
19d337dff rfkill: rewrite |
607 608 |
} EXPORT_SYMBOL(rfkill_set_states); |
648b50dd6 net: rfkill: add ... |
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 |
static const char * const rfkill_types[] = { NULL, /* RFKILL_TYPE_ALL */ "wlan", "bluetooth", "ultrawideband", "wimax", "wwan", "gps", "fm", "nfc", }; enum rfkill_type rfkill_find_type(const char *name) { int i; BUILD_BUG_ON(ARRAY_SIZE(rfkill_types) != NUM_RFKILL_TYPES); if (!name) return RFKILL_TYPE_ALL; for (i = 1; i < NUM_RFKILL_TYPES; i++) if (!strcmp(name, rfkill_types[i])) return i; return RFKILL_TYPE_ALL; } EXPORT_SYMBOL(rfkill_find_type); |
e49df67df net: rfkill: conv... |
636 637 |
static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) |
19d337dff rfkill: rewrite |
638 639 640 641 642 643 |
{ struct rfkill *rfkill = to_rfkill(dev); return sprintf(buf, "%s ", rfkill->name); } |
e49df67df net: rfkill: conv... |
644 |
static DEVICE_ATTR_RO(name); |
19d337dff rfkill: rewrite |
645 |
|
e49df67df net: rfkill: conv... |
646 647 |
static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) |
19d337dff rfkill: rewrite |
648 649 |
{ struct rfkill *rfkill = to_rfkill(dev); |
648b50dd6 net: rfkill: add ... |
650 651 |
return sprintf(buf, "%s ", rfkill_types[rfkill->type]); |
19d337dff rfkill: rewrite |
652 |
} |
e49df67df net: rfkill: conv... |
653 |
static DEVICE_ATTR_RO(type); |
19d337dff rfkill: rewrite |
654 |
|
e49df67df net: rfkill: conv... |
655 656 |
static ssize_t index_show(struct device *dev, struct device_attribute *attr, char *buf) |
c64fb0162 rfkill: create us... |
657 658 659 660 661 662 |
{ struct rfkill *rfkill = to_rfkill(dev); return sprintf(buf, "%d ", rfkill->idx); } |
e49df67df net: rfkill: conv... |
663 |
static DEVICE_ATTR_RO(index); |
c64fb0162 rfkill: create us... |
664 |
|
e49df67df net: rfkill: conv... |
665 666 |
static ssize_t persistent_show(struct device *dev, struct device_attribute *attr, char *buf) |
464902e81 rfkill: export pe... |
667 668 669 670 671 672 |
{ struct rfkill *rfkill = to_rfkill(dev); return sprintf(buf, "%d ", rfkill->persistent); } |
e49df67df net: rfkill: conv... |
673 |
static DEVICE_ATTR_RO(persistent); |
464902e81 rfkill: export pe... |
674 |
|
e49df67df net: rfkill: conv... |
675 676 |
static ssize_t hard_show(struct device *dev, struct device_attribute *attr, char *buf) |
6c26361e4 enhance sysfs rfk... |
677 678 |
{ struct rfkill *rfkill = to_rfkill(dev); |
6c26361e4 enhance sysfs rfk... |
679 |
|
819bfecc4 rename new rfkill... |
680 681 |
return sprintf(buf, "%d ", (rfkill->state & RFKILL_BLOCK_HW) ? 1 : 0 ); |
6c26361e4 enhance sysfs rfk... |
682 |
} |
e49df67df net: rfkill: conv... |
683 |
static DEVICE_ATTR_RO(hard); |
6c26361e4 enhance sysfs rfk... |
684 |
|
e49df67df net: rfkill: conv... |
685 686 |
static ssize_t soft_show(struct device *dev, struct device_attribute *attr, char *buf) |
6c26361e4 enhance sysfs rfk... |
687 688 |
{ struct rfkill *rfkill = to_rfkill(dev); |
6c26361e4 enhance sysfs rfk... |
689 |
|
819bfecc4 rename new rfkill... |
690 691 |
return sprintf(buf, "%d ", (rfkill->state & RFKILL_BLOCK_SW) ? 1 : 0 ); |
6c26361e4 enhance sysfs rfk... |
692 |
} |
e49df67df net: rfkill: conv... |
693 694 |
static ssize_t soft_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
6c26361e4 enhance sysfs rfk... |
695 696 697 698 699 700 701 |
{ struct rfkill *rfkill = to_rfkill(dev); unsigned long state; int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; |
1bac92cac net/rfkill/core.c... |
702 |
err = kstrtoul(buf, 0, &state); |
6c26361e4 enhance sysfs rfk... |
703 704 705 706 707 708 709 710 711 |
if (err) return err; if (state > 1 ) return -EINVAL; mutex_lock(&rfkill_global_mutex); rfkill_set_block(rfkill, state); mutex_unlock(&rfkill_global_mutex); |
6f7c962c0 rfkill: error can... |
712 |
return count; |
6c26361e4 enhance sysfs rfk... |
713 |
} |
e49df67df net: rfkill: conv... |
714 |
static DEVICE_ATTR_RW(soft); |
6c26361e4 enhance sysfs rfk... |
715 |
|
19d337dff rfkill: rewrite |
716 717 718 719 720 721 722 723 724 |
static u8 user_state_from_blocked(unsigned long state) { if (state & RFKILL_BLOCK_HW) return RFKILL_USER_STATE_HARD_BLOCKED; if (state & RFKILL_BLOCK_SW) return RFKILL_USER_STATE_SOFT_BLOCKED; return RFKILL_USER_STATE_UNBLOCKED; } |
e49df67df net: rfkill: conv... |
725 726 |
static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) |
19d337dff rfkill: rewrite |
727 728 |
{ struct rfkill *rfkill = to_rfkill(dev); |
19d337dff rfkill: rewrite |
729 |
|
819bfecc4 rename new rfkill... |
730 731 |
return sprintf(buf, "%d ", user_state_from_blocked(rfkill->state)); |
19d337dff rfkill: rewrite |
732 |
} |
e49df67df net: rfkill: conv... |
733 734 |
static ssize_t state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
19d337dff rfkill: rewrite |
735 |
{ |
f54c14272 rfkill: allow tog... |
736 737 738 739 740 741 |
struct rfkill *rfkill = to_rfkill(dev); unsigned long state; int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; |
1bac92cac net/rfkill/core.c... |
742 |
err = kstrtoul(buf, 0, &state); |
f54c14272 rfkill: allow tog... |
743 744 745 746 747 748 749 750 751 752 |
if (err) return err; if (state != RFKILL_USER_STATE_SOFT_BLOCKED && state != RFKILL_USER_STATE_UNBLOCKED) return -EINVAL; mutex_lock(&rfkill_global_mutex); rfkill_set_block(rfkill, state == RFKILL_USER_STATE_SOFT_BLOCKED); mutex_unlock(&rfkill_global_mutex); |
19d337dff rfkill: rewrite |
753 |
|
6f7c962c0 rfkill: error can... |
754 |
return count; |
19d337dff rfkill: rewrite |
755 |
} |
e49df67df net: rfkill: conv... |
756 |
static DEVICE_ATTR_RW(state); |
19d337dff rfkill: rewrite |
757 |
|
e49df67df net: rfkill: conv... |
758 759 760 761 762 763 |
static struct attribute *rfkill_dev_attrs[] = { &dev_attr_name.attr, &dev_attr_type.attr, &dev_attr_index.attr, &dev_attr_persistent.attr, &dev_attr_state.attr, |
e49df67df net: rfkill: conv... |
764 765 766 |
&dev_attr_soft.attr, &dev_attr_hard.attr, NULL, |
19d337dff rfkill: rewrite |
767 |
}; |
e49df67df net: rfkill: conv... |
768 |
ATTRIBUTE_GROUPS(rfkill_dev); |
19d337dff rfkill: rewrite |
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 |
static void rfkill_release(struct device *dev) { struct rfkill *rfkill = to_rfkill(dev); kfree(rfkill); } static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { struct rfkill *rfkill = to_rfkill(dev); unsigned long flags; u32 state; int error; error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name); if (error) return error; error = add_uevent_var(env, "RFKILL_TYPE=%s", |
648b50dd6 net: rfkill: add ... |
788 |
rfkill_types[rfkill->type]); |
19d337dff rfkill: rewrite |
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
if (error) return error; spin_lock_irqsave(&rfkill->lock, flags); state = rfkill->state; spin_unlock_irqrestore(&rfkill->lock, flags); error = add_uevent_var(env, "RFKILL_STATE=%d", user_state_from_blocked(state)); return error; } void rfkill_pause_polling(struct rfkill *rfkill) { BUG_ON(!rfkill); if (!rfkill->ops->poll) return; |
dd21dfc64 rfkill: disentang... |
805 |
rfkill->polling_paused = true; |
19d337dff rfkill: rewrite |
806 807 808 809 810 811 812 813 814 815 |
cancel_delayed_work_sync(&rfkill->poll_work); } EXPORT_SYMBOL(rfkill_pause_polling); void rfkill_resume_polling(struct rfkill *rfkill) { BUG_ON(!rfkill); if (!rfkill->ops->poll) return; |
dd21dfc64 rfkill: disentang... |
816 817 818 819 |
rfkill->polling_paused = false; if (rfkill->suspended) return; |
67235cbca net: rfkill: move... |
820 821 |
queue_delayed_work(system_power_efficient_wq, &rfkill->poll_work, 0); |
19d337dff rfkill: rewrite |
822 823 |
} EXPORT_SYMBOL(rfkill_resume_polling); |
28f297a7a net: rfkill: Swit... |
824 825 |
#ifdef CONFIG_PM_SLEEP static int rfkill_suspend(struct device *dev) |
19d337dff rfkill: rewrite |
826 827 |
{ struct rfkill *rfkill = to_rfkill(dev); |
dd21dfc64 rfkill: disentang... |
828 829 |
rfkill->suspended = true; cancel_delayed_work_sync(&rfkill->poll_work); |
19d337dff rfkill: rewrite |
830 |
|
19d337dff rfkill: rewrite |
831 832 833 834 835 836 837 |
return 0; } static int rfkill_resume(struct device *dev) { struct rfkill *rfkill = to_rfkill(dev); bool cur; |
dd21dfc64 rfkill: disentang... |
838 |
rfkill->suspended = false; |
06d5caf47 rfkill: don't res... |
839 840 841 842 |
if (!rfkill->persistent) { cur = !!(rfkill->state & RFKILL_BLOCK_SW); rfkill_set_block(rfkill, cur); } |
19d337dff rfkill: rewrite |
843 |
|
dd21dfc64 rfkill: disentang... |
844 845 846 |
if (rfkill->ops->poll && !rfkill->polling_paused) queue_delayed_work(system_power_efficient_wq, &rfkill->poll_work, 0); |
19d337dff rfkill: rewrite |
847 848 849 |
return 0; } |
28f297a7a net: rfkill: Swit... |
850 851 852 853 854 |
static SIMPLE_DEV_PM_OPS(rfkill_pm_ops, rfkill_suspend, rfkill_resume); #define RFKILL_PM_OPS (&rfkill_pm_ops) #else #define RFKILL_PM_OPS NULL #endif |
19d337dff rfkill: rewrite |
855 856 857 |
static struct class rfkill_class = { .name = "rfkill", .dev_release = rfkill_release, |
e49df67df net: rfkill: conv... |
858 |
.dev_groups = rfkill_dev_groups, |
19d337dff rfkill: rewrite |
859 |
.dev_uevent = rfkill_dev_uevent, |
28f297a7a net: rfkill: Swit... |
860 |
.pm = RFKILL_PM_OPS, |
19d337dff rfkill: rewrite |
861 |
}; |
6081162e2 rfkill: add funct... |
862 863 864 865 866 867 868 869 870 871 872 873 |
bool rfkill_blocked(struct rfkill *rfkill) { unsigned long flags; u32 state; spin_lock_irqsave(&rfkill->lock, flags); state = rfkill->state; spin_unlock_irqrestore(&rfkill->lock, flags); return !!(state & RFKILL_BLOCK_ANY); } EXPORT_SYMBOL(rfkill_blocked); |
19d337dff rfkill: rewrite |
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 |
struct rfkill * __must_check rfkill_alloc(const char *name, struct device *parent, const enum rfkill_type type, const struct rfkill_ops *ops, void *ops_data) { struct rfkill *rfkill; struct device *dev; if (WARN_ON(!ops)) return NULL; if (WARN_ON(!ops->set_block)) return NULL; if (WARN_ON(!name)) return NULL; |
c64fb0162 rfkill: create us... |
892 |
if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES)) |
19d337dff rfkill: rewrite |
893 |
return NULL; |
b7bb11000 rfkill: copy the ... |
894 |
rfkill = kzalloc(sizeof(*rfkill) + strlen(name) + 1, GFP_KERNEL); |
19d337dff rfkill: rewrite |
895 896 897 898 899 900 |
if (!rfkill) return NULL; spin_lock_init(&rfkill->lock); INIT_LIST_HEAD(&rfkill->node); rfkill->type = type; |
b7bb11000 rfkill: copy the ... |
901 |
strcpy(rfkill->name, name); |
19d337dff rfkill: rewrite |
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 |
rfkill->ops = ops; rfkill->data = ops_data; dev = &rfkill->dev; dev->class = &rfkill_class; dev->parent = parent; device_initialize(dev); return rfkill; } EXPORT_SYMBOL(rfkill_alloc); static void rfkill_poll(struct work_struct *work) { struct rfkill *rfkill; rfkill = container_of(work, struct rfkill, poll_work.work); /* * Poll hardware state -- driver will use one of the * rfkill_set{,_hw,_sw}_state functions and use its * return value to update the current status. */ rfkill->ops->poll(rfkill, rfkill->data); |
67235cbca net: rfkill: move... |
926 927 |
queue_delayed_work(system_power_efficient_wq, &rfkill->poll_work, |
19d337dff rfkill: rewrite |
928 929 930 931 932 933 934 935 |
round_jiffies_relative(POLL_INTERVAL)); } static void rfkill_uevent_work(struct work_struct *work) { struct rfkill *rfkill; rfkill = container_of(work, struct rfkill, uevent_work); |
c64fb0162 rfkill: create us... |
936 937 938 |
mutex_lock(&rfkill_global_mutex); rfkill_event(rfkill); mutex_unlock(&rfkill_global_mutex); |
19d337dff rfkill: rewrite |
939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 |
} static void rfkill_sync_work(struct work_struct *work) { struct rfkill *rfkill; bool cur; rfkill = container_of(work, struct rfkill, sync_work); mutex_lock(&rfkill_global_mutex); cur = rfkill_global_states[rfkill->type].cur; rfkill_set_block(rfkill, cur); mutex_unlock(&rfkill_global_mutex); } int __must_check rfkill_register(struct rfkill *rfkill) { static unsigned long rfkill_no; struct device *dev = &rfkill->dev; int error; BUG_ON(!rfkill); mutex_lock(&rfkill_global_mutex); if (rfkill->registered) { error = -EALREADY; goto unlock; } |
c64fb0162 rfkill: create us... |
968 |
rfkill->idx = rfkill_no; |
19d337dff rfkill: rewrite |
969 970 |
dev_set_name(dev, "rfkill%lu", rfkill_no); rfkill_no++; |
19d337dff rfkill: rewrite |
971 972 973 974 975 976 977 978 979 980 981 |
list_add_tail(&rfkill->node, &rfkill_list); error = device_add(dev); if (error) goto remove; error = rfkill_led_trigger_register(rfkill); if (error) goto devdel; rfkill->registered = true; |
2ec2c68c1 rfkill: always in... |
982 |
INIT_DELAYED_WORK(&rfkill->poll_work, rfkill_poll); |
19d337dff rfkill: rewrite |
983 |
INIT_WORK(&rfkill->uevent_work, rfkill_uevent_work); |
19d337dff rfkill: rewrite |
984 |
INIT_WORK(&rfkill->sync_work, rfkill_sync_work); |
2ec2c68c1 rfkill: always in... |
985 986 |
if (rfkill->ops->poll) |
67235cbca net: rfkill: move... |
987 988 |
queue_delayed_work(system_power_efficient_wq, &rfkill->poll_work, |
2ec2c68c1 rfkill: always in... |
989 |
round_jiffies_relative(POLL_INTERVAL)); |
b3fa1329e rfkill: remove se... |
990 991 992 993 994 995 996 997 998 999 1000 |
if (!rfkill->persistent || rfkill_epo_lock_active) { schedule_work(&rfkill->sync_work); } else { #ifdef CONFIG_RFKILL_INPUT bool soft_blocked = !!(rfkill->state & RFKILL_BLOCK_SW); if (!atomic_read(&rfkill_input_disabled)) __rfkill_switch_all(rfkill->type, soft_blocked); #endif } |
2ec2c68c1 rfkill: always in... |
1001 |
|
9b8e34e21 rfkill: Add rfkil... |
1002 |
rfkill_any_led_trigger_event(); |
c64fb0162 rfkill: create us... |
1003 |
rfkill_send_events(rfkill, RFKILL_OP_ADD); |
19d337dff rfkill: rewrite |
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 |
mutex_unlock(&rfkill_global_mutex); return 0; devdel: device_del(&rfkill->dev); remove: list_del_init(&rfkill->node); unlock: mutex_unlock(&rfkill_global_mutex); return error; } EXPORT_SYMBOL(rfkill_register); void rfkill_unregister(struct rfkill *rfkill) { BUG_ON(!rfkill); if (rfkill->ops->poll) cancel_delayed_work_sync(&rfkill->poll_work); cancel_work_sync(&rfkill->uevent_work); cancel_work_sync(&rfkill->sync_work); rfkill->registered = false; device_del(&rfkill->dev); mutex_lock(&rfkill_global_mutex); |
c64fb0162 rfkill: create us... |
1033 |
rfkill_send_events(rfkill, RFKILL_OP_DEL); |
19d337dff rfkill: rewrite |
1034 |
list_del_init(&rfkill->node); |
9b8e34e21 rfkill: Add rfkil... |
1035 |
rfkill_any_led_trigger_event(); |
19d337dff rfkill: rewrite |
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
mutex_unlock(&rfkill_global_mutex); rfkill_led_trigger_unregister(rfkill); } EXPORT_SYMBOL(rfkill_unregister); void rfkill_destroy(struct rfkill *rfkill) { if (rfkill) put_device(&rfkill->dev); } EXPORT_SYMBOL(rfkill_destroy); |
c64fb0162 rfkill: create us... |
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 |
static int rfkill_fop_open(struct inode *inode, struct file *file) { struct rfkill_data *data; struct rfkill *rfkill; struct rfkill_int_event *ev, *tmp; data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; INIT_LIST_HEAD(&data->events); mutex_init(&data->mtx); init_waitqueue_head(&data->read_wait); mutex_lock(&rfkill_global_mutex); mutex_lock(&data->mtx); /* * start getting events from elsewhere but hold mtx to get * startup events added first */ |
c64fb0162 rfkill: create us... |
1068 1069 1070 1071 1072 1073 1074 1075 |
list_for_each_entry(rfkill, &rfkill_list, node) { ev = kzalloc(sizeof(*ev), GFP_KERNEL); if (!ev) goto free; rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD); list_add_tail(&ev->list, &data->events); } |
bd2281b85 net/rfkill/core.c... |
1076 |
list_add(&data->list, &rfkill_fds); |
c64fb0162 rfkill: create us... |
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 |
mutex_unlock(&data->mtx); mutex_unlock(&rfkill_global_mutex); file->private_data = data; return nonseekable_open(inode, file); free: mutex_unlock(&data->mtx); mutex_unlock(&rfkill_global_mutex); mutex_destroy(&data->mtx); list_for_each_entry_safe(ev, tmp, &data->events, list) kfree(ev); kfree(data); return -ENOMEM; } static unsigned int rfkill_fop_poll(struct file *file, poll_table *wait) { struct rfkill_data *data = file->private_data; unsigned int res = POLLOUT | POLLWRNORM; poll_wait(file, &data->read_wait, wait); mutex_lock(&data->mtx); if (!list_empty(&data->events)) res = POLLIN | POLLRDNORM; mutex_unlock(&data->mtx); return res; } |
c64fb0162 rfkill: create us... |
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 |
static ssize_t rfkill_fop_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct rfkill_data *data = file->private_data; struct rfkill_int_event *ev; unsigned long sz; int ret; mutex_lock(&data->mtx); while (list_empty(&data->events)) { if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; goto out; } mutex_unlock(&data->mtx); |
6736fde96 rfkill: fix rfkil... |
1124 1125 1126 |
/* since we re-check and it just compares pointers, * using !list_empty() without locking isn't a problem */ |
c64fb0162 rfkill: create us... |
1127 |
ret = wait_event_interruptible(data->read_wait, |
6736fde96 rfkill: fix rfkil... |
1128 |
!list_empty(&data->events)); |
c64fb0162 rfkill: create us... |
1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 |
mutex_lock(&data->mtx); if (ret) goto out; } ev = list_first_entry(&data->events, struct rfkill_int_event, list); sz = min_t(unsigned long, sizeof(ev->ev), count); ret = sz; if (copy_to_user(buf, &ev->ev, sz)) ret = -EFAULT; list_del(&ev->list); kfree(ev); out: mutex_unlock(&data->mtx); return ret; } static ssize_t rfkill_fop_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) { struct rfkill *rfkill; struct rfkill_event ev; |
1948b2a2e rfkill: Use switc... |
1155 |
int ret; |
c64fb0162 rfkill: create us... |
1156 1157 |
/* we don't need the 'hard' variable but accept it */ |
1be491fca rfkill: prep for ... |
1158 |
if (count < RFKILL_EVENT_SIZE_V1 - 1) |
c64fb0162 rfkill: create us... |
1159 |
return -EINVAL; |
1be491fca rfkill: prep for ... |
1160 1161 1162 1163 1164 1165 1166 |
/* * Copy as much data as we can accept into our 'ev' buffer, * but tell userspace how much we've copied so it can determine * our API version even in a write() call, if it cares. */ count = min(count, sizeof(ev)); if (copy_from_user(&ev, buf, count)) |
c64fb0162 rfkill: create us... |
1167 |
return -EFAULT; |
c64fb0162 rfkill: create us... |
1168 1169 1170 1171 |
if (ev.type >= NUM_RFKILL_TYPES) return -EINVAL; mutex_lock(&rfkill_global_mutex); |
1948b2a2e rfkill: Use switc... |
1172 1173 |
switch (ev.op) { case RFKILL_OP_CHANGE_ALL: |
9487bd6b9 rfkill: Factor rf... |
1174 |
rfkill_update_global_state(ev.type, ev.soft); |
1948b2a2e rfkill: Use switc... |
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 |
list_for_each_entry(rfkill, &rfkill_list, node) if (rfkill->type == ev.type || ev.type == RFKILL_TYPE_ALL) rfkill_set_block(rfkill, ev.soft); ret = 0; break; case RFKILL_OP_CHANGE: list_for_each_entry(rfkill, &rfkill_list, node) if (rfkill->idx == ev.idx && (rfkill->type == ev.type || ev.type == RFKILL_TYPE_ALL)) rfkill_set_block(rfkill, ev.soft); ret = 0; break; default: ret = -EINVAL; break; |
c64fb0162 rfkill: create us... |
1192 |
} |
1948b2a2e rfkill: Use switc... |
1193 |
|
c64fb0162 rfkill: create us... |
1194 |
mutex_unlock(&rfkill_global_mutex); |
1948b2a2e rfkill: Use switc... |
1195 |
return ret ?: count; |
c64fb0162 rfkill: create us... |
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 |
} static int rfkill_fop_release(struct inode *inode, struct file *file) { struct rfkill_data *data = file->private_data; struct rfkill_int_event *ev, *tmp; mutex_lock(&rfkill_global_mutex); list_del(&data->list); mutex_unlock(&rfkill_global_mutex); mutex_destroy(&data->mtx); list_for_each_entry_safe(ev, tmp, &data->events, list) kfree(ev); #ifdef CONFIG_RFKILL_INPUT if (data->input_handler) |
207ee1621 rfkill: print eve... |
1213 1214 1215 |
if (atomic_dec_return(&rfkill_input_disabled) == 0) printk(KERN_DEBUG "rfkill: input handler enabled "); |
c64fb0162 rfkill: create us... |
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 |
#endif kfree(data); return 0; } #ifdef CONFIG_RFKILL_INPUT static long rfkill_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct rfkill_data *data = file->private_data; if (_IOC_TYPE(cmd) != RFKILL_IOC_MAGIC) return -ENOSYS; if (_IOC_NR(cmd) != RFKILL_IOC_NOINPUT) return -ENOSYS; mutex_lock(&data->mtx); if (!data->input_handler) { |
207ee1621 rfkill: print eve... |
1238 1239 1240 |
if (atomic_inc_return(&rfkill_input_disabled) == 1) printk(KERN_DEBUG "rfkill: input handler disabled "); |
c64fb0162 rfkill: create us... |
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 |
data->input_handler = true; } mutex_unlock(&data->mtx); return 0; } #endif static const struct file_operations rfkill_fops = { |
45ba564d7 rfkill: fix miscd... |
1251 |
.owner = THIS_MODULE, |
c64fb0162 rfkill: create us... |
1252 1253 1254 1255 1256 1257 1258 1259 1260 |
.open = rfkill_fop_open, .read = rfkill_fop_read, .write = rfkill_fop_write, .poll = rfkill_fop_poll, .release = rfkill_fop_release, #ifdef CONFIG_RFKILL_INPUT .unlocked_ioctl = rfkill_fop_ioctl, .compat_ioctl = rfkill_fop_ioctl, #endif |
6038f373a llseek: automatic... |
1261 |
.llseek = no_llseek, |
c64fb0162 rfkill: create us... |
1262 1263 1264 1265 1266 1267 1268 |
}; static struct miscdevice rfkill_miscdev = { .name = "rfkill", .fops = &rfkill_fops, .minor = MISC_DYNAMIC_MINOR, }; |
19d337dff rfkill: rewrite |
1269 1270 1271 1272 |
static int __init rfkill_init(void) { int error; |
19d337dff rfkill: rewrite |
1273 |
|
9487bd6b9 rfkill: Factor rf... |
1274 |
rfkill_update_global_state(RFKILL_TYPE_ALL, !rfkill_default_state); |
19d337dff rfkill: rewrite |
1275 1276 1277 |
error = class_register(&rfkill_class); if (error) |
6124c53ed rfkill: Cleanup e... |
1278 |
goto error_class; |
19d337dff rfkill: rewrite |
1279 |
|
c64fb0162 rfkill: create us... |
1280 |
error = misc_register(&rfkill_miscdev); |
6124c53ed rfkill: Cleanup e... |
1281 1282 |
if (error) goto error_misc; |
c64fb0162 rfkill: create us... |
1283 |
|
9b8e34e21 rfkill: Add rfkil... |
1284 1285 1286 |
error = rfkill_any_led_trigger_register(); if (error) goto error_led_trigger; |
19d337dff rfkill: rewrite |
1287 1288 |
#ifdef CONFIG_RFKILL_INPUT error = rfkill_handler_init(); |
6124c53ed rfkill: Cleanup e... |
1289 1290 |
if (error) goto error_input; |
19d337dff rfkill: rewrite |
1291 |
#endif |
6124c53ed rfkill: Cleanup e... |
1292 |
return 0; |
f6b4122c9 rfkill: hide unus... |
1293 |
#ifdef CONFIG_RFKILL_INPUT |
6124c53ed rfkill: Cleanup e... |
1294 |
error_input: |
9b8e34e21 rfkill: Add rfkil... |
1295 |
rfkill_any_led_trigger_unregister(); |
7b854982b Revert "rfkill: A... |
1296 |
#endif |
9b8e34e21 rfkill: Add rfkil... |
1297 1298 |
error_led_trigger: misc_deregister(&rfkill_miscdev); |
6124c53ed rfkill: Cleanup e... |
1299 1300 1301 |
error_misc: class_unregister(&rfkill_class); error_class: |
19d337dff rfkill: rewrite |
1302 1303 1304 1305 1306 1307 1308 1309 1310 |
return error; } subsys_initcall(rfkill_init); static void __exit rfkill_exit(void) { #ifdef CONFIG_RFKILL_INPUT rfkill_handler_exit(); #endif |
9b8e34e21 rfkill: Add rfkil... |
1311 |
rfkill_any_led_trigger_unregister(); |
c64fb0162 rfkill: create us... |
1312 |
misc_deregister(&rfkill_miscdev); |
19d337dff rfkill: rewrite |
1313 1314 1315 |
class_unregister(&rfkill_class); } module_exit(rfkill_exit); |