Commit | Line | Data |
---|---|---|
ad97edd2 MA |
1 | /****************************************************************************** |
2 | * | |
3 | * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved. | |
4 | * | |
5 | * Portions of this file are derived from the ipw3945 project, as well | |
6 | * as portions of the ieee80211 subsystem header files. | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify it | |
9 | * under the terms of version 2 of the GNU General Public License as | |
10 | * published by the Free Software Foundation. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
15 | * more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License along with | |
18 | * this program; if not, write to the Free Software Foundation, Inc., | |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA | |
20 | * | |
21 | * The full GNU General Public License is included in this distribution in the | |
22 | * file called LICENSE. | |
23 | * | |
24 | * Contact Information: | |
25 | * James P. Ketrenos <ipw2100-admin@linux.intel.com> | |
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | |
27 | *****************************************************************************/ | |
28 | #include <linux/kernel.h> | |
29 | #include <linux/module.h> | |
30 | #include <linux/version.h> | |
31 | #include <linux/init.h> | |
32 | ||
33 | #include <net/mac80211.h> | |
34 | ||
35 | #include "iwl-eeprom.h" | |
3e0d4cb1 | 36 | #include "iwl-dev.h" |
fee1247a | 37 | #include "iwl-core.h" |
ad97edd2 MA |
38 | #include "iwl-helpers.h" |
39 | ||
40 | ||
ad97edd2 MA |
41 | /* software rf-kill from user */ |
42 | static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) | |
43 | { | |
44 | struct iwl_priv *priv = data; | |
45 | int err = 0; | |
46 | ||
47 | if (!priv->rfkill_mngr.rfkill) | |
48 | return 0; | |
49 | ||
59003835 MA |
50 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
51 | return 0; | |
52 | ||
ad97edd2 MA |
53 | IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); |
54 | mutex_lock(&priv->mutex); | |
55 | ||
56 | switch (state) { | |
57 | case RFKILL_STATE_ON: | |
58 | priv->cfg->ops->lib->radio_kill_sw(priv, 0); | |
59 | /* if HW rf-kill is set dont allow ON state */ | |
60 | if (iwl_is_rfkill(priv)) | |
61 | err = -EBUSY; | |
62 | break; | |
63 | case RFKILL_STATE_OFF: | |
64 | priv->cfg->ops->lib->radio_kill_sw(priv, 1); | |
65 | if (!iwl_is_rfkill(priv)) | |
66 | err = -EBUSY; | |
67 | break; | |
68 | } | |
69 | mutex_unlock(&priv->mutex); | |
70 | ||
71 | return err; | |
72 | } | |
73 | ||
74 | int iwl_rfkill_init(struct iwl_priv *priv) | |
75 | { | |
76 | struct device *device = wiphy_dev(priv->hw->wiphy); | |
77 | int ret = 0; | |
78 | ||
79 | BUG_ON(device == NULL); | |
80 | ||
03d29c68 | 81 | IWL_DEBUG_RF_KILL("Initializing RFKILL.\n"); |
ad97edd2 MA |
82 | priv->rfkill_mngr.rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); |
83 | if (!priv->rfkill_mngr.rfkill) { | |
03d29c68 | 84 | IWL_ERROR("Unable to allocate rfkill device.\n"); |
ad97edd2 MA |
85 | ret = -ENOMEM; |
86 | goto error; | |
87 | } | |
88 | ||
89 | priv->rfkill_mngr.rfkill->name = priv->cfg->name; | |
90 | priv->rfkill_mngr.rfkill->data = priv; | |
91 | priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; | |
92 | priv->rfkill_mngr.rfkill->toggle_radio = iwl_rfkill_soft_rf_kill; | |
93 | priv->rfkill_mngr.rfkill->user_claim_unsupported = 1; | |
94 | ||
95 | priv->rfkill_mngr.rfkill->dev.class->suspend = NULL; | |
96 | priv->rfkill_mngr.rfkill->dev.class->resume = NULL; | |
97 | ||
98 | priv->rfkill_mngr.input_dev = input_allocate_device(); | |
99 | if (!priv->rfkill_mngr.input_dev) { | |
03d29c68 | 100 | IWL_ERROR("Unable to allocate rfkill input device.\n"); |
ad97edd2 MA |
101 | ret = -ENOMEM; |
102 | goto freed_rfkill; | |
103 | } | |
104 | ||
105 | priv->rfkill_mngr.input_dev->name = priv->cfg->name; | |
106 | priv->rfkill_mngr.input_dev->phys = wiphy_name(priv->hw->wiphy); | |
107 | priv->rfkill_mngr.input_dev->id.bustype = BUS_HOST; | |
108 | priv->rfkill_mngr.input_dev->id.vendor = priv->pci_dev->vendor; | |
109 | priv->rfkill_mngr.input_dev->dev.parent = device; | |
110 | priv->rfkill_mngr.input_dev->evbit[0] = BIT(EV_KEY); | |
111 | set_bit(KEY_WLAN, priv->rfkill_mngr.input_dev->keybit); | |
112 | ||
113 | ret = rfkill_register(priv->rfkill_mngr.rfkill); | |
03d29c68 MA |
114 | if (ret) { |
115 | IWL_ERROR("Unable to register rfkill: %d\n", ret); | |
ad97edd2 | 116 | goto free_input_dev; |
03d29c68 | 117 | } |
ad97edd2 MA |
118 | |
119 | ret = input_register_device(priv->rfkill_mngr.input_dev); | |
03d29c68 MA |
120 | if (ret) { |
121 | IWL_ERROR("Unable to register rfkill input device: %d\n", ret); | |
ad97edd2 | 122 | goto unregister_rfkill; |
03d29c68 | 123 | } |
ad97edd2 | 124 | |
03d29c68 | 125 | IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); |
ad97edd2 MA |
126 | return ret; |
127 | ||
128 | unregister_rfkill: | |
129 | rfkill_unregister(priv->rfkill_mngr.rfkill); | |
03d29c68 | 130 | priv->rfkill_mngr.rfkill = NULL; |
ad97edd2 MA |
131 | |
132 | free_input_dev: | |
133 | input_free_device(priv->rfkill_mngr.input_dev); | |
134 | priv->rfkill_mngr.input_dev = NULL; | |
135 | ||
136 | freed_rfkill: | |
03d29c68 MA |
137 | if (priv->rfkill_mngr.rfkill != NULL) |
138 | rfkill_free(priv->rfkill_mngr.rfkill); | |
ad97edd2 MA |
139 | priv->rfkill_mngr.rfkill = NULL; |
140 | ||
141 | error: | |
03d29c68 | 142 | IWL_DEBUG_RF_KILL("RFKILL initialization complete.\n"); |
ad97edd2 MA |
143 | return ret; |
144 | } | |
145 | EXPORT_SYMBOL(iwl_rfkill_init); | |
146 | ||
147 | void iwl_rfkill_unregister(struct iwl_priv *priv) | |
148 | { | |
149 | ||
150 | if (priv->rfkill_mngr.input_dev) | |
151 | input_unregister_device(priv->rfkill_mngr.input_dev); | |
152 | ||
153 | if (priv->rfkill_mngr.rfkill) | |
154 | rfkill_unregister(priv->rfkill_mngr.rfkill); | |
ad97edd2 | 155 | |
03d29c68 MA |
156 | priv->rfkill_mngr.input_dev = NULL; |
157 | priv->rfkill_mngr.rfkill = NULL; | |
ad97edd2 | 158 | } |
03d29c68 | 159 | EXPORT_SYMBOL(iwl_rfkill_unregister); |
ad97edd2 MA |
160 | |
161 | /* set rf-kill to the right state. */ | |
162 | void iwl_rfkill_set_hw_state(struct iwl_priv *priv) | |
163 | { | |
164 | ||
165 | if (!priv->rfkill_mngr.rfkill) | |
166 | return; | |
167 | ||
168 | if (!iwl_is_rfkill(priv)) | |
169 | priv->rfkill_mngr.rfkill->state = RFKILL_STATE_ON; | |
170 | else | |
171 | priv->rfkill_mngr.rfkill->state = RFKILL_STATE_OFF; | |
172 | } | |
173 | EXPORT_SYMBOL(iwl_rfkill_set_hw_state); |