aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/net/wireless/b43legacy/leds.c4
-rw-r--r--drivers/net/wireless/b43legacy/main.c20
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c133
3 files changed, 88 insertions, 69 deletions
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c
index f0affb781002..cacb786d9713 100644
--- a/drivers/net/wireless/b43legacy/leds.c
+++ b/drivers/net/wireless/b43legacy/leds.c
@@ -165,6 +165,9 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev,
165 b43legacy_register_led(dev, &dev->led_radio, name, 165 b43legacy_register_led(dev, &dev->led_radio, name,
166 b43legacy_rfkill_led_name(dev), 166 b43legacy_rfkill_led_name(dev),
167 led_index, activelow); 167 led_index, activelow);
168 /* Sync the RF-kill LED state with the switch state. */
169 if (dev->radio_hw_enable)
170 b43legacy_led_turn_on(dev, led_index, activelow);
168 break; 171 break;
169 case B43legacy_LED_WEIRD: 172 case B43legacy_LED_WEIRD:
170 case B43legacy_LED_ASSOC: 173 case B43legacy_LED_ASSOC:
@@ -234,4 +237,5 @@ void b43legacy_leds_exit(struct b43legacy_wldev *dev)
234 b43legacy_unregister_led(&dev->led_tx); 237 b43legacy_unregister_led(&dev->led_tx);
235 b43legacy_unregister_led(&dev->led_rx); 238 b43legacy_unregister_led(&dev->led_rx);
236 b43legacy_unregister_led(&dev->led_assoc); 239 b43legacy_unregister_led(&dev->led_assoc);
240 b43legacy_unregister_led(&dev->led_radio);
237} 241}
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index aa723effcf22..14087fc20f3a 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1995,7 +1995,6 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev,
1995static void b43legacy_chip_exit(struct b43legacy_wldev *dev) 1995static void b43legacy_chip_exit(struct b43legacy_wldev *dev)
1996{ 1996{
1997 b43legacy_radio_turn_off(dev, 1); 1997 b43legacy_radio_turn_off(dev, 1);
1998 b43legacy_leds_exit(dev);
1999 b43legacy_gpio_cleanup(dev); 1998 b43legacy_gpio_cleanup(dev);
2000 /* firmware is released later */ 1999 /* firmware is released later */
2001} 2000}
@@ -2025,11 +2024,10 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
2025 err = b43legacy_gpio_init(dev); 2024 err = b43legacy_gpio_init(dev);
2026 if (err) 2025 if (err)
2027 goto out; /* firmware is released later */ 2026 goto out; /* firmware is released later */
2028 b43legacy_leds_init(dev);
2029 2027
2030 err = b43legacy_upload_initvals(dev); 2028 err = b43legacy_upload_initvals(dev);
2031 if (err) 2029 if (err)
2032 goto err_leds_exit; 2030 goto err_gpio_clean;
2033 b43legacy_radio_turn_on(dev); 2031 b43legacy_radio_turn_on(dev);
2034 2032
2035 b43legacy_write16(dev, 0x03E6, 0x0000); 2033 b43legacy_write16(dev, 0x03E6, 0x0000);
@@ -2111,8 +2109,7 @@ out:
2111 2109
2112err_radio_off: 2110err_radio_off:
2113 b43legacy_radio_turn_off(dev, 1); 2111 b43legacy_radio_turn_off(dev, 1);
2114err_leds_exit: 2112err_gpio_clean:
2115 b43legacy_leds_exit(dev);
2116 b43legacy_gpio_cleanup(dev); 2113 b43legacy_gpio_cleanup(dev);
2117 goto out; 2114 goto out;
2118} 2115}
@@ -2969,10 +2966,7 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)
2969 cancel_work_sync(&dev->restart_work); 2966 cancel_work_sync(&dev->restart_work);
2970 mutex_lock(&wl->mutex); 2967 mutex_lock(&wl->mutex);
2971 2968
2972 mutex_unlock(&dev->wl->mutex); 2969 b43legacy_leds_exit(dev);
2973 b43legacy_rfkill_exit(dev);
2974 mutex_lock(&dev->wl->mutex);
2975
2976 b43legacy_rng_exit(dev->wl); 2970 b43legacy_rng_exit(dev->wl);
2977 b43legacy_pio_free(dev); 2971 b43legacy_pio_free(dev);
2978 b43legacy_dma_free(dev); 2972 b43legacy_dma_free(dev);
@@ -3138,11 +3132,11 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
3138 memset(wl->mac_addr, 0, ETH_ALEN); 3132 memset(wl->mac_addr, 0, ETH_ALEN);
3139 b43legacy_upload_card_macaddress(dev); 3133 b43legacy_upload_card_macaddress(dev);
3140 b43legacy_security_init(dev); 3134 b43legacy_security_init(dev);
3141 b43legacy_rfkill_init(dev);
3142 b43legacy_rng_init(wl); 3135 b43legacy_rng_init(wl);
3143 3136
3144 b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); 3137 b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
3145 3138
3139 b43legacy_leds_init(dev);
3146out: 3140out:
3147 return err; 3141 return err;
3148 3142
@@ -3231,6 +3225,10 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)
3231 int did_init = 0; 3225 int did_init = 0;
3232 int err = 0; 3226 int err = 0;
3233 3227
3228 /* First register RFkill.
3229 * LEDs that are registered later depend on it. */
3230 b43legacy_rfkill_init(dev);
3231
3234 mutex_lock(&wl->mutex); 3232 mutex_lock(&wl->mutex);
3235 3233
3236 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { 3234 if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
@@ -3260,6 +3258,8 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)
3260 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); 3258 struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
3261 struct b43legacy_wldev *dev = wl->current_dev; 3259 struct b43legacy_wldev *dev = wl->current_dev;
3262 3260
3261 b43legacy_rfkill_exit(dev);
3262
3263 mutex_lock(&wl->mutex); 3263 mutex_lock(&wl->mutex);
3264 if (b43legacy_status(dev) >= B43legacy_STAT_STARTED) 3264 if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
3265 b43legacy_wireless_core_stop(dev); 3265 b43legacy_wireless_core_stop(dev);
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