diff options
Diffstat (limited to 'net/rfkill/rfkill.c')
-rw-r--r-- | net/rfkill/rfkill.c | 75 |
1 files changed, 61 insertions, 14 deletions
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"); | |||
39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ | 39 | static LIST_HEAD(rfkill_list); /* list of registered rf switches */ |
40 | static DEFINE_MUTEX(rfkill_mutex); | 40 | static DEFINE_MUTEX(rfkill_mutex); |
41 | 41 | ||
42 | static unsigned int rfkill_default_state = RFKILL_STATE_ON; | 42 | static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED; |
43 | module_param_named(default_state, rfkill_default_state, uint, 0444); | 43 | module_param_named(default_state, rfkill_default_state, uint, 0444); |
44 | MODULE_PARM_DESC(default_state, | 44 | MODULE_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 | */ | ||
131 | static int rfkill_toggle_radio(struct rfkill *rfkill, | 153 | static 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 | */ |
190 | void rfkill_epo(void) | 231 | void 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++) |