summaryrefslogtreecommitdiff
path: root/net/rfkill/rfkill.c
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2008-06-24 00:46:42 +0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-26 22:21:22 +0400
commit5005657cbd0fd6f277f807c0612a6b6d4396a02c (patch)
treee6ed81f07a1a85ed2c440ac8631ca19cc77907c1 /net/rfkill/rfkill.c
parentdc288520a21879c6540f3249e9532c5e032da4e8 (diff)
downloadlinux-5005657cbd0fd6f277f807c0612a6b6d4396a02c.tar.xz
rfkill: rename the rfkill_state states and add block-locked state
The current naming of rfkill_state causes a lot of confusion: not only the "kill" in rfkill suggests negative logic, but also the fact that rfkill cannot turn anything on (it can just force something off or stop forcing something off) is often forgotten. Rename RFKILL_STATE_OFF to RFKILL_STATE_SOFT_BLOCKED (transmitter is blocked and will not operate; state can be changed by a toggle_radio request), and RFKILL_STATE_ON to RFKILL_STATE_UNBLOCKED (transmitter is not blocked, and may operate). Also, add a new third state, RFKILL_STATE_HARD_BLOCKED (transmitter is blocked and will not operate; state cannot be changed through a toggle_radio request), which is used by drivers to indicate a wireless transmiter was blocked by a hardware rfkill line that accepts no overrides. Keep the old names as #defines, but document them as deprecated. This way, drivers can be converted to the new names *and* verified to actually use rfkill correctly one by one. 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.c75
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");
static LIST_HEAD(rfkill_list); /* list of registered rf switches */
static DEFINE_MUTEX(rfkill_mutex);
-static unsigned int rfkill_default_state = RFKILL_STATE_ON;
+static unsigned int rfkill_default_state = RFKILL_STATE_UNBLOCKED;
module_param_named(default_state, rfkill_default_state, uint, 0444);
MODULE_PARM_DESC(default_state,
"Default initial state for all radio types, 0 = radio off");
@@ -98,7 +98,7 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
if (!led->name)
return;
- if (state == RFKILL_STATE_OFF)
+ if (state != RFKILL_STATE_UNBLOCKED)
led_trigger_event(led, LED_OFF);
else
led_trigger_event(led, LED_FULL);
@@ -128,6 +128,28 @@ static void update_rfkill_state(struct rfkill *rfkill)
}
}
+/**
+ * rfkill_toggle_radio - wrapper for toggle_radio hook
+ * calls toggle_radio taking into account a lot of "small"
+ * details.
+ * @rfkill: the rfkill struct to use
+ * @force: calls toggle_radio even if cache says it is not needed,
+ * and also makes sure notifications of the state will be
+ * sent even if it didn't change
+ * @state: the new state to call toggle_radio() with
+ *
+ * This wrappen protects and enforces the API for toggle_radio
+ * calls. Note that @force cannot override a (possibly cached)
+ * state of RFKILL_STATE_HARD_BLOCKED. Any device making use of
+ * RFKILL_STATE_HARD_BLOCKED implements either get_state() or
+ * rfkill_force_state(), so the cache either is bypassed or valid.
+ *
+ * Note that we do call toggle_radio for RFKILL_STATE_SOFT_BLOCKED
+ * even if the radio is in RFKILL_STATE_HARD_BLOCKED state, so as to
+ * give the driver a hint that it should double-BLOCK the transmitter.
+ *
+ * Caller must have aquired rfkill_mutex.
+ */
static int rfkill_toggle_radio(struct rfkill *rfkill,
enum rfkill_state state,
int force)
@@ -141,9 +163,28 @@ static int rfkill_toggle_radio(struct rfkill *rfkill,
!rfkill->get_state(rfkill->data, &newstate))
rfkill->state = newstate;
+ switch (state) {
+ case RFKILL_STATE_HARD_BLOCKED:
+ /* typically happens when refreshing hardware state,
+ * such as on resume */
+ state = RFKILL_STATE_SOFT_BLOCKED;
+ break;
+ case RFKILL_STATE_UNBLOCKED:
+ /* force can't override this, only rfkill_force_state() can */
+ if (rfkill->state == RFKILL_STATE_HARD_BLOCKED)
+ return -EPERM;
+ break;
+ case RFKILL_STATE_SOFT_BLOCKED:
+ /* nothing to do, we want to give drivers the hint to double
+ * BLOCK even a transmitter that is already in state
+ * RFKILL_STATE_HARD_BLOCKED */
+ break;
+ }
+
if (force || state != rfkill->state) {
retval = rfkill->toggle_radio(rfkill->data, state);
- if (!retval)
+ /* never allow a HARD->SOFT downgrade! */
+ if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED)
rfkill->state = state;
}
@@ -184,7 +225,7 @@ EXPORT_SYMBOL(rfkill_switch_all);
/**
* rfkill_epo - emergency power off all transmitters
*
- * This kicks all rfkill devices to RFKILL_STATE_OFF, ignoring
+ * This kicks all rfkill devices to RFKILL_STATE_SOFT_BLOCKED, ignoring
* everything in its path but rfkill_mutex.
*/
void rfkill_epo(void)
@@ -193,7 +234,7 @@ void rfkill_epo(void)
mutex_lock(&rfkill_mutex);
list_for_each_entry(rfkill, &rfkill_list, node) {
- rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF, 1);
+ rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
}
mutex_unlock(&rfkill_mutex);
}
@@ -215,8 +256,9 @@ int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
{
enum rfkill_state oldstate;
- if (state != RFKILL_STATE_OFF &&
- state != RFKILL_STATE_ON)
+ if (state != RFKILL_STATE_SOFT_BLOCKED &&
+ state != RFKILL_STATE_UNBLOCKED &&
+ state != RFKILL_STATE_HARD_BLOCKED)
return -EINVAL;
mutex_lock(&rfkill->mutex);
@@ -290,11 +332,14 @@ static ssize_t rfkill_state_store(struct device *dev,
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
+ if (state != RFKILL_STATE_UNBLOCKED &&
+ state != RFKILL_STATE_SOFT_BLOCKED)
+ return -EINVAL;
+
if (mutex_lock_interruptible(&rfkill->mutex))
return -ERESTARTSYS;
- error = rfkill_toggle_radio(rfkill,
- state ? RFKILL_STATE_ON : RFKILL_STATE_OFF,
- 0);
+ error = rfkill_toggle_radio(rfkill, state, 0);
mutex_unlock(&rfkill->mutex);
return error ? error : count;
@@ -373,7 +418,8 @@ static int rfkill_suspend(struct device *dev, pm_message_t state)
update_rfkill_state(rfkill);
mutex_lock(&rfkill->mutex);
- rfkill->toggle_radio(rfkill->data, RFKILL_STATE_OFF);
+ rfkill->toggle_radio(rfkill->data,
+ RFKILL_STATE_SOFT_BLOCKED);
mutex_unlock(&rfkill->mutex);
}
@@ -470,7 +516,7 @@ static void rfkill_remove_switch(struct rfkill *rfkill)
{
mutex_lock(&rfkill_mutex);
list_del_init(&rfkill->node);
- rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF, 1);
+ rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
mutex_unlock(&rfkill_mutex);
}
@@ -610,8 +656,9 @@ static int __init rfkill_init(void)
int error;
int i;
- if (rfkill_default_state != RFKILL_STATE_OFF &&
- rfkill_default_state != RFKILL_STATE_ON)
+ /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
+ if (rfkill_default_state != RFKILL_STATE_SOFT_BLOCKED &&
+ rfkill_default_state != RFKILL_STATE_UNBLOCKED)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)