aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43legacy/rfkill.c
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2007-12-16 13:21:06 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 18:07:25 -0500
commit4ad36d780caf34630d1a4cc39f9bc11017f5b81d (patch)
treee108911eb96f8bf7379bc220a52723e03d8b41ee /drivers/net/wireless/b43legacy/rfkill.c
parentb7c5678f0b1e6c385b0b308a9e8298edf3c91a20 (diff)
b43legacy: Fix rfkill radio LED
This fixes Bug #9414 for b43legacy. This patch is the equivalent of one submitted earlier for b43. Since addition of the rfkill callback, the LED associated with the off switch on the radio has not worked for several reasons: (1) Essential data in the rfkill structure were missing. (2) The rfkill structure was initialized after the LED initialization. (3) There was a minor memory leak if the radio LED structure was inited. Once the above problems were fixed, additional difficulties were noted: (4) The radio LED was in the wrong state at startup. (5) The radio switch had to be manipulated twice for each state change. (6) A circular mutex locking situation existed. (7) If rfkill-input is built as a module, it is not automatically loaded. This patch fixes all of the above and removes a couple of sparse warnings. Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Stefano Brivio <stefano.brivio@polimi.it> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43legacy/rfkill.c')
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c133
1 files changed, 74 insertions, 59 deletions
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c
index b9d38a4f286d..520910fd5c45 100644
--- a/drivers/net/wireless/b43legacy/rfkill.c
+++ b/drivers/net/wireless/b43legacy/rfkill.c
@@ -26,6 +26,8 @@
26#include "radio.h" 26#include "radio.h"
27#include "b43legacy.h" 27#include "b43legacy.h"
28 28
29#include <linux/kmod.h>
30
29 31
30/* Returns TRUE, if the radio is enabled in hardware. */ 32/* Returns TRUE, if the radio is enabled in hardware. */
31static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) 33static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
@@ -51,7 +53,10 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
51 bool report_change = 0; 53 bool report_change = 0;
52 54
53 mutex_lock(&wl->mutex); 55 mutex_lock(&wl->mutex);
54 B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); 56 if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) {
57 mutex_unlock(&wl->mutex);
58 return;
59 }
55 enabled = b43legacy_is_hw_radio_enabled(dev); 60 enabled = b43legacy_is_hw_radio_enabled(dev);
56 if (unlikely(enabled != dev->radio_hw_enable)) { 61 if (unlikely(enabled != dev->radio_hw_enable)) {
57 dev->radio_hw_enable = enabled; 62 dev->radio_hw_enable = enabled;
@@ -61,8 +66,12 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)
61 } 66 }
62 mutex_unlock(&wl->mutex); 67 mutex_unlock(&wl->mutex);
63 68
64 if (unlikely(report_change)) 69 /* send the radio switch event to the system - note both a key press
65 input_report_key(poll_dev->input, KEY_WLAN, enabled); 70 * and a release are required */
71 if (unlikely(report_change)) {
72 input_report_key(poll_dev->input, KEY_WLAN, 1);
73 input_report_key(poll_dev->input, KEY_WLAN, 0);
74 }
66} 75}
67 76
68/* Called when the RFKILL toggled in software. 77/* Called when the RFKILL toggled in software.
@@ -71,13 +80,15 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)
71{ 80{
72 struct b43legacy_wldev *dev = data; 81 struct b43legacy_wldev *dev = data;
73 struct b43legacy_wl *wl = dev->wl; 82 struct b43legacy_wl *wl = dev->wl;
74 int err = 0; 83 int err = -EBUSY;
75 84
76 if (!wl->rfkill.registered) 85 if (!wl->rfkill.registered)
77 return 0; 86 return 0;
78 87
79 mutex_lock(&wl->mutex); 88 mutex_lock(&wl->mutex);
80 B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); 89 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)
90 goto out_unlock;
91 err = 0;
81 switch (state) { 92 switch (state) {
82 case RFKILL_STATE_ON: 93 case RFKILL_STATE_ON:
83 if (!dev->radio_hw_enable) { 94 if (!dev->radio_hw_enable) {
@@ -103,11 +114,11 @@ out_unlock:
103 114
104char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) 115char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)
105{ 116{
106 struct b43legacy_wl *wl = dev->wl; 117 struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
107 118
108 if (!wl->rfkill.rfkill) 119 if (!rfk->registered)
109 return NULL; 120 return NULL;
110 return rfkill_get_led_name(wl->rfkill.rfkill); 121 return rfkill_get_led_name(rfk->rfkill);
111} 122}
112 123
113void b43legacy_rfkill_init(struct b43legacy_wldev *dev) 124void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
@@ -116,53 +127,13 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev)
116 struct b43legacy_rfkill *rfk = &(wl->rfkill); 127 struct b43legacy_rfkill *rfk = &(wl->rfkill);
117 int err; 128 int err;
118 129
119 if (rfk->rfkill) { 130 rfk->registered = 0;
120 err = rfkill_register(rfk->rfkill);
121 if (err) {
122 b43legacywarn(wl, "Failed to register RF-kill button\n");
123 goto err_free_rfk;
124 }
125 }
126 if (rfk->poll_dev) {
127 err = input_register_polled_device(rfk->poll_dev);
128 if (err) {
129 b43legacywarn(wl, "Failed to register RF-kill polldev\n");
130 goto err_free_polldev;
131 }
132 }
133
134 return;
135err_free_rfk:
136 rfkill_free(rfk->rfkill);
137 rfk->rfkill = NULL;
138err_free_polldev:
139 input_free_polled_device(rfk->poll_dev);
140 rfk->poll_dev = NULL;
141}
142
143void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
144{
145 struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
146
147 if (rfk->poll_dev)
148 input_unregister_polled_device(rfk->poll_dev);
149 if (rfk->rfkill)
150 rfkill_unregister(rfk->rfkill);
151}
152
153void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev)
154{
155 struct b43legacy_wl *wl = dev->wl;
156 struct b43legacy_rfkill *rfk = &(wl->rfkill);
157 131
132 rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
133 if (!rfk->rfkill)
134 goto out_error;
158 snprintf(rfk->name, sizeof(rfk->name), 135 snprintf(rfk->name, sizeof(rfk->name),
159 "b43legacy-%s", wiphy_name(wl->hw->wiphy)); 136 "b43legacy-%s", wiphy_name(wl->hw->wiphy));
160
161 rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
162 if (!rfk->rfkill) {
163 b43legacywarn(wl, "Failed to allocate RF-kill button\n");
164 return;
165 }
166 rfk->rfkill->name = rfk->name; 137 rfk->rfkill->name = rfk->name;
167 rfk->rfkill->state = RFKILL_STATE_ON; 138 rfk->rfkill->state = RFKILL_STATE_ON;
168 rfk->rfkill->data = dev; 139 rfk->rfkill->data = dev;
@@ -170,20 +141,64 @@ void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev)
170 rfk->rfkill->user_claim_unsupported = 1; 141 rfk->rfkill->user_claim_unsupported = 1;
171 142
172 rfk->poll_dev = input_allocate_polled_device(); 143 rfk->poll_dev = input_allocate_polled_device();
173 if (rfk->poll_dev) { 144 if (!rfk->poll_dev)
174 rfk->poll_dev->private = dev; 145 goto err_free_rfk;
175 rfk->poll_dev->poll = b43legacy_rfkill_poll; 146 rfk->poll_dev->private = dev;
176 rfk->poll_dev->poll_interval = 1000; /* msecs */ 147 rfk->poll_dev->poll = b43legacy_rfkill_poll;
177 } else 148 rfk->poll_dev->poll_interval = 1000; /* msecs */
178 b43legacywarn(wl, "Failed to allocate RF-kill polldev\n"); 149
150 rfk->poll_dev->input->name = rfk->name;
151 rfk->poll_dev->input->id.bustype = BUS_HOST;
152 rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor;
153 rfk->poll_dev->input->evbit[0] = BIT(EV_KEY);
154 set_bit(KEY_WLAN, rfk->poll_dev->input->keybit);
155
156 err = rfkill_register(rfk->rfkill);
157 if (err)
158 goto err_free_polldev;
159
160#ifdef CONFIG_RFKILL_INPUT_MODULE
161 /* B43legacy RF-kill isn't useful without the rfkill-input subsystem.
162 * Try to load the module. */
163 err = request_module("rfkill-input");
164 if (err)
165 b43legacywarn(wl, "Failed to load the rfkill-input module."
166 "The built-in radio LED will not work.\n");
167#endif /* CONFIG_RFKILL_INPUT */
168
169 err = input_register_polled_device(rfk->poll_dev);
170 if (err)
171 goto err_unreg_rfk;
172
173 rfk->registered = 1;
174
175 return;
176err_unreg_rfk:
177 rfkill_unregister(rfk->rfkill);
178err_free_polldev:
179 input_free_polled_device(rfk->poll_dev);
180 rfk->poll_dev = NULL;
181err_free_rfk:
182 rfkill_free(rfk->rfkill);
183 rfk->rfkill = NULL;
184out_error:
185 rfk->registered = 0;
186 b43legacywarn(wl, "RF-kill button init failed\n");
179} 187}
180 188
181void b43legacy_rfkill_free(struct b43legacy_wldev *dev) 189void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)
182{ 190{
183 struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); 191 struct b43legacy_rfkill *rfk = &(dev->wl->rfkill);
184 192
193 if (!rfk->registered)
194 return;
195 rfk->registered = 0;
196
197 input_unregister_polled_device(rfk->poll_dev);
198 rfkill_unregister(rfk->rfkill);
185 input_free_polled_device(rfk->poll_dev); 199 input_free_polled_device(rfk->poll_dev);
186 rfk->poll_dev = NULL; 200 rfk->poll_dev = NULL;
187 rfkill_free(rfk->rfkill); 201 rfkill_free(rfk->rfkill);
188 rfk->rfkill = NULL; 202 rfk->rfkill = NULL;
189} 203}
204