Commit cf4328cd949c2086091c62c5685f1580fe9b55e4

Authored by Ivo van Doorn
Committed by David S. Miller
1 parent 2396a22e09

[NET]: rfkill: add support for input key to control wireless radio

The RF kill patch that provides infrastructure for implementing
switches controlling radio states on various network and other cards.

[dtor@insightbb.com: address review comments]
[akpm@linux-foundation.org: cleanups, build fixes]

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 7 changed files with 703 additions and 0 deletions Side-by-side Diff

include/linux/rfkill.h
  1 +#ifndef __RFKILL_H
  2 +#define __RFKILL_H
  3 +
  4 +/*
  5 + * Copyright (C) 2006 Ivo van Doorn
  6 + * Copyright (C) 2007 Dmitry Torokhov
  7 + *
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License as published by
  10 + * the Free Software Foundation; either version 2 of the License, or
  11 + * (at your option) any later version.
  12 + *
  13 + * This program is distributed in the hope that it will be useful,
  14 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16 + * GNU General Public License for more details.
  17 + *
  18 + * You should have received a copy of the GNU General Public License
  19 + * along with this program; if not, write to the
  20 + * Free Software Foundation, Inc.,
  21 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22 + */
  23 +
  24 +#include <linux/types.h>
  25 +#include <linux/kernel.h>
  26 +#include <linux/list.h>
  27 +#include <linux/mutex.h>
  28 +#include <linux/device.h>
  29 +
  30 +/**
  31 + * enum rfkill_type - type of rfkill switch.
  32 + * RFKILL_TYPE_WLAN: switch is no a Wireless network devices.
  33 + * RFKILL_TYPE_BlUETOOTH: switch is on a bluetooth device.
  34 + * RFKILL_TYPE_IRDA: switch is on an infrared devices.
  35 + */
  36 +enum rfkill_type {
  37 + RFKILL_TYPE_WLAN = 0,
  38 + RFKILL_TYPE_BLUETOOTH = 1,
  39 + RFKILL_TYPE_IRDA = 2,
  40 + RFKILL_TYPE_MAX = 3,
  41 +};
  42 +
  43 +enum rfkill_state {
  44 + RFKILL_STATE_OFF = 0,
  45 + RFKILL_STATE_ON = 1,
  46 +};
  47 +
  48 +/**
  49 + * struct rfkill - rfkill control structure.
  50 + * @name: Name of the switch.
  51 + * @type: Radio type which the button controls, the value stored
  52 + * here should be a value from enum rfkill_type.
  53 + * @state: State of the switch (on/off).
  54 + * @user_claim: Set when the switch is controlled exlusively by userspace.
  55 + * @mutex: Guards switch state transitions
  56 + * @data: Pointer to the RF button drivers private data which will be
  57 + * passed along when toggling radio state.
  58 + * @toggle_radio(): Mandatory handler to control state of the radio.
  59 + * @dev: Device structure integrating the switch into device tree.
  60 + * @node: Used to place switch into list of all switches known to the
  61 + * the system.
  62 + *
  63 + * This structure represents a RF switch located on a network device.
  64 + */
  65 +struct rfkill {
  66 + char *name;
  67 + enum rfkill_type type;
  68 +
  69 + enum rfkill_state state;
  70 + bool user_claim;
  71 +
  72 + struct mutex mutex;
  73 +
  74 + void *data;
  75 + int (*toggle_radio)(void *data, enum rfkill_state state);
  76 +
  77 + struct device dev;
  78 + struct list_head node;
  79 +};
  80 +#define to_rfkill(d) container_of(d, struct rfkill, dev)
  81 +
  82 +struct rfkill *rfkill_allocate(struct device *parent, enum rfkill_type type);
  83 +void rfkill_free(struct rfkill *rfkill);
  84 +int rfkill_register(struct rfkill *rfkill);
  85 +void rfkill_unregister(struct rfkill *rfkill);
  86 +
  87 +void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state);
  88 +
  89 +#endif /* RFKILL_H */
... ... @@ -225,6 +225,8 @@
225 225  
226 226 endmenu
227 227  
  228 +source "net/rfkill/Kconfig"
  229 +
228 230 endif # if NET
229 231 endmenu # Networking
... ... @@ -51,6 +51,7 @@
51 51 obj-$(CONFIG_TIPC) += tipc/
52 52 obj-$(CONFIG_NETLABEL) += netlabel/
53 53 obj-$(CONFIG_IUCV) += iucv/
  54 +obj-$(CONFIG_RFKILL) += rfkill/
54 55  
55 56 ifeq ($(CONFIG_NET),y)
56 57 obj-$(CONFIG_SYSCTL) += sysctl_net.o
  1 +#
  2 +# RF switch subsystem configuration
  3 +#
  4 +menuconfig RFKILL
  5 + tristate "RF switch subsystem support"
  6 + help
  7 + Say Y here if you want to have control over RF switches
  8 + found on many WiFi, Bluetooth and IRDA cards.
  9 +
  10 + To compile this driver as a module, choose M here: the
  11 + module will be called rfkill.
  12 +
  13 +config RFKILL_INPUT
  14 + tristate "Input layer to RF switch connector"
  15 + depends on RFKILL && INPUT
  16 + help
  17 + Say Y here if you want kernel automatically toggle state
  18 + of RF switches on and off when user presses appropriate
  19 + button or a key on the keyboard. Without this module you
  20 + need a some kind of userspace application to control
  21 + state of the switches.
  22 +
  23 + To compile this driver as a module, choose M here: the
  24 + module will be called rfkill-input.
  1 +#
  2 +# Makefile for the RF switch subsystem.
  3 +#
  4 +
  5 +obj-$(CONFIG_RFKILL) += rfkill.o
  6 +obj-$(CONFIG_RFKILL_INPUT) += rfkill-input.o
net/rfkill/rfkill-input.c
  1 +/*
  2 + * Input layer to RF Kill interface connector
  3 + *
  4 + * Copyright (c) 2007 Dmitry Torokhov
  5 + */
  6 +
  7 +/*
  8 + * This program is free software; you can redistribute it and/or modify it
  9 + * under the terms of the GNU General Public License version 2 as published
  10 + * by the Free Software Foundation.
  11 + */
  12 +
  13 +#include <linux/module.h>
  14 +#include <linux/input.h>
  15 +#include <linux/slab.h>
  16 +#include <linux/workqueue.h>
  17 +#include <linux/init.h>
  18 +#include <linux/rfkill.h>
  19 +
  20 +MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
  21 +MODULE_DESCRIPTION("Input layer to RF switch connector");
  22 +MODULE_LICENSE("GPL");
  23 +
  24 +struct rfkill_task {
  25 + struct work_struct work;
  26 + enum rfkill_type type;
  27 + struct mutex mutex; /* ensures that task is serialized */
  28 + spinlock_t lock; /* for accessing last and desired state */
  29 + unsigned long last; /* last schedule */
  30 + enum rfkill_state desired_state; /* on/off */
  31 + enum rfkill_state current_state; /* on/off */
  32 +};
  33 +
  34 +static void rfkill_task_handler(struct work_struct *work)
  35 +{
  36 + struct rfkill_task *task = container_of(work, struct rfkill_task, work);
  37 + enum rfkill_state state;
  38 +
  39 + mutex_lock(&task->mutex);
  40 +
  41 + /*
  42 + * Use temp variable to fetch desired state to keep it
  43 + * consistent even if rfkill_schedule_toggle() runs in
  44 + * another thread or interrupts us.
  45 + */
  46 + state = task->desired_state;
  47 +
  48 + if (state != task->current_state) {
  49 + rfkill_switch_all(task->type, state);
  50 + task->current_state = state;
  51 + }
  52 +
  53 + mutex_unlock(&task->mutex);
  54 +}
  55 +
  56 +static void rfkill_schedule_toggle(struct rfkill_task *task)
  57 +{
  58 + unsigned int flags;
  59 +
  60 + spin_lock_irqsave(&task->lock, flags);
  61 +
  62 + if (time_after(jiffies, task->last + msecs_to_jiffies(200))) {
  63 + task->desired_state = !task->desired_state;
  64 + task->last = jiffies;
  65 + schedule_work(&task->work);
  66 + }
  67 +
  68 + spin_unlock_irqrestore(&task->lock, flags);
  69 +}
  70 +
  71 +#define DEFINE_RFKILL_TASK(n, t) \
  72 + struct rfkill_task n = { \
  73 + .work = __WORK_INITIALIZER(n.work, \
  74 + rfkill_task_handler), \
  75 + .type = t, \
  76 + .mutex = __MUTEX_INITIALIZER(n.mutex), \
  77 + .lock = __SPIN_LOCK_UNLOCKED(n.lock), \
  78 + .desired_state = RFKILL_STATE_ON, \
  79 + .current_state = RFKILL_STATE_ON, \
  80 + }
  81 +
  82 +static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN);
  83 +static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH);
  84 +
  85 +static void rfkill_event(struct input_handle *handle, unsigned int type,
  86 + unsigned int code, int down)
  87 +{
  88 + if (type == EV_KEY && down == 1) {
  89 + switch (code) {
  90 + case KEY_WLAN:
  91 + rfkill_schedule_toggle(&rfkill_wlan);
  92 + break;
  93 + case KEY_BLUETOOTH:
  94 + rfkill_schedule_toggle(&rfkill_bt);
  95 + break;
  96 + default:
  97 + break;
  98 + }
  99 + }
  100 +}
  101 +
  102 +static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
  103 + const struct input_device_id *id)
  104 +{
  105 + struct input_handle *handle;
  106 + int error;
  107 +
  108 + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
  109 + if (!handle)
  110 + return -ENOMEM;
  111 +
  112 + handle->dev = dev;
  113 + handle->handler = handler;
  114 + handle->name = "rfkill";
  115 +
  116 + error = input_register_handle(handle);
  117 + if (error)
  118 + goto err_free_handle;
  119 +
  120 + error = input_open_device(handle);
  121 + if (error)
  122 + goto err_unregister_handle;
  123 +
  124 + return 0;
  125 +
  126 + err_unregister_handle:
  127 + input_unregister_handle(handle);
  128 + err_free_handle:
  129 + kfree(handle);
  130 + return error;
  131 +}
  132 +
  133 +static void rfkill_disconnect(struct input_handle *handle)
  134 +{
  135 + input_close_device(handle);
  136 + input_unregister_handle(handle);
  137 + kfree(handle);
  138 +}
  139 +
  140 +static const struct input_device_id rfkill_ids[] = {
  141 + {
  142 + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
  143 + .evbit = { BIT(EV_KEY) },
  144 + .keybit = { [LONG(KEY_WLAN)] = BIT(KEY_WLAN) },
  145 + },
  146 + {
  147 + .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
  148 + .evbit = { BIT(EV_KEY) },
  149 + .keybit = { [LONG(KEY_BLUETOOTH)] = BIT(KEY_BLUETOOTH) },
  150 + },
  151 + { }
  152 +};
  153 +
  154 +static struct input_handler rfkill_handler = {
  155 + .event = rfkill_event,
  156 + .connect = rfkill_connect,
  157 + .disconnect = rfkill_disconnect,
  158 + .name = "rfkill",
  159 + .id_table = rfkill_ids,
  160 +};
  161 +
  162 +static int __init rfkill_handler_init(void)
  163 +{
  164 + return input_register_handler(&rfkill_handler);
  165 +}
  166 +
  167 +static void __exit rfkill_handler_exit(void)
  168 +{
  169 + input_unregister_handler(&rfkill_handler);
  170 + flush_scheduled_work();
  171 +}
  172 +
  173 +module_init(rfkill_handler_init);
  174 +module_exit(rfkill_handler_exit);
  1 +/*
  2 + * Copyright (C) 2006 Ivo van Doorn
  3 + * Copyright (C) 2007 Dmitry Torokhov
  4 + *
  5 + * This program is free software; you can redistribute it and/or modify
  6 + * it under the terms of the GNU General Public License as published by
  7 + * the Free Software Foundation; either version 2 of the License, or
  8 + * (at your option) any later version.
  9 + *
  10 + * This program is distributed in the hope that it will be useful,
  11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13 + * GNU General Public License for more details.
  14 + *
  15 + * You should have received a copy of the GNU General Public License
  16 + * along with this program; if not, write to the
  17 + * Free Software Foundation, Inc.,
  18 + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19 + */
  20 +
  21 +#include <linux/kernel.h>
  22 +#include <linux/module.h>
  23 +#include <linux/init.h>
  24 +#include <linux/workqueue.h>
  25 +#include <linux/capability.h>
  26 +#include <linux/list.h>
  27 +#include <linux/mutex.h>
  28 +#include <linux/rfkill.h>
  29 +
  30 +MODULE_AUTHOR("Ivo van Doorn <IvDoorn@gmail.com>");
  31 +MODULE_VERSION("1.0");
  32 +MODULE_DESCRIPTION("RF switch support");
  33 +MODULE_LICENSE("GPL");
  34 +
  35 +static LIST_HEAD(rfkill_list); /* list of registered rf switches */
  36 +static DEFINE_MUTEX(rfkill_mutex);
  37 +
  38 +static enum rfkill_state rfkill_states[RFKILL_TYPE_MAX];
  39 +
  40 +static int rfkill_toggle_radio(struct rfkill *rfkill,
  41 + enum rfkill_state state)
  42 +{
  43 + int retval;
  44 +
  45 + retval = mutex_lock_interruptible(&rfkill->mutex);
  46 + if (retval)
  47 + return retval;
  48 +
  49 + if (state != rfkill->state) {
  50 + retval = rfkill->toggle_radio(rfkill->data, state);
  51 + if (!retval)
  52 + rfkill->state = state;
  53 + }
  54 +
  55 + mutex_unlock(&rfkill->mutex);
  56 + return retval;
  57 +}
  58 +
  59 +/**
  60 + * rfkill_switch_all - Toggle state of all switches of given type
  61 + * @type: type of interfaces to be affeceted
  62 + * @state: the new state
  63 + *
  64 + * This function toggles state of all switches of given type unless
  65 + * a specific switch is claimed by userspace in which case it is
  66 + * left alone.
  67 + */
  68 +
  69 +void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state)
  70 +{
  71 + struct rfkill *rfkill;
  72 +
  73 + mutex_lock(&rfkill_mutex);
  74 +
  75 + rfkill_states[type] = state;
  76 +
  77 + list_for_each_entry(rfkill, &rfkill_list, node) {
  78 + if (!rfkill->user_claim)
  79 + rfkill_toggle_radio(rfkill, state);
  80 + }
  81 +
  82 + mutex_unlock(&rfkill_mutex);
  83 +}
  84 +EXPORT_SYMBOL(rfkill_switch_all);
  85 +
  86 +static ssize_t rfkill_name_show(struct device *dev,
  87 + struct device_attribute *attr,
  88 + char *buf)
  89 +{
  90 + struct rfkill *rfkill = to_rfkill(dev);
  91 +
  92 + return sprintf(buf, "%s\n", rfkill->name);
  93 +}
  94 +
  95 +static ssize_t rfkill_type_show(struct device *dev,
  96 + struct device_attribute *attr,
  97 + char *buf)
  98 +{
  99 + struct rfkill *rfkill = to_rfkill(dev);
  100 + const char *type;
  101 +
  102 + switch (rfkill->type) {
  103 + case RFKILL_TYPE_WLAN:
  104 + type = "wlan";
  105 + break;
  106 + case RFKILL_TYPE_BLUETOOTH:
  107 + type = "bluetooth";
  108 + break;
  109 + case RFKILL_TYPE_IRDA:
  110 + type = "irda";
  111 + break;
  112 + default:
  113 + BUG();
  114 + }
  115 +
  116 + return sprintf(buf, "%s\n", type);
  117 +}
  118 +
  119 +static ssize_t rfkill_state_show(struct device *dev,
  120 + struct device_attribute *attr,
  121 + char *buf)
  122 +{
  123 + struct rfkill *rfkill = to_rfkill(dev);
  124 +
  125 + return sprintf(buf, "%d\n", rfkill->state);
  126 +}
  127 +
  128 +static ssize_t rfkill_state_store(struct device *dev,
  129 + struct device_attribute *attr,
  130 + const char *buf, size_t count)
  131 +{
  132 + struct rfkill *rfkill = to_rfkill(dev);
  133 + unsigned int state = simple_strtoul(buf, NULL, 0);
  134 + int error;
  135 +
  136 + if (!capable(CAP_NET_ADMIN))
  137 + return -EPERM;
  138 +
  139 + error = rfkill_toggle_radio(rfkill,
  140 + state ? RFKILL_STATE_ON : RFKILL_STATE_OFF);
  141 + if (error)
  142 + return error;
  143 +
  144 + return count;
  145 +}
  146 +
  147 +static ssize_t rfkill_claim_show(struct device *dev,
  148 + struct device_attribute *attr,
  149 + char *buf)
  150 +{
  151 + struct rfkill *rfkill = to_rfkill(dev);
  152 +
  153 + return sprintf(buf, "%d", rfkill->user_claim);
  154 +}
  155 +
  156 +static ssize_t rfkill_claim_store(struct device *dev,
  157 + struct device_attribute *attr,
  158 + const char *buf, size_t count)
  159 +{
  160 + struct rfkill *rfkill = to_rfkill(dev);
  161 + bool claim = !!simple_strtoul(buf, NULL, 0);
  162 + int error;
  163 +
  164 + if (!capable(CAP_NET_ADMIN))
  165 + return -EPERM;
  166 +
  167 + /*
  168 + * Take the global lock to make sure the kernel is not in
  169 + * the middle of rfkill_switch_all
  170 + */
  171 + error = mutex_lock_interruptible(&rfkill_mutex);
  172 + if (error)
  173 + return error;
  174 +
  175 + if (rfkill->user_claim != claim) {
  176 + if (!claim)
  177 + rfkill_toggle_radio(rfkill,
  178 + rfkill_states[rfkill->type]);
  179 + rfkill->user_claim = claim;
  180 + }
  181 +
  182 + mutex_unlock(&rfkill_mutex);
  183 +
  184 + return count;
  185 +}
  186 +
  187 +static struct device_attribute rfkill_dev_attrs[] = {
  188 + __ATTR(name, S_IRUGO, rfkill_name_show, NULL),
  189 + __ATTR(type, S_IRUGO, rfkill_type_show, NULL),
  190 + __ATTR(state, S_IRUGO, rfkill_state_show, rfkill_state_store),
  191 + __ATTR(claim, S_IRUGO|S_IWUSR, rfkill_claim_show, rfkill_claim_store),
  192 + __ATTR_NULL
  193 +};
  194 +
  195 +static void rfkill_release(struct device *dev)
  196 +{
  197 + struct rfkill *rfkill = to_rfkill(dev);
  198 +
  199 + kfree(rfkill);
  200 + module_put(THIS_MODULE);
  201 +}
  202 +
  203 +#ifdef CONFIG_PM
  204 +static int rfkill_suspend(struct device *dev, pm_message_t state)
  205 +{
  206 + struct rfkill *rfkill = to_rfkill(dev);
  207 +
  208 + if (dev->power.power_state.event != state.event) {
  209 + if (state.event == PM_EVENT_SUSPEND) {
  210 + mutex_lock(&rfkill->mutex);
  211 +
  212 + if (rfkill->state == RFKILL_STATE_ON)
  213 + rfkill->toggle_radio(rfkill->data,
  214 + RFKILL_STATE_OFF);
  215 +
  216 + mutex_unlock(&rfkill->mutex);
  217 + }
  218 +
  219 + dev->power.power_state = state;
  220 + }
  221 +
  222 + return 0;
  223 +}
  224 +
  225 +static int rfkill_resume(struct device *dev)
  226 +{
  227 + struct rfkill *rfkill = to_rfkill(dev);
  228 +
  229 + if (dev->power.power_state.event != PM_EVENT_ON) {
  230 + mutex_lock(&rfkill->mutex);
  231 +
  232 + if (rfkill->state == RFKILL_STATE_ON)
  233 + rfkill->toggle_radio(rfkill->data, RFKILL_STATE_ON);
  234 +
  235 + mutex_unlock(&rfkill->mutex);
  236 + }
  237 +
  238 + dev->power.power_state = PMSG_ON;
  239 + return 0;
  240 +}
  241 +#else
  242 +#define rfkill_suspend NULL
  243 +#define rfkill_resume NULL
  244 +#endif
  245 +
  246 +static struct class rfkill_class = {
  247 + .name = "rfkill",
  248 + .dev_release = rfkill_release,
  249 + .dev_attrs = rfkill_dev_attrs,
  250 + .suspend = rfkill_suspend,
  251 + .resume = rfkill_resume,
  252 +};
  253 +
  254 +static int rfkill_add_switch(struct rfkill *rfkill)
  255 +{
  256 + int retval;
  257 +
  258 + retval = mutex_lock_interruptible(&rfkill_mutex);
  259 + if (retval)
  260 + return retval;
  261 +
  262 + retval = rfkill_toggle_radio(rfkill, rfkill_states[rfkill->type]);
  263 + if (retval)
  264 + goto out;
  265 +
  266 + list_add_tail(&rfkill->node, &rfkill_list);
  267 +
  268 + out:
  269 + mutex_unlock(&rfkill_mutex);
  270 + return retval;
  271 +}
  272 +
  273 +static void rfkill_remove_switch(struct rfkill *rfkill)
  274 +{
  275 + mutex_lock(&rfkill_mutex);
  276 + list_del_init(&rfkill->node);
  277 + rfkill_toggle_radio(rfkill, RFKILL_STATE_OFF);
  278 + mutex_unlock(&rfkill_mutex);
  279 +}
  280 +
  281 +/**
  282 + * rfkill_allocate - allocate memory for rfkill structure.
  283 + * @parent: device that has rf switch on it
  284 + * @type: type of the switch (wlan, bluetooth, irda)
  285 + *
  286 + * This function should be called by the network driver when it needs
  287 + * rfkill structure. Once the structure is allocated the driver shoud
  288 + * finish its initialization by setting name, private data, enable_radio
  289 + * and disable_radio methods and then register it with rfkill_register().
  290 + * NOTE: If registration fails the structure shoudl be freed by calling
  291 + * rfkill_free() otherwise rfkill_unregister() should be used.
  292 + */
  293 +struct rfkill *rfkill_allocate(struct device *parent, enum rfkill_type type)
  294 +{
  295 + struct rfkill *rfkill;
  296 + struct device *dev;
  297 +
  298 + rfkill = kzalloc(sizeof(struct rfkill), GFP_KERNEL);
  299 + if (rfkill)
  300 + return NULL;
  301 +
  302 + mutex_init(&rfkill->mutex);
  303 + INIT_LIST_HEAD(&rfkill->node);
  304 + rfkill->type = type;
  305 +
  306 + dev = &rfkill->dev;
  307 + dev->class = &rfkill_class;
  308 + dev->parent = parent;
  309 + device_initialize(dev);
  310 +
  311 + __module_get(THIS_MODULE);
  312 +
  313 + return rfkill;
  314 +}
  315 +EXPORT_SYMBOL(rfkill_allocate);
  316 +
  317 +/**
  318 + * rfkill_free - Mark rfkill structure for deletion
  319 + * @rfkill: rfkill structure to be destroyed
  320 + *
  321 + * Decrements reference count of rfkill structure so it is destoryed.
  322 + * Note that rfkill_free() should _not_ be called after rfkill_unregister().
  323 + */
  324 +void rfkill_free(struct rfkill *rfkill)
  325 +{
  326 + if (rfkill)
  327 + put_device(&rfkill->dev);
  328 +}
  329 +EXPORT_SYMBOL(rfkill_free);
  330 +
  331 +/**
  332 + * rfkill_register - Register a rfkill structure.
  333 + * @rfkill: rfkill structure to be registered
  334 + *
  335 + * This function should be called by the network driver when the rfkill
  336 + * structure needs to be registered. Immediately from registration the
  337 + * switch driver should be able to service calls to toggle_radio.
  338 + */
  339 +int rfkill_register(struct rfkill *rfkill)
  340 +{
  341 + static atomic_t rfkill_no = ATOMIC_INIT(0);
  342 + struct device *dev = &rfkill->dev;
  343 + int error;
  344 +
  345 + if (!rfkill->toggle_radio)
  346 + return -EINVAL;
  347 +
  348 + error = rfkill_add_switch(rfkill);
  349 + if (error)
  350 + return error;
  351 +
  352 + snprintf(dev->bus_id, sizeof(dev->bus_id),
  353 + "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1);
  354 +
  355 + error = device_add(dev);
  356 + if (error) {
  357 + rfkill_remove_switch(rfkill);
  358 + return error;
  359 + }
  360 +
  361 + return 0;
  362 +}
  363 +EXPORT_SYMBOL(rfkill_register);
  364 +
  365 +/**
  366 + * rfkill_unregister - Uegister a rfkill structure.
  367 + * @rfkill: rfkill structure to be unregistered
  368 + *
  369 + * This function should be called by the network driver during device
  370 + * teardown to destroy rfkill structure. Note that rfkill_free() should
  371 + * _not_ be called after rfkill_unregister().
  372 + */
  373 +void rfkill_unregister(struct rfkill *rfkill)
  374 +{
  375 + device_del(&rfkill->dev);
  376 + rfkill_remove_switch(rfkill);
  377 + put_device(&rfkill->dev);
  378 +}
  379 +EXPORT_SYMBOL(rfkill_unregister);
  380 +
  381 +/*
  382 + * Rfkill module initialization/deinitialization.
  383 + */
  384 +static int __init rfkill_init(void)
  385 +{
  386 + int error;
  387 + int i;
  388 +
  389 + for (i = 0; i < ARRAY_SIZE(rfkill_states); i++)
  390 + rfkill_states[i] = RFKILL_STATE_ON;
  391 +
  392 + error = class_register(&rfkill_class);
  393 + if (error) {
  394 + printk(KERN_ERR "rfkill: unable to register rfkill class\n");
  395 + return error;
  396 + }
  397 +
  398 + return 0;
  399 +}
  400 +
  401 +static void __exit rfkill_exit(void)
  402 +{
  403 + class_unregister(&rfkill_class);
  404 +}
  405 +
  406 +module_init(rfkill_init);
  407 +module_exit(rfkill_exit);