aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Jenkins <alan-jenkins@tuffmail.co.uk>2009-06-16 10:39:51 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-06-19 11:50:17 -0400
commit06d5caf47ef4fbd9efdceae33293c42778cb7b0c (patch)
tree51bce5f2f9f7aef903c464ac68c80da6f83e2c53
parent7fa20a7f60df0afceafbb8197b5d110507f42c72 (diff)
rfkill: don't restore software blocked state on persistent devices
The setting of the "persistent" flag is also made more explicit using a new rfkill_init_sw_state() function, instead of special-casing rfkill_set_sw_state() when it is called before registration. Suspend is a bit of a corner case so we try to get away without adding another hack to rfkill-input - it's going to be removed soon. If the state does change over suspend, users will simply have to prod rfkill-input twice in order to toggle the state. Userspace policy agents will be able to implement a more consistent user experience. For example, they can avoid the above problem if they toggle devices individually. Then there would be no "global state" to get out of sync. Currently there are only two rfkill drivers with persistent soft-blocked state. thinkpad-acpi already checks the software state on resume. eeepc-laptop will require modification. Signed-off-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk> CC: Marcel Holtmann <marcel@holtmann.org> Acked-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/platform/x86/eeepc-laptop.c8
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c14
-rw-r--r--include/linux/rfkill.h32
-rw-r--r--net/rfkill/core.c40
4 files changed, 63 insertions, 31 deletions
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 03bf522bd7ab..01682eca4360 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -675,8 +675,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
675 if (!ehotk->eeepc_wlan_rfkill) 675 if (!ehotk->eeepc_wlan_rfkill)
676 goto wlan_fail; 676 goto wlan_fail;
677 677
678 rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, 678 rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill,
679 get_acpi(CM_ASL_WLAN) != 1); 679 get_acpi(CM_ASL_WLAN) != 1);
680 result = rfkill_register(ehotk->eeepc_wlan_rfkill); 680 result = rfkill_register(ehotk->eeepc_wlan_rfkill);
681 if (result) 681 if (result)
682 goto wlan_fail; 682 goto wlan_fail;
@@ -693,8 +693,8 @@ static int eeepc_hotk_add(struct acpi_device *device)
693 if (!ehotk->eeepc_bluetooth_rfkill) 693 if (!ehotk->eeepc_bluetooth_rfkill)
694 goto bluetooth_fail; 694 goto bluetooth_fail;
695 695
696 rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill, 696 rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill,
697 get_acpi(CM_ASL_BLUETOOTH) != 1); 697 get_acpi(CM_ASL_BLUETOOTH) != 1);
698 result = rfkill_register(ehotk->eeepc_bluetooth_rfkill); 698 result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
699 if (result) 699 if (result)
700 goto bluetooth_fail; 700 goto bluetooth_fail;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 86e958539f46..40d64c03278c 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -1163,8 +1163,8 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
1163{ 1163{
1164 struct tpacpi_rfk *atp_rfk; 1164 struct tpacpi_rfk *atp_rfk;
1165 int res; 1165 int res;
1166 bool initial_sw_state = false; 1166 bool sw_state = false;
1167 int initial_sw_status; 1167 int sw_status;
1168 1168
1169 BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); 1169 BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]);
1170 1170
@@ -1185,17 +1185,17 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id,
1185 atp_rfk->id = id; 1185 atp_rfk->id = id;
1186 atp_rfk->ops = tp_rfkops; 1186 atp_rfk->ops = tp_rfkops;
1187 1187
1188 initial_sw_status = (tp_rfkops->get_status)(); 1188 sw_status = (tp_rfkops->get_status)();
1189 if (initial_sw_status < 0) { 1189 if (sw_status < 0) {
1190 printk(TPACPI_ERR 1190 printk(TPACPI_ERR
1191 "failed to read initial state for %s, error %d\n", 1191 "failed to read initial state for %s, error %d\n",
1192 name, initial_sw_status); 1192 name, sw_status);
1193 } else { 1193 } else {
1194 initial_sw_state = (initial_sw_status == TPACPI_RFK_RADIO_OFF); 1194 sw_state = (sw_status == TPACPI_RFK_RADIO_OFF);
1195 if (set_default) { 1195 if (set_default) {
1196 /* try to keep the initial state, since we ask the 1196 /* try to keep the initial state, since we ask the
1197 * firmware to preserve it across S5 in NVRAM */ 1197 * firmware to preserve it across S5 in NVRAM */
1198 rfkill_set_sw_state(atp_rfk->rfkill, initial_sw_state); 1198 rfkill_init_sw_state(atp_rfk->rfkill, sw_state);
1199 } 1199 }
1200 } 1200 }
1201 rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state()); 1201 rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state());
diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h
index 16e39c7a67fc..dcac724340d8 100644
--- a/include/linux/rfkill.h
+++ b/include/linux/rfkill.h
@@ -160,8 +160,9 @@ struct rfkill * __must_check rfkill_alloc(const char *name,
160 * the rfkill structure. Before calling this function the driver needs 160 * the rfkill structure. Before calling this function the driver needs
161 * to be ready to service method calls from rfkill. 161 * to be ready to service method calls from rfkill.
162 * 162 *
163 * If the software blocked state is not set before registration, 163 * If rfkill_init_sw_state() is not called before registration,
164 * set_block will be called to initialize it to a default value. 164 * set_block() will be called to initialize the software blocked state
165 * to a default value.
165 * 166 *
166 * If the hardware blocked state is not set before registration, 167 * If the hardware blocked state is not set before registration,
167 * it is assumed to be unblocked. 168 * it is assumed to be unblocked.
@@ -234,9 +235,11 @@ bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
234 * rfkill drivers that get events when the soft-blocked state changes 235 * rfkill drivers that get events when the soft-blocked state changes
235 * (yes, some platforms directly act on input but allow changing again) 236 * (yes, some platforms directly act on input but allow changing again)
236 * use this function to notify the rfkill core (and through that also 237 * use this function to notify the rfkill core (and through that also
237 * userspace) of the current state. It is not necessary to notify on 238 * userspace) of the current state.
238 * resume; since hibernation can always change the soft-blocked state, 239 *
239 * the rfkill core will unconditionally restore the previous state. 240 * Drivers should also call this function after resume if the state has
241 * been changed by the user. This only makes sense for "persistent"
242 * devices (see rfkill_init_sw_state()).
240 * 243 *
241 * This function can be called in any context, even from within rfkill 244 * This function can be called in any context, even from within rfkill
242 * callbacks. 245 * callbacks.
@@ -247,6 +250,21 @@ bool __must_check rfkill_set_hw_state(struct rfkill *rfkill, bool blocked);
247bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked); 250bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked);
248 251
249/** 252/**
253 * rfkill_init_sw_state - Initialize persistent software block state
254 * @rfkill: pointer to the rfkill class to modify.
255 * @state: the current software block state to set
256 *
257 * rfkill drivers that preserve their software block state over power off
258 * use this function to notify the rfkill core (and through that also
259 * userspace) of their initial state. It should only be used before
260 * registration.
261 *
262 * In addition, it marks the device as "persistent". Persistent devices
263 * are expected to preserve preserve their own state when suspended.
264 */
265void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked);
266
267/**
250 * rfkill_set_states - Set the internal rfkill block states 268 * rfkill_set_states - Set the internal rfkill block states
251 * @rfkill: pointer to the rfkill class to modify. 269 * @rfkill: pointer to the rfkill class to modify.
252 * @sw: the current software block state to set 270 * @sw: the current software block state to set
@@ -307,6 +325,10 @@ static inline bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
307 return blocked; 325 return blocked;
308} 326}
309 327
328static inline void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked)
329{
330}
331
310static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) 332static inline void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
311{ 333{
312} 334}
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 868d79f8ac1d..dcf8df7c573c 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -56,7 +56,6 @@ struct rfkill {
56 u32 idx; 56 u32 idx;
57 57
58 bool registered; 58 bool registered;
59 bool suspended;
60 bool persistent; 59 bool persistent;
61 60
62 const struct rfkill_ops *ops; 61 const struct rfkill_ops *ops;
@@ -224,7 +223,7 @@ static void rfkill_send_events(struct rfkill *rfkill, enum rfkill_operation op)
224 223
225static void rfkill_event(struct rfkill *rfkill) 224static void rfkill_event(struct rfkill *rfkill)
226{ 225{
227 if (!rfkill->registered || rfkill->suspended) 226 if (!rfkill->registered)
228 return; 227 return;
229 228
230 kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); 229 kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
@@ -508,19 +507,32 @@ bool rfkill_set_sw_state(struct rfkill *rfkill, bool blocked)
508 blocked = blocked || hwblock; 507 blocked = blocked || hwblock;
509 spin_unlock_irqrestore(&rfkill->lock, flags); 508 spin_unlock_irqrestore(&rfkill->lock, flags);
510 509
511 if (!rfkill->registered) { 510 if (!rfkill->registered)
512 rfkill->persistent = true; 511 return blocked;
513 } else {
514 if (prev != blocked && !hwblock)
515 schedule_work(&rfkill->uevent_work);
516 512
517 rfkill_led_trigger_event(rfkill); 513 if (prev != blocked && !hwblock)
518 } 514 schedule_work(&rfkill->uevent_work);
515
516 rfkill_led_trigger_event(rfkill);
519 517
520 return blocked; 518 return blocked;
521} 519}
522EXPORT_SYMBOL(rfkill_set_sw_state); 520EXPORT_SYMBOL(rfkill_set_sw_state);
523 521
522void rfkill_init_sw_state(struct rfkill *rfkill, bool blocked)
523{
524 unsigned long flags;
525
526 BUG_ON(!rfkill);
527 BUG_ON(rfkill->registered);
528
529 spin_lock_irqsave(&rfkill->lock, flags);
530 __rfkill_set_sw_state(rfkill, blocked);
531 rfkill->persistent = true;
532 spin_unlock_irqrestore(&rfkill->lock, flags);
533}
534EXPORT_SYMBOL(rfkill_init_sw_state);
535
524void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw) 536void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
525{ 537{
526 unsigned long flags; 538 unsigned long flags;
@@ -718,8 +730,6 @@ static int rfkill_suspend(struct device *dev, pm_message_t state)
718 730
719 rfkill_pause_polling(rfkill); 731 rfkill_pause_polling(rfkill);
720 732
721 rfkill->suspended = true;
722
723 return 0; 733 return 0;
724} 734}
725 735
@@ -728,10 +738,10 @@ static int rfkill_resume(struct device *dev)
728 struct rfkill *rfkill = to_rfkill(dev); 738 struct rfkill *rfkill = to_rfkill(dev);
729 bool cur; 739 bool cur;
730 740
731 cur = !!(rfkill->state & RFKILL_BLOCK_SW); 741 if (!rfkill->persistent) {
732 rfkill_set_block(rfkill, cur); 742 cur = !!(rfkill->state & RFKILL_BLOCK_SW);
733 743 rfkill_set_block(rfkill, cur);
734 rfkill->suspended = false; 744 }
735 745
736 rfkill_resume_polling(rfkill); 746 rfkill_resume_polling(rfkill);
737 747