diff options
author | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 2008-08-02 14:10:58 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-08-22 16:29:56 -0400 |
commit | 9961920199ec88d6b581d3e38502088935925c04 (patch) | |
tree | 38a20b8d4441b4b2a6e033bc9e7a7e6863e72397 /net/rfkill/rfkill.c | |
parent | 02589f60510030a3c1496e7a8c511e4f674ef5ff (diff) |
rfkill: add default global states (v2)
Add a second set of global states, "rfkill_default_states", to track the
state that will be used when the first rfkill class of a given type is
registered, and also to save "undo" information when rfkill_epo is called.
Add a new exported function, rfkill_set_default(), which can be used by
platform drivers to restore radio state saved by the platform across
reboots or shutdown.
Also, fix rfkill_epo to properly update rfkill_states, but still preserve a
copy of the state so that we can undo the effect of rfkill_epo later if we
want to. Add rfkill_restore_states() to restore rfkill_states from the
copy.
Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/rfkill/rfkill.c')
-rw-r--r-- | net/rfkill/rfkill.c | 127 |
1 files changed, 115 insertions, 12 deletions
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 1f23de20a85e..b995fa32cf84 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c | |||
@@ -44,7 +44,13 @@ 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"); |
46 | 46 | ||
47 | static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX]; | 47 | struct rfkill_gsw_state { |
48 | enum rfkill_state current_state; | ||
49 | enum rfkill_state default_state; | ||
50 | }; | ||
51 | |||
52 | static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX]; | ||
53 | static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; | ||
48 | 54 | ||
49 | static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); | 55 | static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); |
50 | 56 | ||
@@ -213,22 +219,22 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, | |||
213 | } | 219 | } |
214 | 220 | ||
215 | /** | 221 | /** |
216 | * rfkill_switch_all - Toggle state of all switches of given type | 222 | * __rfkill_switch_all - Toggle state of all switches of given type |
217 | * @type: type of interfaces to be affected | 223 | * @type: type of interfaces to be affected |
218 | * @state: the new state | 224 | * @state: the new state |
219 | * | 225 | * |
220 | * This function toggles the state of all switches of given type, | 226 | * This function toggles the state of all switches of given type, |
221 | * unless a specific switch is claimed by userspace (in which case, | 227 | * unless a specific switch is claimed by userspace (in which case, |
222 | * that switch is left alone) or suspended. | 228 | * that switch is left alone) or suspended. |
229 | * | ||
230 | * Caller must have acquired rfkill_mutex. | ||
223 | */ | 231 | */ |
224 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | 232 | static void __rfkill_switch_all(const enum rfkill_type type, |
233 | const enum rfkill_state state) | ||
225 | { | 234 | { |
226 | struct rfkill *rfkill; | 235 | struct rfkill *rfkill; |
227 | 236 | ||
228 | mutex_lock(&rfkill_mutex); | 237 | rfkill_global_states[type].current_state = state; |
229 | |||
230 | rfkill_states[type] = state; | ||
231 | |||
232 | list_for_each_entry(rfkill, &rfkill_list, node) { | 238 | list_for_each_entry(rfkill, &rfkill_list, node) { |
233 | if ((!rfkill->user_claim) && (rfkill->type == type)) { | 239 | if ((!rfkill->user_claim) && (rfkill->type == type)) { |
234 | mutex_lock(&rfkill->mutex); | 240 | mutex_lock(&rfkill->mutex); |
@@ -236,7 +242,20 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | |||
236 | mutex_unlock(&rfkill->mutex); | 242 | mutex_unlock(&rfkill->mutex); |
237 | } | 243 | } |
238 | } | 244 | } |
245 | } | ||
239 | 246 | ||
247 | /** | ||
248 | * rfkill_switch_all - Toggle state of all switches of given type | ||
249 | * @type: type of interfaces to be affected | ||
250 | * @state: the new state | ||
251 | * | ||
252 | * Acquires rfkill_mutex and calls __rfkill_switch_all(@type, @state). | ||
253 | * Please refer to __rfkill_switch_all() for details. | ||
254 | */ | ||
255 | void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) | ||
256 | { | ||
257 | mutex_lock(&rfkill_mutex); | ||
258 | __rfkill_switch_all(type, state); | ||
240 | mutex_unlock(&rfkill_mutex); | 259 | mutex_unlock(&rfkill_mutex); |
241 | } | 260 | } |
242 | EXPORT_SYMBOL(rfkill_switch_all); | 261 | EXPORT_SYMBOL(rfkill_switch_all); |
@@ -246,10 +265,14 @@ EXPORT_SYMBOL(rfkill_switch_all); | |||
246 | * | 265 | * |
247 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, | 266 | * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED, |
248 | * ignoring everything in its path but rfkill_mutex and rfkill->mutex. | 267 | * ignoring everything in its path but rfkill_mutex and rfkill->mutex. |
268 | * | ||
269 | * The global state before the EPO is saved and can be restored later | ||
270 | * using rfkill_restore_states(). | ||
249 | */ | 271 | */ |
250 | void rfkill_epo(void) | 272 | void rfkill_epo(void) |
251 | { | 273 | { |
252 | struct rfkill *rfkill; | 274 | struct rfkill *rfkill; |
275 | int i; | ||
253 | 276 | ||
254 | mutex_lock(&rfkill_mutex); | 277 | mutex_lock(&rfkill_mutex); |
255 | list_for_each_entry(rfkill, &rfkill_list, node) { | 278 | list_for_each_entry(rfkill, &rfkill_list, node) { |
@@ -257,11 +280,35 @@ void rfkill_epo(void) | |||
257 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); | 280 | rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); |
258 | mutex_unlock(&rfkill->mutex); | 281 | mutex_unlock(&rfkill->mutex); |
259 | } | 282 | } |
283 | for (i = 0; i < RFKILL_TYPE_MAX; i++) { | ||
284 | rfkill_global_states[i].default_state = | ||
285 | rfkill_global_states[i].current_state; | ||
286 | rfkill_global_states[i].current_state = | ||
287 | RFKILL_STATE_SOFT_BLOCKED; | ||
288 | } | ||
260 | mutex_unlock(&rfkill_mutex); | 289 | mutex_unlock(&rfkill_mutex); |
261 | } | 290 | } |
262 | EXPORT_SYMBOL_GPL(rfkill_epo); | 291 | EXPORT_SYMBOL_GPL(rfkill_epo); |
263 | 292 | ||
264 | /** | 293 | /** |
294 | * rfkill_restore_states - restore global states | ||
295 | * | ||
296 | * Restore (and sync switches to) the global state from the | ||
297 | * states in rfkill_default_states. This can undo the effects of | ||
298 | * a call to rfkill_epo(). | ||
299 | */ | ||
300 | void rfkill_restore_states(void) | ||
301 | { | ||
302 | int i; | ||
303 | |||
304 | mutex_lock(&rfkill_mutex); | ||
305 | for (i = 0; i < RFKILL_TYPE_MAX; i++) | ||
306 | __rfkill_switch_all(i, rfkill_global_states[i].default_state); | ||
307 | mutex_unlock(&rfkill_mutex); | ||
308 | } | ||
309 | EXPORT_SYMBOL_GPL(rfkill_restore_states); | ||
310 | |||
311 | /** | ||
265 | * rfkill_force_state - Force the internal rfkill radio state | 312 | * rfkill_force_state - Force the internal rfkill radio state |
266 | * @rfkill: pointer to the rfkill class to modify. | 313 | * @rfkill: pointer to the rfkill class to modify. |
267 | * @state: the current radio state the class should be forced to. | 314 | * @state: the current radio state the class should be forced to. |
@@ -406,8 +453,8 @@ static ssize_t rfkill_claim_store(struct device *dev, | |||
406 | if (!claim) { | 453 | if (!claim) { |
407 | mutex_lock(&rfkill->mutex); | 454 | mutex_lock(&rfkill->mutex); |
408 | rfkill_toggle_radio(rfkill, | 455 | rfkill_toggle_radio(rfkill, |
409 | rfkill_states[rfkill->type], | 456 | rfkill_global_states[rfkill->type].current_state, |
410 | 0); | 457 | 0); |
411 | mutex_unlock(&rfkill->mutex); | 458 | mutex_unlock(&rfkill->mutex); |
412 | } | 459 | } |
413 | rfkill->user_claim = claim; | 460 | rfkill->user_claim = claim; |
@@ -554,7 +601,16 @@ static int rfkill_add_switch(struct rfkill *rfkill) | |||
554 | if (error < 0) | 601 | if (error < 0) |
555 | goto unlock_out; | 602 | goto unlock_out; |
556 | 603 | ||
557 | rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type], 0); | 604 | if (!error) { |
605 | /* lock default after first use */ | ||
606 | set_bit(rfkill->type, rfkill_states_lockdflt); | ||
607 | rfkill_global_states[rfkill->type].current_state = | ||
608 | rfkill_global_states[rfkill->type].default_state; | ||
609 | } | ||
610 | |||
611 | rfkill_toggle_radio(rfkill, | ||
612 | rfkill_global_states[rfkill->type].current_state, | ||
613 | 0); | ||
558 | 614 | ||
559 | list_add_tail(&rfkill->node, &rfkill_list); | 615 | list_add_tail(&rfkill->node, &rfkill_list); |
560 | 616 | ||
@@ -710,6 +766,53 @@ void rfkill_unregister(struct rfkill *rfkill) | |||
710 | } | 766 | } |
711 | EXPORT_SYMBOL(rfkill_unregister); | 767 | EXPORT_SYMBOL(rfkill_unregister); |
712 | 768 | ||
769 | /** | ||
770 | * rfkill_set_default - set initial value for a switch type | ||
771 | * @type - the type of switch to set the default state of | ||
772 | * @state - the new default state for that group of switches | ||
773 | * | ||
774 | * Sets the initial state rfkill should use for a given type. | ||
775 | * The following initial states are allowed: RFKILL_STATE_SOFT_BLOCKED | ||
776 | * and RFKILL_STATE_UNBLOCKED. | ||
777 | * | ||
778 | * This function is meant to be used by platform drivers for platforms | ||
779 | * that can save switch state across power down/reboot. | ||
780 | * | ||
781 | * The default state for each switch type can be changed exactly once. | ||
782 | * After a switch of that type is registered, the default state cannot | ||
783 | * be changed anymore. This guards against multiple drivers it the | ||
784 | * same platform trying to set the initial switch default state, which | ||
785 | * is not allowed. | ||
786 | * | ||
787 | * Returns -EPERM if the state has already been set once or is in use, | ||
788 | * so drivers likely want to either ignore or at most printk(KERN_NOTICE) | ||
789 | * if this function returns -EPERM. | ||
790 | * | ||
791 | * Returns 0 if the new default state was set, or an error if it | ||
792 | * could not be set. | ||
793 | */ | ||
794 | int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) | ||
795 | { | ||
796 | int error; | ||
797 | |||
798 | if (type >= RFKILL_TYPE_MAX || | ||
799 | (state != RFKILL_STATE_SOFT_BLOCKED && | ||
800 | state != RFKILL_STATE_UNBLOCKED)) | ||
801 | return -EINVAL; | ||
802 | |||
803 | mutex_lock(&rfkill_mutex); | ||
804 | |||
805 | if (!test_and_set_bit(type, rfkill_states_lockdflt)) { | ||
806 | rfkill_global_states[type].default_state = state; | ||
807 | error = 0; | ||
808 | } else | ||
809 | error = -EPERM; | ||
810 | |||
811 | mutex_unlock(&rfkill_mutex); | ||
812 | return error; | ||
813 | } | ||
814 | EXPORT_SYMBOL_GPL(rfkill_set_default); | ||
815 | |||
713 | /* | 816 | /* |
714 | * Rfkill module initialization/deinitialization. | 817 | * Rfkill module initialization/deinitialization. |
715 | */ | 818 | */ |
@@ -723,8 +826,8 @@ static int __init rfkill_init(void) | |||
723 | rfkill_default_state != RFKILL_STATE_UNBLOCKED) | 826 | rfkill_default_state != RFKILL_STATE_UNBLOCKED) |
724 | return -EINVAL; | 827 | return -EINVAL; |
725 | 828 | ||
726 | for (i = 0; i < ARRAY_SIZE(rfkill_states); i++) | 829 | for (i = 0; i < RFKILL_TYPE_MAX; i++) |
727 | rfkill_states[i] = rfkill_default_state; | 830 | rfkill_global_states[i].default_state = rfkill_default_state; |
728 | 831 | ||
729 | error = class_register(&rfkill_class); | 832 | error = class_register(&rfkill_class); |
730 | if (error) { | 833 | if (error) { |