aboutsummaryrefslogtreecommitdiffstats
path: root/net/rfkill/rfkill.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2008-06-23 16:23:00 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-26 14:21:20 -0400
commit801e49af4c1a9b988ba0d25de2b368c99c3bf2b3 (patch)
tree60fbf2b2ce2d9aab3055198853d2a76223b03f71 /net/rfkill/rfkill.c
parente954b0b85b9e737564b8ad9738de5816747b5901 (diff)
rfkill: add read-write rfkill switch support
Currently, rfkill support for read/write rfkill switches is hacked through a round-trip over the input layer and rfkill-input to let a driver sync rfkill->state to hardware changes. This is buggy and sub-optimal. It causes real problems. It is best to think of the rfkill class as supporting only write-only switches at the moment. In order to implement the read/write functionality properly: Add a get_state() hook that is called by the class every time it needs to fetch the current state of the switch. Add a call to this hook every time the *current* state of the radio plays a role in a decision. Also add a force_state() method that can be used to forcefully syncronize the class' idea of the current state of the switch. This allows for a faster implementation of the read/write functionality, as a driver which get events on switch changes can avoid the need for a get_state() hook. If the get_state() hook is left as NULL, current behaviour is maintained, so this change is fully backwards compatible with the current rfkill drivers. For hardware that issues events when the rfkill state changes, leave get_state() NULL in the rfkill struct, set the initial state properly before registering with the rfkill class, and use the force_state() method in the driver to keep the rfkill interface up-to-date. get_state() can be called by the class from atomic context. It must not sleep. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Acked-by: Ivo van Doorn <IvDoorn@gmail.com> Cc: Dmitry Torokhov <dtor@mail.ru> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/rfkill/rfkill.c')
-rw-r--r--net/rfkill/rfkill.c53
1 files changed, 50 insertions, 3 deletions
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
index 3edc585dcfa6..4ae4486c77ea 100644
--- a/net/rfkill/rfkill.c
+++ b/net/rfkill/rfkill.c
@@ -62,19 +62,39 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
62#endif /* CONFIG_RFKILL_LEDS */ 62#endif /* CONFIG_RFKILL_LEDS */
63} 63}
64 64
65static void update_rfkill_state(struct rfkill *rfkill)
66{
67 enum rfkill_state newstate;
68
69 if (rfkill->get_state) {
70 mutex_lock(&rfkill->mutex);
71 if (!rfkill->get_state(rfkill->data, &newstate))
72 rfkill->state = newstate;
73 mutex_unlock(&rfkill->mutex);
74 }
75}
76
65static int rfkill_toggle_radio(struct rfkill *rfkill, 77static int rfkill_toggle_radio(struct rfkill *rfkill,
66 enum rfkill_state state) 78 enum rfkill_state state)
67{ 79{
68 int retval = 0; 80 int retval = 0;
81 enum rfkill_state oldstate, newstate;
82
83 oldstate = rfkill->state;
84
85 if (rfkill->get_state &&
86 !rfkill->get_state(rfkill->data, &newstate))
87 rfkill->state = newstate;
69 88
70 if (state != rfkill->state) { 89 if (state != rfkill->state) {
71 retval = rfkill->toggle_radio(rfkill->data, state); 90 retval = rfkill->toggle_radio(rfkill->data, state);
72 if (!retval) { 91 if (!retval)
73 rfkill->state = state; 92 rfkill->state = state;
74 rfkill_led_trigger(rfkill, state);
75 }
76 } 93 }
77 94
95 if (rfkill->state != oldstate)
96 rfkill_led_trigger(rfkill, rfkill->state);
97
78 return retval; 98 return retval;
79} 99}
80 100
@@ -105,6 +125,32 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
105} 125}
106EXPORT_SYMBOL(rfkill_switch_all); 126EXPORT_SYMBOL(rfkill_switch_all);
107 127
128/**
129 * rfkill_force_state - Force the internal rfkill radio state
130 * @rfkill: pointer to the rfkill class to modify.
131 * @state: the current radio state the class should be forced to.
132 *
133 * This function updates the internal state of the radio cached
134 * by the rfkill class. It should be used when the driver gets
135 * a notification by the firmware/hardware of the current *real*
136 * state of the radio rfkill switch.
137 *
138 * It may not be called from an atomic context.
139 */
140int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
141{
142 if (state != RFKILL_STATE_OFF &&
143 state != RFKILL_STATE_ON)
144 return -EINVAL;
145
146 mutex_lock(&rfkill->mutex);
147 rfkill->state = state;
148 mutex_unlock(&rfkill->mutex);
149
150 return 0;
151}
152EXPORT_SYMBOL(rfkill_force_state);
153
108static ssize_t rfkill_name_show(struct device *dev, 154static ssize_t rfkill_name_show(struct device *dev,
109 struct device_attribute *attr, 155 struct device_attribute *attr,
110 char *buf) 156 char *buf)
@@ -147,6 +193,7 @@ static ssize_t rfkill_state_show(struct device *dev,
147{ 193{
148 struct rfkill *rfkill = to_rfkill(dev); 194 struct rfkill *rfkill = to_rfkill(dev);
149 195
196 update_rfkill_state(rfkill);
150 return sprintf(buf, "%d\n", rfkill->state); 197 return sprintf(buf, "%d\n", rfkill->state);
151} 198}
152 199