aboutsummaryrefslogtreecommitdiffstats
path: root/net/rfkill
diff options
context:
space:
mode:
Diffstat (limited to 'net/rfkill')
-rw-r--r--net/rfkill/rfkill-input.c29
-rw-r--r--net/rfkill/rfkill.c75
2 files changed, 76 insertions, 28 deletions
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index 5d4c8b2446f7..8aa822730145 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -84,7 +84,8 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
84 spin_lock_irqsave(&task->lock, flags); 84 spin_lock_irqsave(&task->lock, flags);
85 85
86 if (time_after(jiffies, task->last + msecs_to_jiffies(200))) { 86 if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
87 task->desired_state = !task->desired_state; 87 task->desired_state =
88 rfkill_state_complement(task->desired_state);
88 task->last = jiffies; 89 task->last = jiffies;
89 schedule_work(&task->work); 90 schedule_work(&task->work);
90 } 91 }
@@ -92,14 +93,14 @@ static void rfkill_schedule_toggle(struct rfkill_task *task)
92 spin_unlock_irqrestore(&task->lock, flags); 93 spin_unlock_irqrestore(&task->lock, flags);
93} 94}
94 95
95#define DEFINE_RFKILL_TASK(n, t) \ 96#define DEFINE_RFKILL_TASK(n, t) \
96 struct rfkill_task n = { \ 97 struct rfkill_task n = { \
97 .work = __WORK_INITIALIZER(n.work, \ 98 .work = __WORK_INITIALIZER(n.work, \
98 rfkill_task_handler), \ 99 rfkill_task_handler), \
99 .type = t, \ 100 .type = t, \
100 .mutex = __MUTEX_INITIALIZER(n.mutex), \ 101 .mutex = __MUTEX_INITIALIZER(n.mutex), \
101 .lock = __SPIN_LOCK_UNLOCKED(n.lock), \ 102 .lock = __SPIN_LOCK_UNLOCKED(n.lock), \
102 .desired_state = RFKILL_STATE_ON, \ 103 .desired_state = RFKILL_STATE_UNBLOCKED, \
103 } 104 }
104 105
105static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); 106static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
@@ -135,15 +136,15 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
135 /* handle EPO (emergency power off) through shortcut */ 136 /* handle EPO (emergency power off) through shortcut */
136 if (data) { 137 if (data) {
137 rfkill_schedule_set(&rfkill_wwan, 138 rfkill_schedule_set(&rfkill_wwan,
138 RFKILL_STATE_ON); 139 RFKILL_STATE_UNBLOCKED);
139 rfkill_schedule_set(&rfkill_wimax, 140 rfkill_schedule_set(&rfkill_wimax,
140 RFKILL_STATE_ON); 141 RFKILL_STATE_UNBLOCKED);
141 rfkill_schedule_set(&rfkill_uwb, 142 rfkill_schedule_set(&rfkill_uwb,
142 RFKILL_STATE_ON); 143 RFKILL_STATE_UNBLOCKED);
143 rfkill_schedule_set(&rfkill_bt, 144 rfkill_schedule_set(&rfkill_bt,
144 RFKILL_STATE_ON); 145 RFKILL_STATE_UNBLOCKED);
145 rfkill_schedule_set(&rfkill_wlan, 146 rfkill_schedule_set(&rfkill_wlan,
146 RFKILL_STATE_ON); 147 RFKILL_STATE_UNBLOCKED);
147 } else 148 } else
148 rfkill_schedule_epo(); 149 rfkill_schedule_epo();
149 break; 150 break;
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 7d07175c407f..ce0e23148cdd 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -39,7 +39,7 @@ MODULE_LICENSE("GPL");
39static LIST_HEAD(rfkill_list); /* list of registered rf switches */ 39static LIST_HEAD(rfkill_list); /* list of registered rf switches */
40static DEFINE_MUTEX(rfkill_mutex); 40static DEFINE_MUTEX(rfkill_mutex);
41 41
42static unsigned int rfkill_default_state = RFKILL_STATE_ON; 42static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED;
43module_param_named(default_state, rfkill_default_state, uint, 0444); 43module_param_named(default_state, rfkill_default_state, uint, 0444);
44MODULE_PARM_DESC(default_state, 44MODULE_PARM_DESC(default_state,
45 "Default initial state for all radio types, 0 = radio off"); 45 "Default initial state for all radio types, 0 = radio off");
@@ -98,7 +98,7 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
98 98
99 if (!led->name) 99 if (!led->name)
100 return; 100 return;
101 if (state == RFKILL_STATE_OFF) 101 if (state != RFKILL_STATE_UNBLOCKED)
102 led_trigger_event(led, LED_OFF); 102 led_trigger_event(led, LED_OFF);
103 else 103 else
104 led_trigger_event(led, LED_FULL); 104 led_trigger_event(led, LED_FULL);
@@ -128,6 +128,28 @@ static void update_rfkill_state(struct rfkill *rfkill)
128 } 128 }
129} 129}
130 130
131/**
132 * rfkill_toggle_radio - wrapper for toggle_radio hook
133 * calls toggle_radio taking into account a lot of "small"
134 * details.
135 * @rfkill: the rfkill struct to use
136 * @force: calls toggle_radio even if cache says it is not needed,
137 * and also makes sure notifications of the state will be
138 * sent even if it didn't change
139 * @state: the new state to call toggle_radio() with
140 *
141 * This wrappen protects and enforces the API for toggle_radio
142 * calls. Note that @force cannot override a (possibly cached)
143 * state of RFKILL_STATE_HARD_BLOCKED. Any device making use of
144 * RFKILL_STATE_HARD_BLOCKED implements either get_state() or
145 * rfkill_force_state(), so the cache either is bypassed or valid.
146 *
147 * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED
148 * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to
149 * give the driver a hint that it should double-BLOCK the transmitter.
150 *
151 * Caller must have aquired rfkill_mutex.
152 */
131static int rfkill_toggle_radio(struct rfkill *rfkill, 153static int rfkill_toggle_radio(struct rfkill *rfkill,
132 enum rfkill_state state, 154 enum rfkill_state state,
133 int force) 155 int force)
@@ -141,9 +163,28 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
141 !rfkill->get_state(rfkill->data, &newstate)) 163 !rfkill->get_state(rfkill->data, &newstate))
142 rfkill->state = newstate; 164 rfkill->state = newstate;
143 165
166 switch (state) {
167 case RFKILL_STATE_HARD_BLOCKED:
168 /* typically happens when refreshing hardware state,
169 * such as on resume */
170 state = RFKILL_STATE_SOFT_BLOCKED;
171 break;
172 case RFKILL_STATE_UNBLOCKED:
173 /* force can't override this, only rfkill_force_state() can */
174 if (rfkill->state == RFKILL_STATE_HARD_BLOCKED)
175 return -EPERM;
176 break;
177 case RFKILL_STATE_SOFT_BLOCKED:
178 /* nothing to do, we want to give drivers the hint to double
179 * BLOCK even a transmitter that is already in state
180 * RFKILL_STATE_HARD_BLOCKED */
181 break;
182 }
183
144 if (force || state != rfkill->state) { 184 if (force || state != rfkill->state) {
145 retval = rfkill->toggle_radio(rfkill->data, state); 185 retval = rfkill->toggle_radio(rfkill->data, state);
146 if (!retval) 186 /* never allow a HARD->SOFT downgrade! */
187 if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED)
147 rfkill->state = state; 188 rfkill->state = state;
148 } 189 }
149 190
@@ -184,7 +225,7 @@ EXPORT_SYMBOL(rfkill_switch_all);
184/** 225/**
185 * rfkill_epo - emergency power off all transmitters 226 * rfkill_epo - emergency power off all transmitters
186 * 227 *
187 * This kicks all rfkill devices to RFKILL_STATE_OFF, ignoring 228 * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring
188 * everything in its path but rfkill_mutex. 229 * everything in its path but rfkill_mutex.
189 */ 230 */
190void rfkill_epo(void) 231void rfkill_epo(void)
@@ -193,7 +234,7 @@ void rfkill_epo(void)
193 234
194 mutex_lock(&rfkill_mutex); 235 mutex_lock(&rfkill_mutex);
195 list_for_each_entry(rfkill, &rfkill_list, node) { 236 list_for_each_entry(rfkill, &rfkill_list, node) {
196 rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF, 1); 237 rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
197 } 238 }
198 mutex_unlock(&rfkill_mutex); 239 mutex_unlock(&rfkill_mutex);
199} 240}
@@ -215,8 +256,9 @@ int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
215{ 256{
216 enum rfkill_state oldstate; 257 enum rfkill_state oldstate;
217 258
218 if (state != RFKILL_STATE_OFF && 259 if (state != RFKILL_STATE_SOFT_BLOCKED &&
219 state != RFKILL_STATE_ON) 260 state != RFKILL_STATE_UNBLOCKED &&
261 state != RFKILL_STATE_HARD_BLOCKED)
220 return -EINVAL; 262 return -EINVAL;
221 263
222 mutex_lock(&rfkill->mutex); 264 mutex_lock(&rfkill->mutex);
@@ -290,11 +332,14 @@ static ssize_t rfkill_state_store(struct device *dev,
290 if (!capable(CAP_NET_ADMIN)) 332 if (!capable(CAP_NET_ADMIN))
291 return -EPERM; 333 return -EPERM;
292 334
335 /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
336 if (state != RFKILL_STATE_UNBLOCKED &&
337 state != RFKILL_STATE_SOFT_BLOCKED)
338 return -EINVAL;
339
293 if (mutex_lock_interruptible(&rfkill->mutex)) 340 if (mutex_lock_interruptible(&rfkill->mutex))
294 return -ERESTARTSYS; 341 return -ERESTARTSYS;
295 error = rfkill_toggle_radio(rfkill, 342 error = rfkill_toggle_radio(rfkill, state, 0);
296 state ? RFKILL_STATE_ON : RFKILL_STATE_OFF,
297 0);
298 mutex_unlock(&rfkill->mutex); 343 mutex_unlock(&rfkill->mutex);
299 344
300 return error ? error : count; 345 return error ? error : count;
@@ -373,7 +418,8 @@ static int rfkill_suspend(struct device *dev, pm_message_t state)
373 update_rfkill_state(rfkill); 418 update_rfkill_state(rfkill);
374 419
375 mutex_lock(&rfkill->mutex); 420 mutex_lock(&rfkill->mutex);
376 rfkill->toggle_radio(rfkill->data, RFKILL_STATE_OFF); 421 rfkill->toggle_radio(rfkill->data,
422 RFKILL_STATE_SOFT_BLOCKED);
377 mutex_unlock(&rfkill->mutex); 423 mutex_unlock(&rfkill->mutex);
378 } 424 }
379 425
@@ -470,7 +516,7 @@ static void rfkill_remove_switch(struct rfkill *rfkill)
470{ 516{
471 mutex_lock(&rfkill_mutex); 517 mutex_lock(&rfkill_mutex);
472 list_del_init(&rfkill->node); 518 list_del_init(&rfkill->node);
473 rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF, 1); 519 rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
474 mutex_unlock(&rfkill_mutex); 520 mutex_unlock(&rfkill_mutex);
475} 521}
476 522
@@ -610,8 +656,9 @@ static int __init rfkill_init(void)
610 int error; 656 int error;
611 int i; 657 int i;
612 658
613 if (rfkill_default_state != RFKILL_STATE_OFF && 659 /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
614 rfkill_default_state != RFKILL_STATE_ON) 660 if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED &&
661 rfkill_default_state != RFKILL_STATE_UNBLOCKED)
615 return -EINVAL; 662 return -EINVAL;
616 663
617 for (i = 0; i < ARRAY_SIZE(rfkill_states); i++) 664 for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)