aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2007-11-03 09:34:32 -0400
committerJeff Garzik <jeff@garzik.org>2007-11-10 04:25:12 -0500
commit35c7e6602b81bdacb745f04236a419402777139e (patch)
tree4ee928ff39b6b6bb09677399b9e1c1772ee445e8 /drivers/net/wireless/b43
parent30c4ae42317666f3aeed658cdb8803c84ac6fe77 (diff)
b43: Rewrite and fix rfkill init
The rfkill subsystem doesn't like code like that rfkill_allocate(); rfkill_register(); rfkill_unregister(); rfkill_register(); /* <- This will crash */ This sequence happens with modprobe b43 ifconfig wlanX up ifconfig wlanX down ifconfig wlanX up Fix this by always re-allocating the rfkill stuff before register. Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43')
-rw-r--r--drivers/net/wireless/b43/main.c2
-rw-r--r--drivers/net/wireless/b43/rfkill.c119
-rw-r--r--drivers/net/wireless/b43/rfkill.h14
3 files changed, 55 insertions, 80 deletions
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 5058e60e5703..c9778c6cf2e8 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3661,7 +3661,6 @@ static int b43_setup_modes(struct b43_wldev *dev,
3661 3661
3662static void b43_wireless_core_detach(struct b43_wldev *dev) 3662static void b43_wireless_core_detach(struct b43_wldev *dev)
3663{ 3663{
3664 b43_rfkill_free(dev);
3665 /* We release firmware that late to not be required to re-request 3664 /* We release firmware that late to not be required to re-request
3666 * is all the time when we reinit the core. */ 3665 * is all the time when we reinit the core. */
3667 b43_release_firmware(dev); 3666 b43_release_firmware(dev);
@@ -3747,7 +3746,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
3747 if (!wl->current_dev) 3746 if (!wl->current_dev)
3748 wl->current_dev = dev; 3747 wl->current_dev = dev;
3749 INIT_WORK(&dev->restart_work, b43_chip_reset); 3748 INIT_WORK(&dev->restart_work, b43_chip_reset);
3750 b43_rfkill_alloc(dev);
3751 3749
3752 b43_radio_turn_off(dev, 1); 3750 b43_radio_turn_off(dev, 1);
3753 b43_switch_analog(dev, 0); 3751 b43_switch_analog(dev, 0);
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index 456930ffef2d..9b1f905ffbf4 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -47,18 +47,21 @@ static void b43_rfkill_poll(struct input_polled_dev *poll_dev)
47 struct b43_wldev *dev = poll_dev->private; 47 struct b43_wldev *dev = poll_dev->private;
48 struct b43_wl *wl = dev->wl; 48 struct b43_wl *wl = dev->wl;
49 bool enabled; 49 bool enabled;
50 bool report_change = 0;
50 51
51 mutex_lock(&wl->mutex); 52 mutex_lock(&wl->mutex);
52 B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED); 53 B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
53 enabled = b43_is_hw_radio_enabled(dev); 54 enabled = b43_is_hw_radio_enabled(dev);
54 if (unlikely(enabled != dev->radio_hw_enable)) { 55 if (unlikely(enabled != dev->radio_hw_enable)) {
55 dev->radio_hw_enable = enabled; 56 dev->radio_hw_enable = enabled;
57 report_change = 1;
56 b43info(wl, "Radio hardware status changed to %s\n", 58 b43info(wl, "Radio hardware status changed to %s\n",
57 enabled ? "ENABLED" : "DISABLED"); 59 enabled ? "ENABLED" : "DISABLED");
58 mutex_unlock(&wl->mutex); 60 }
61 mutex_unlock(&wl->mutex);
62
63 if (unlikely(report_change))
59 input_report_key(poll_dev->input, KEY_WLAN, enabled); 64 input_report_key(poll_dev->input, KEY_WLAN, enabled);
60 } else
61 mutex_unlock(&wl->mutex);
62} 65}
63 66
64/* Called when the RFKILL toggled in software. */ 67/* Called when the RFKILL toggled in software. */
@@ -68,18 +71,11 @@ static int b43_rfkill_soft_toggle(void *data, enum rfkill_state state)
68 struct b43_wl *wl = dev->wl; 71 struct b43_wl *wl = dev->wl;
69 int err = 0; 72 int err = 0;
70 73
71 /* When RFKILL is registered, it will call back into this callback. 74 if (!wl->rfkill.registered)
72 * wl->mutex will already be locked when this happens. 75 return 0;
73 * So first trylock. On contention check if we are in initialization.
74 * Silently return if that happens to avoid a deadlock. */
75 if (mutex_trylock(&wl->mutex) == 0) {
76 if (b43_status(dev) < B43_STAT_INITIALIZED)
77 return 0;
78 mutex_lock(&wl->mutex);
79 }
80 if (b43_status(dev) < B43_STAT_INITIALIZED)
81 goto out_unlock;
82 76
77 mutex_lock(&wl->mutex);
78 B43_WARN_ON(b43_status(dev) < B43_STAT_INITIALIZED);
83 switch (state) { 79 switch (state) {
84 case RFKILL_STATE_ON: 80 case RFKILL_STATE_ON:
85 if (!dev->radio_hw_enable) { 81 if (!dev->radio_hw_enable) {
@@ -104,11 +100,11 @@ out_unlock:
104 100
105char * b43_rfkill_led_name(struct b43_wldev *dev) 101char * b43_rfkill_led_name(struct b43_wldev *dev)
106{ 102{
107 struct b43_wl *wl = dev->wl; 103 struct b43_rfkill *rfk = &(dev->wl->rfkill);
108 104
109 if (!wl->rfkill.rfkill) 105 if (!rfk->registered)
110 return NULL; 106 return NULL;
111 return rfkill_get_led_name(wl->rfkill.rfkill); 107 return rfkill_get_led_name(rfk->rfkill);
112} 108}
113 109
114void b43_rfkill_init(struct b43_wldev *dev) 110void b43_rfkill_init(struct b43_wldev *dev)
@@ -117,53 +113,13 @@ void b43_rfkill_init(struct b43_wldev *dev)
117 struct b43_rfkill *rfk = &(wl->rfkill); 113 struct b43_rfkill *rfk = &(wl->rfkill);
118 int err; 114 int err;
119 115
120 if (rfk->rfkill) { 116 rfk->registered = 0;
121 err = rfkill_register(rfk->rfkill);
122 if (err) {
123 b43warn(wl, "Failed to register RF-kill button\n");
124 goto err_free_rfk;
125 }
126 }
127 if (rfk->poll_dev) {
128 err = input_register_polled_device(rfk->poll_dev);
129 if (err) {
130 b43warn(wl, "Failed to register RF-kill polldev\n");
131 goto err_free_polldev;
132 }
133 }
134
135 return;
136err_free_rfk:
137 rfkill_free(rfk->rfkill);
138 rfk->rfkill = NULL;
139err_free_polldev:
140 input_free_polled_device(rfk->poll_dev);
141 rfk->poll_dev = NULL;
142}
143
144void b43_rfkill_exit(struct b43_wldev *dev)
145{
146 struct b43_rfkill *rfk = &(dev->wl->rfkill);
147
148 if (rfk->poll_dev)
149 input_unregister_polled_device(rfk->poll_dev);
150 if (rfk->rfkill)
151 rfkill_unregister(rfk->rfkill);
152}
153
154void b43_rfkill_alloc(struct b43_wldev *dev)
155{
156 struct b43_wl *wl = dev->wl;
157 struct b43_rfkill *rfk = &(wl->rfkill);
158 117
118 rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
119 if (!rfk->rfkill)
120 goto out_error;
159 snprintf(rfk->name, sizeof(rfk->name), 121 snprintf(rfk->name, sizeof(rfk->name),
160 "b43-%s", wiphy_name(wl->hw->wiphy)); 122 "b43-%s", wiphy_name(wl->hw->wiphy));
161
162 rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN);
163 if (!rfk->rfkill) {
164 b43warn(wl, "Failed to allocate RF-kill button\n");
165 return;
166 }
167 rfk->rfkill->name = rfk->name; 123 rfk->rfkill->name = rfk->name;
168 rfk->rfkill->state = RFKILL_STATE_ON; 124 rfk->rfkill->state = RFKILL_STATE_ON;
169 rfk->rfkill->data = dev; 125 rfk->rfkill->data = dev;
@@ -171,18 +127,45 @@ void b43_rfkill_alloc(struct b43_wldev *dev)
171 rfk->rfkill->user_claim_unsupported = 1; 127 rfk->rfkill->user_claim_unsupported = 1;
172 128
173 rfk->poll_dev = input_allocate_polled_device(); 129 rfk->poll_dev = input_allocate_polled_device();
174 if (rfk->poll_dev) { 130 if (!rfk->poll_dev)
175 rfk->poll_dev->private = dev; 131 goto err_free_rfk;
176 rfk->poll_dev->poll = b43_rfkill_poll; 132 rfk->poll_dev->private = dev;
177 rfk->poll_dev->poll_interval = 1000; /* msecs */ 133 rfk->poll_dev->poll = b43_rfkill_poll;
178 } else 134 rfk->poll_dev->poll_interval = 1000; /* msecs */
179 b43warn(wl, "Failed to allocate RF-kill polldev\n"); 135
136 err = rfkill_register(rfk->rfkill);
137 if (err)
138 goto err_free_polldev;
139 err = input_register_polled_device(rfk->poll_dev);
140 if (err)
141 goto err_unreg_rfk;
142
143 rfk->registered = 1;
144
145 return;
146err_unreg_rfk:
147 rfkill_unregister(rfk->rfkill);
148err_free_polldev:
149 input_free_polled_device(rfk->poll_dev);
150 rfk->poll_dev = NULL;
151err_free_rfk:
152 rfkill_free(rfk->rfkill);
153 rfk->rfkill = NULL;
154out_error:
155 rfk->registered = 0;
156 b43warn(wl, "RF-kill button init failed\n");
180} 157}
181 158
182void b43_rfkill_free(struct b43_wldev *dev) 159void b43_rfkill_exit(struct b43_wldev *dev)
183{ 160{
184 struct b43_rfkill *rfk = &(dev->wl->rfkill); 161 struct b43_rfkill *rfk = &(dev->wl->rfkill);
185 162
163 if (!rfk->registered)
164 return;
165 rfk->registered = 0;
166
167 input_unregister_polled_device(rfk->poll_dev);
168 rfkill_unregister(rfk->rfkill);
186 input_free_polled_device(rfk->poll_dev); 169 input_free_polled_device(rfk->poll_dev);
187 rfk->poll_dev = NULL; 170 rfk->poll_dev = NULL;
188 rfkill_free(rfk->rfkill); 171 rfkill_free(rfk->rfkill);
diff --git a/drivers/net/wireless/b43/rfkill.h b/drivers/net/wireless/b43/rfkill.h
index 29544e8c9e5f..adacf936d815 100644
--- a/drivers/net/wireless/b43/rfkill.h
+++ b/drivers/net/wireless/b43/rfkill.h
@@ -15,14 +15,14 @@ struct b43_rfkill {
15 struct rfkill *rfkill; 15 struct rfkill *rfkill;
16 /* The poll device for the RFKILL input button */ 16 /* The poll device for the RFKILL input button */
17 struct input_polled_dev *poll_dev; 17 struct input_polled_dev *poll_dev;
18 /* Did initialization succeed? Used for freeing. */
19 bool registered;
18 /* The unique name of this rfkill switch */ 20 /* The unique name of this rfkill switch */
19 char name[32]; 21 char name[sizeof("b43-phy4294967295")];
20}; 22};
21 23
22/* All the init functions return void, because we are not interested 24/* The init function returns void, because we are not interested
23 * in failing the b43 init process when rfkill init failed. */ 25 * in failing the b43 init process when rfkill init failed. */
24void b43_rfkill_alloc(struct b43_wldev *dev);
25void b43_rfkill_free(struct b43_wldev *dev);
26void b43_rfkill_init(struct b43_wldev *dev); 26void b43_rfkill_init(struct b43_wldev *dev);
27void b43_rfkill_exit(struct b43_wldev *dev); 27void b43_rfkill_exit(struct b43_wldev *dev);
28 28
@@ -36,12 +36,6 @@ struct b43_rfkill {
36 /* empty */ 36 /* empty */
37}; 37};
38 38
39static inline void b43_rfkill_alloc(struct b43_wldev *dev)
40{
41}
42static inline void b43_rfkill_free(struct b43_wldev *dev)
43{
44}
45static inline void b43_rfkill_init(struct b43_wldev *dev) 39static inline void b43_rfkill_init(struct b43_wldev *dev)
46{ 40{
47} 41}