rfkill: preserve state across suspend
Henrique de Moraes Holschuh [Fri, 21 Nov 2008 22:40:09 +0000 (20:40 -0200)]
The rfkill class API requires that the driver connected to a class
call rfkill_force_state() on resume to update the real state of the
rfkill controller, OR that it provides a get_state() hook.

This means there is potentially a hidden call in the resume code flow
that changes rfkill->state (i.e. rfkill_force_state()), so the
previous state of the transmitter was being lost.

The simplest and most future-proof way to fix this is to explicitly
store the pre-sleep state on the rfkill structure, and restore from
that on resume.

Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
Acked-by: Ivo van Doorn <IvDoorn@gmail.com>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Alan Jenkins <alan-jenkins@tuffmail.co.uk>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

include/linux/rfkill.h
net/rfkill/rfkill.c

index 4cd64b0..f376a93 100644 (file)
@@ -108,6 +108,7 @@ struct rfkill {
 
        struct device dev;
        struct list_head node;
+       enum rfkill_state state_for_resume;
 };
 #define to_rfkill(d)   container_of(d, struct rfkill, dev)
 
index ec26eae..5ad411d 100644 (file)
@@ -565,10 +565,15 @@ static void rfkill_release(struct device *dev)
 #ifdef CONFIG_PM
 static int rfkill_suspend(struct device *dev, pm_message_t state)
 {
+       struct rfkill *rfkill = to_rfkill(dev);
+
        /* mark class device as suspended */
        if (dev->power.power_state.event != state.event)
                dev->power.power_state = state;
 
+       /* store state for the resume handler */
+       rfkill->state_for_resume = rfkill->state;
+
        return 0;
 }
 
@@ -590,7 +595,7 @@ static int rfkill_resume(struct device *dev)
                rfkill_toggle_radio(rfkill,
                                rfkill_epo_lock_active ?
                                        RFKILL_STATE_SOFT_BLOCKED :
-                                       rfkill->state,
+                                       rfkill->state_for_resume,
                                1);
 
                mutex_unlock(&rfkill->mutex);