aboutsummaryrefslogtreecommitdiff
path: root/net/rfkill/rfkill.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-06-02 13:01:37 +0200
committerJohn W. Linville <linville@tuxdriver.com>2009-06-03 14:06:13 -0400
commit19d337dff95cbf76edd3ad95c0cee2732c3e1ec5 (patch)
tree33326eeb09cb9664cc8427a5dc7cd2b08b5a57c3 /net/rfkill/rfkill.c
parent0f6399c4c525b518644a9b09f8d6fb125a418c4d (diff)
downloadvexpress-lsk-19d337dff95cbf76edd3ad95c0cee2732c3e1ec5.tar.gz
rfkill: rewrite
This patch completely rewrites the rfkill core to address the following deficiencies: * all rfkill drivers need to implement polling where necessary rather than having one central implementation * updating the rfkill state cannot be done from arbitrary contexts, forcing drivers to use schedule_work and requiring lots of code * rfkill drivers need to keep track of soft/hard blocked internally -- the core should do this * the rfkill API has many unexpected quirks, for example being asymmetric wrt. alloc/free and register/unregister * rfkill can call back into a driver from within a function the driver called -- this is prone to deadlocks and generally should be avoided * rfkill-input pointlessly is a separate module * drivers need to #ifdef rfkill functions (unless they want to depend on or select RFKILL) -- rfkill should provide inlines that do nothing if it isn't compiled in * the rfkill structure is not opaque -- drivers need to initialise it correctly (lots of sanity checking code required) -- instead force drivers to pass the right variables to rfkill_alloc() * the documentation is hard to read because it always assumes the reader is completely clueless and contains way TOO MANY CAPS * the rfkill code needlessly uses a lot of locks and atomic operations in locked sections * fix LED trigger to actually change the LED when the radio state changes -- this wasn't done before Tested-by: Alan Jenkins <alan-jenkins@tuffmail.co.uk> Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> [thinkpad] Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/rfkill/rfkill.c')
-rw-r--r--net/rfkill/rfkill.c855
1 files changed, 0 insertions, 855 deletions
diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c
deleted file mode 100644
index 4f5a83183c9..00000000000
--- a/net/rfkill/rfkill.c
+++ /dev/null
@@ -1,855 +0,0 @@
-/*
- * Copyright (C) 2006 - 2007 Ivo van Doorn
- * Copyright (C) 2007 Dmitry Torokhov
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/workqueue.h>
-#include <linux/capability.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-#include <linux/rfkill.h>
-
-/* Get declaration of rfkill_switch_all() to shut up sparse. */
-#include "rfkill-input.h"
-
-
-MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>");
-MODULE_VERSION("1.0");
-MODULE_DESCRIPTION("RF switch support");
-MODULE_LICENSE("GPL");
-
-static LIST_HEAD(rfkill_list); /* list of registered rf switches */
-static DEFINE_MUTEX(rfkill_global_mutex);
-
-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");
-
-struct rfkill_gsw_state {
- enum rfkill_state current_state;
- enum rfkill_state default_state;
-};
-
-static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX];
-static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-static bool rfkill_epo_lock_active;
-
-
-#ifdef CONFIG_RFKILL_LEDS
-static void rfkill_led_trigger(struct rfkill *rfkill,
- enum rfkill_state state)
-{
- struct led_trigger *led = &rfkill->led_trigger;
-
- if (!led->name)
- return;
- if (state != RFKILL_STATE_UNBLOCKED)
- led_trigger_event(led, LED_OFF);
- else
- led_trigger_event(led, LED_FULL);
-}
-
-static void rfkill_led_trigger_activate(struct led_classdev *led)
-{
- struct rfkill *rfkill = container_of(led->trigger,
- struct rfkill, led_trigger);
-
- rfkill_led_trigger(rfkill, rfkill->state);
-}
-#else
-static inline void rfkill_led_trigger(struct rfkill *rfkill,
- enum rfkill_state state)
-{
-}
-#endif /* CONFIG_RFKILL_LEDS */
-
-static void rfkill_uevent(struct rfkill *rfkill)
-{
- kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE);
-}
-
-static void update_rfkill_state(struct rfkill *rfkill)
-{
- enum rfkill_state newstate, oldstate;
-
- if (rfkill->get_state) {
- mutex_lock(&rfkill->mutex);
- if (!rfkill->get_state(rfkill->data, &newstate)) {
- oldstate = rfkill->state;
- rfkill->state = newstate;
- if (oldstate != newstate)
- rfkill_uevent(rfkill);
- }
- mutex_unlock(&rfkill->mutex);
- }
- rfkill_led_trigger(rfkill, rfkill->state);
-}
-
-/**
- * rfkill_toggle_radio - wrapper for toggle_radio hook
- * @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
- *
- * Calls rfkill->toggle_radio, enforcing the API for toggle_radio
- * calls and handling all the red tape such as issuing notifications
- * if the call is successful.
- *
- * Suspended devices are not touched at all, and -EAGAIN is returned.
- *
- * Note that the @force parameter 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 acquired rfkill->mutex.
- */
-static int rfkill_toggle_radio(struct rfkill *rfkill,
- enum rfkill_state state,
- int force)
-{
- int retval = 0;
- enum rfkill_state oldstate, newstate;
-
- if (unlikely(rfkill->dev.power.power_state.event & PM_EVENT_SLEEP))
- return -EBUSY;
-
- oldstate = rfkill->state;
-
- if (rfkill->get_state && !force &&
- !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;
- default:
- WARN(1, KERN_WARNING
- "rfkill: illegal state %d passed as parameter "
- "to rfkill_toggle_radio\n", state);
- return -EINVAL;
- }
-
- if (force || state != rfkill->state) {
- retval = rfkill->toggle_radio(rfkill->data, state);
- /* never allow a HARD->SOFT downgrade! */
- if (!retval && rfkill->state != RFKILL_STATE_HARD_BLOCKED)
- rfkill->state = state;
- }
-
- if (force || rfkill->state != oldstate)
- rfkill_uevent(rfkill);
-
- rfkill_led_trigger(rfkill, rfkill->state);
- return retval;
-}
-
-/**
- * __rfkill_switch_all - Toggle state of all switches of given type
- * @type: type of interfaces to be affected
- * @state: the new state
- *
- * This function toggles the state of all switches of given type,
- * unless a specific switch is claimed by userspace (in which case,
- * that switch is left alone) or suspended.
- *
- * Caller must have acquired rfkill_global_mutex.
- */
-static void __rfkill_switch_all(const enum rfkill_type type,
- const enum rfkill_state state)
-{
- struct rfkill *rfkill;
-
- if (WARN((state >= RFKILL_STATE_MAX || type >= RFKILL_TYPE_MAX),
- KERN_WARNING
- "rfkill: illegal state %d or type %d "
- "passed as parameter to __rfkill_switch_all\n",
- state, type))
- return;
-
- rfkill_global_states[type].current_state = state;
- list_for_each_entry(rfkill, &rfkill_list, node) {
- if (rfkill->type == type) {
- mutex_lock(&rfkill->mutex);
- rfkill_toggle_radio(rfkill, state, 0);
- mutex_unlock(&rfkill->mutex);
- rfkill_led_trigger(rfkill, rfkill->state);
- }
- }
-}
-
-/**
- * rfkill_switch_all - Toggle state of all switches of given type
- * @type: type of interfaces to be affected
- * @state: the new state
- *
- * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state).
- * Please refer to __rfkill_switch_all() for details.
- *
- * Does nothing if the EPO lock is active.
- */
-void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
-{
- mutex_lock(&rfkill_global_mutex);
- if (!rfkill_epo_lock_active)
- __rfkill_switch_all(type, state);
- mutex_unlock(&rfkill_global_mutex);
-}
-EXPORT_SYMBOL(rfkill_switch_all);
-
-/**
- * rfkill_epo - emergency power off all transmitters
- *
- * This kicks all non-suspended rfkill devices to RFKILL_STATE_SOFT_BLOCKED,
- * ignoring everything in its path but rfkill_global_mutex and rfkill->mutex.
- *
- * The global state before the EPO is saved and can be restored later
- * using rfkill_restore_states().
- */
-void rfkill_epo(void)
-{
- struct rfkill *rfkill;
- int i;
-
- mutex_lock(&rfkill_global_mutex);
-
- rfkill_epo_lock_active = true;
- list_for_each_entry(rfkill, &rfkill_list, node) {
- mutex_lock(&rfkill->mutex);
- rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
- mutex_unlock(&rfkill->mutex);
- }
- for (i = 0; i < RFKILL_TYPE_MAX; i++) {
- rfkill_global_states[i].default_state =
- rfkill_global_states[i].current_state;
- rfkill_global_states[i].current_state =
- RFKILL_STATE_SOFT_BLOCKED;
- }
- mutex_unlock(&rfkill_global_mutex);
- rfkill_led_trigger(rfkill, rfkill->state);
-}
-EXPORT_SYMBOL_GPL(rfkill_epo);
-
-/**
- * rfkill_restore_states - restore global states
- *
- * Restore (and sync switches to) the global state from the
- * states in rfkill_default_states. This can undo the effects of
- * a call to rfkill_epo().
- */
-void rfkill_restore_states(void)
-{
- int i;
-
- mutex_lock(&rfkill_global_mutex);
-
- rfkill_epo_lock_active = false;
- for (i = 0; i < RFKILL_TYPE_MAX; i++)
- __rfkill_switch_all(i, rfkill_global_states[i].default_state);
- mutex_unlock(&rfkill_global_mutex);
-}
-EXPORT_SYMBOL_GPL(rfkill_restore_states);
-
-/**
- * rfkill_remove_epo_lock - unlock state changes
- *
- * Used by rfkill-input manually unlock state changes, when
- * the EPO switch is deactivated.
- */
-void rfkill_remove_epo_lock(void)
-{
- mutex_lock(&rfkill_global_mutex);
- rfkill_epo_lock_active = false;
- mutex_unlock(&rfkill_global_mutex);
-}
-EXPORT_SYMBOL_GPL(rfkill_remove_epo_lock);
-
-/**
- * rfkill_is_epo_lock_active - returns true EPO is active
- *
- * Returns 0 (false) if there is NOT an active EPO contidion,
- * and 1 (true) if there is an active EPO contition, which
- * locks all radios in one of the BLOCKED states.
- *
- * Can be called in atomic context.
- */
-bool rfkill_is_epo_lock_active(void)
-{
- return rfkill_epo_lock_active;
-}
-EXPORT_SYMBOL_GPL(rfkill_is_epo_lock_active);
-
-/**
- * rfkill_get_global_state - returns global state for a type
- * @type: the type to get the global state of
- *
- * Returns the current global state for a given wireless
- * device type.
- */
-enum rfkill_state rfkill_get_global_state(const enum rfkill_type type)
-{
- return rfkill_global_states[type].current_state;
-}
-EXPORT_SYMBOL_GPL(rfkill_get_global_state);
-
-/**
- * rfkill_force_state - Force the internal rfkill radio state
- * @rfkill: pointer to the rfkill class to modify.
- * @state: the current radio state the class should be forced to.
- *
- * This function updates the internal state of the radio cached
- * by the rfkill class. It should be used when the driver gets
- * a notification by the firmware/hardware of the current *real*
- * state of the radio rfkill switch.
- *
- * Devices which are subject to external changes on their rfkill
- * state (such as those caused by a hardware rfkill line) MUST
- * have their driver arrange to call rfkill_force_state() as soon
- * as possible after such a change.
- *
- * This function may not be called from an atomic context.
- */
-int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state)
-{
- enum rfkill_state oldstate;
-
- BUG_ON(!rfkill);
- if (WARN((state >= RFKILL_STATE_MAX),
- KERN_WARNING
- "rfkill: illegal state %d passed as parameter "
- "to rfkill_force_state\n", state))
- return -EINVAL;
-
- mutex_lock(&rfkill->mutex);
-
- oldstate = rfkill->state;
- rfkill->state = state;
-
- if (state != oldstate)
- rfkill_uevent(rfkill);
-
- mutex_unlock(&rfkill->mutex);
- rfkill_led_trigger(rfkill, rfkill->state);
-
- return 0;
-}
-EXPORT_SYMBOL(rfkill_force_state);
-
-static ssize_t rfkill_name_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rfkill *rfkill = to_rfkill(dev);
-
- return sprintf(buf, "%s\n", rfkill->name);
-}
-
-static const char *rfkill_get_type_str(enum rfkill_type type)
-{
- switch (type) {
- case RFKILL_TYPE_WLAN:
- return "wlan";
- case RFKILL_TYPE_BLUETOOTH:
- return "bluetooth";
- case RFKILL_TYPE_UWB:
- return "ultrawideband";
- case RFKILL_TYPE_WIMAX:
- return "wimax";
- case RFKILL_TYPE_WWAN:
- return "wwan";
- default:
- BUG();
- }
-}
-
-static ssize_t rfkill_type_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rfkill *rfkill = to_rfkill(dev);
-
- return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type));
-}
-
-static ssize_t rfkill_state_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct rfkill *rfkill = to_rfkill(dev);
-
- update_rfkill_state(rfkill);
- return sprintf(buf, "%d\n", rfkill->state);
-}
-
-static ssize_t rfkill_state_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct rfkill *rfkill = to_rfkill(dev);
- unsigned long state;
- int error;
-
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- error = strict_strtoul(buf, 0, &state);
- if (error)
- return error;
-
- /* RFKILL_STATE_HARD_BLOCKED is illegal here... */
- if (state != RFKILL_STATE_UNBLOCKED &&
- state != RFKILL_STATE_SOFT_BLOCKED)
- return -EINVAL;
-
- error = mutex_lock_killable(&rfkill->mutex);
- if (error)
- return error;
-
- if (!rfkill_epo_lock_active)
- error = rfkill_toggle_radio(rfkill, state, 0);
- else
- error = -EPERM;
-
- mutex_unlock(&rfkill->mutex);
-
- return error ? error : count;
-}
-
-static ssize_t rfkill_claim_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%d\n", 0);
-}
-
-static ssize_t rfkill_claim_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return -EOPNOTSUPP;
-}
-
-static struct device_attribute rfkill_dev_attrs[] = {
- __ATTR(name, S_IRUGO, rfkill_name_show, NULL),
- __ATTR(type, S_IRUGO, rfkill_type_show, NULL),
- __ATTR(state, S_IRUGO|S_IWUSR, rfkill_state_show, rfkill_state_store),
- __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
- __ATTR_NULL
-};
-
-static void rfkill_release(struct device *dev)
-{
- struct rfkill *rfkill = to_rfkill(dev);
-
- kfree(rfkill);
- module_put(THIS_MODULE);
-}
-
-#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;
-}
-
-static int rfkill_resume(struct device *dev)
-{
- struct rfkill *rfkill = to_rfkill(dev);
- enum rfkill_state newstate;
-
- if (dev->power.power_state.event != PM_EVENT_ON) {
- mutex_lock(&rfkill->mutex);
-
- dev->power.power_state.event = PM_EVENT_ON;
-
- /*
- * rfkill->state could have been modified before we got
- * called, and won't be updated by rfkill_toggle_radio()
- * in force mode. Sync it FIRST.
- */
- if (rfkill->get_state &&
- !rfkill->get_state(rfkill->data, &newstate))
- rfkill->state = newstate;
-
- /*
- * If we are under EPO, kick transmitter offline,
- * otherwise restore to pre-suspend state.
- *
- * Issue a notification in any case
- */
- rfkill_toggle_radio(rfkill,
- rfkill_epo_lock_active ?
- RFKILL_STATE_SOFT_BLOCKED :
- rfkill->state_for_resume,
- 1);
-
- mutex_unlock(&rfkill->mutex);
- rfkill_led_trigger(rfkill, rfkill->state);
- }
-
- return 0;
-}
-#else
-#define rfkill_suspend NULL
-#define rfkill_resume NULL
-#endif
-
-static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
- struct rfkill *rfkill = to_rfkill(dev);
- int error;
-
- error = add_uevent_var(env, "RFKILL_NAME=%s", rfkill->name);
- if (error)
- return error;
- error = add_uevent_var(env, "RFKILL_TYPE=%s",
- rfkill_get_type_str(rfkill->type));
- if (error)
- return error;
- error = add_uevent_var(env, "RFKILL_STATE=%d", rfkill->state);
- return error;
-}
-
-static struct class rfkill_class = {
- .name = "rfkill",
- .dev_release = rfkill_release,
- .dev_attrs = rfkill_dev_attrs,
- .suspend = rfkill_suspend,
- .resume = rfkill_resume,
- .dev_uevent = rfkill_dev_uevent,
-};
-
-static int rfkill_check_duplicity(const struct rfkill *rfkill)
-{
- struct rfkill *p;
- unsigned long seen[BITS_TO_LONGS(RFKILL_TYPE_MAX)];
-
- memset(seen, 0, sizeof(seen));
-
- list_for_each_entry(p, &rfkill_list, node) {
- if (WARN((p == rfkill), KERN_WARNING
- "rfkill: illegal attempt to register "
- "an already registered rfkill struct\n"))
- return -EEXIST;
- set_bit(p->type, seen);
- }
-
- /* 0: first switch of its kind */
- return (test_bit(rfkill->type, seen)) ? 1 : 0;
-}
-
-static int rfkill_add_switch(struct rfkill *rfkill)
-{
- int error;
-
- mutex_lock(&rfkill_global_mutex);
-
- error = rfkill_check_duplicity(rfkill);
- if (error < 0)
- goto unlock_out;
-
- if (!error) {
- /* lock default after first use */
- set_bit(rfkill->type, rfkill_states_lockdflt);
- rfkill_global_states[rfkill->type].current_state =
- rfkill_global_states[rfkill->type].default_state;
- }
-
- rfkill_toggle_radio(rfkill,
- rfkill_global_states[rfkill->type].current_state,
- 0);
-
- list_add_tail(&rfkill->node, &rfkill_list);
-
- error = 0;
-unlock_out:
- mutex_unlock(&rfkill_global_mutex);
-
- return error;
-}
-
-static void rfkill_remove_switch(struct rfkill *rfkill)
-{
- mutex_lock(&rfkill_global_mutex);
- list_del_init(&rfkill->node);
- mutex_unlock(&rfkill_global_mutex);
-
- mutex_lock(&rfkill->mutex);
- rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1);
- mutex_unlock(&rfkill->mutex);
-}
-
-/**
- * rfkill_allocate - allocate memory for rfkill structure.
- * @parent: device that has rf switch on it
- * @type: type of the switch (RFKILL_TYPE_*)
- *
- * This function should be called by the network driver when it needs
- * rfkill structure. Once the structure is allocated the driver should
- * finish its initialization by setting the name, private data, enable_radio
- * and disable_radio methods and then register it with rfkill_register().
- *
- * NOTE: If registration fails the structure shoudl be freed by calling
- * rfkill_free() otherwise rfkill_unregister() should be used.
- */
-struct rfkill * __must_check rfkill_allocate(struct device *parent,
- enum rfkill_type type)
-{
- struct rfkill *rfkill;
- struct device *dev;
-
- if (WARN((type >= RFKILL_TYPE_MAX),
- KERN_WARNING
- "rfkill: illegal type %d passed as parameter "
- "to rfkill_allocate\n", type))
- return NULL;
-
- rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL);
- if (!rfkill)
- return NULL;
-
- mutex_init(&rfkill->mutex);
- INIT_LIST_HEAD(&rfkill->node);
- rfkill->type = type;
-
- dev = &rfkill->dev;
- dev->class = &rfkill_class;
- dev->parent = parent;
- device_initialize(dev);
-
- __module_get(THIS_MODULE);
-
- return rfkill;
-}
-EXPORT_SYMBOL(rfkill_allocate);
-
-/**
- * rfkill_free - Mark rfkill structure for deletion
- * @rfkill: rfkill structure to be destroyed
- *
- * Decrements reference count of the rfkill structure so it is destroyed.
- * Note that rfkill_free() should _not_ be called after rfkill_unregister().
- */
-void rfkill_free(struct rfkill *rfkill)
-{
- if (rfkill)
- put_device(&rfkill->dev);
-}
-EXPORT_SYMBOL(rfkill_free);
-
-static void rfkill_led_trigger_register(struct rfkill *rfkill)
-{
-#ifdef CONFIG_RFKILL_LEDS
- int error;
-
- if (!rfkill->led_trigger.name)
- rfkill->led_trigger.name = dev_name(&rfkill->dev);
- if (!rfkill->led_trigger.activate)
- rfkill->led_trigger.activate = rfkill_led_trigger_activate;
- error = led_trigger_register(&rfkill->led_trigger);
- if (error)
- rfkill->led_trigger.name = NULL;
-#endif /* CONFIG_RFKILL_LEDS */
-}
-
-static void rfkill_led_trigger_unregister(struct rfkill *rfkill)
-{
-#ifdef CONFIG_RFKILL_LEDS
- if (rfkill->led_trigger.name) {
- led_trigger_unregister(&rfkill->led_trigger);
- rfkill->led_trigger.name = NULL;
- }
-#endif
-}
-
-/**
- * rfkill_register - Register a rfkill structure.
- * @rfkill: rfkill structure to be registered
- *
- * This function should be called by the network driver when the rfkill
- * structure needs to be registered. Immediately from registration the
- * switch driver should be able to service calls to toggle_radio.
- */
-int __must_check rfkill_register(struct rfkill *rfkill)
-{
- static atomic_t rfkill_no = ATOMIC_INIT(0);
- struct device *dev = &rfkill->dev;
- int error;
-
- if (WARN((!rfkill || !rfkill->toggle_radio ||
- rfkill->type >= RFKILL_TYPE_MAX ||
- rfkill->state >= RFKILL_STATE_MAX),
- KERN_WARNING
- "rfkill: attempt to register a "
- "badly initialized rfkill struct\n"))
- return -EINVAL;
-
- dev_set_name(dev, "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1);
-
- rfkill_led_trigger_register(rfkill);
-
- error = rfkill_add_switch(rfkill);
- if (error) {
- rfkill_led_trigger_unregister(rfkill);
- return error;
- }
-
- error = device_add(dev);
- if (error) {
- rfkill_remove_switch(rfkill);
- rfkill_led_trigger_unregister(rfkill);
- return error;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(rfkill_register);
-
-/**
- * rfkill_unregister - Unregister a rfkill structure.
- * @rfkill: rfkill structure to be unregistered
- *
- * This function should be called by the network driver during device
- * teardown to destroy rfkill structure. Note that rfkill_free() should
- * _not_ be called after rfkill_unregister().
- */
-void rfkill_unregister(struct rfkill *rfkill)
-{
- BUG_ON(!rfkill);
- device_del(&rfkill->dev);
- rfkill_remove_switch(rfkill);
- rfkill_led_trigger_unregister(rfkill);
- put_device(&rfkill->dev);
-}
-EXPORT_SYMBOL(rfkill_unregister);
-
-/**
- * rfkill_set_default - set initial value for a switch type
- * @type - the type of switch to set the default state of
- * @state - the new default state for that group of switches
- *
- * Sets the initial state rfkill should use for a given type.
- * The following initial states are allowed: RFKILL_STATE_SOFT_BLOCKED
- * and RFKILL_STATE_UNBLOCKED.
- *
- * This function is meant to be used by platform drivers for platforms
- * that can save switch state across power down/reboot.
- *
- * The default state for each switch type can be changed exactly once.
- * After a switch of that type is registered, the default state cannot
- * be changed anymore. This guards against multiple drivers it the
- * same platform trying to set the initial switch default state, which
- * is not allowed.
- *
- * Returns -EPERM if the state has already been set once or is in use,
- * so drivers likely want to either ignore or at most printk(KERN_NOTICE)
- * if this function returns -EPERM.
- *
- * Returns 0 if the new default state was set, or an error if it
- * could not be set.
- */
-int rfkill_set_default(enum rfkill_type type, enum rfkill_state state)
-{
- int error;
-
- if (WARN((type >= RFKILL_TYPE_MAX ||
- (state != RFKILL_STATE_SOFT_BLOCKED &&
- state != RFKILL_STATE_UNBLOCKED)),
- KERN_WARNING
- "rfkill: illegal state %d or type %d passed as "
- "parameter to rfkill_set_default\n", state, type))
- return -EINVAL;
-
- mutex_lock(&rfkill_global_mutex);
-
- if (!test_and_set_bit(type, rfkill_states_lockdflt)) {
- rfkill_global_states[type].default_state = state;
- rfkill_global_states[type].current_state = state;
- error = 0;
- } else
- error = -EPERM;
-
- mutex_unlock(&rfkill_global_mutex);
- return error;
-}
-EXPORT_SYMBOL_GPL(rfkill_set_default);
-
-/*
- * Rfkill module initialization/deinitialization.
- */
-static int __init rfkill_init(void)
-{
- int error;
- int i;
-
- /* 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 < RFKILL_TYPE_MAX; i++)
- rfkill_global_states[i].default_state = rfkill_default_state;
-
- error = class_register(&rfkill_class);
- if (error) {
- printk(KERN_ERR "rfkill: unable to register rfkill class\n");
- return error;
- }
-
- return 0;
-}
-
-static void __exit rfkill_exit(void)
-{
- class_unregister(&rfkill_class);
-}
-
-subsys_initcall(rfkill_init);
-module_exit(rfkill_exit);