diff options
author | Michael Buesch <mb@bu3sch.de> | 2007-11-03 09:34:32 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-11-10 04:25:12 -0500 |
commit | 35c7e6602b81bdacb745f04236a419402777139e (patch) | |
tree | 4ee928ff39b6b6bb09677399b9e1c1772ee445e8 /drivers/net/wireless/b43 | |
parent | 30c4ae42317666f3aeed658cdb8803c84ac6fe77 (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.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/b43/rfkill.c | 119 | ||||
-rw-r--r-- | drivers/net/wireless/b43/rfkill.h | 14 |
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 | ||
3662 | static void b43_wireless_core_detach(struct b43_wldev *dev) | 3662 | static 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 | ||
105 | char * b43_rfkill_led_name(struct b43_wldev *dev) | 101 | char * 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 | ||
114 | void b43_rfkill_init(struct b43_wldev *dev) | 110 | void 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; | ||
136 | err_free_rfk: | ||
137 | rfkill_free(rfk->rfkill); | ||
138 | rfk->rfkill = NULL; | ||
139 | err_free_polldev: | ||
140 | input_free_polled_device(rfk->poll_dev); | ||
141 | rfk->poll_dev = NULL; | ||
142 | } | ||
143 | |||
144 | void 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 | |||
154 | void 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; | ||
146 | err_unreg_rfk: | ||
147 | rfkill_unregister(rfk->rfkill); | ||
148 | err_free_polldev: | ||
149 | input_free_polled_device(rfk->poll_dev); | ||
150 | rfk->poll_dev = NULL; | ||
151 | err_free_rfk: | ||
152 | rfkill_free(rfk->rfkill); | ||
153 | rfk->rfkill = NULL; | ||
154 | out_error: | ||
155 | rfk->registered = 0; | ||
156 | b43warn(wl, "RF-kill button init failed\n"); | ||
180 | } | 157 | } |
181 | 158 | ||
182 | void b43_rfkill_free(struct b43_wldev *dev) | 159 | void 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. */ |
24 | void b43_rfkill_alloc(struct b43_wldev *dev); | ||
25 | void b43_rfkill_free(struct b43_wldev *dev); | ||
26 | void b43_rfkill_init(struct b43_wldev *dev); | 26 | void b43_rfkill_init(struct b43_wldev *dev); |
27 | void b43_rfkill_exit(struct b43_wldev *dev); | 27 | void b43_rfkill_exit(struct b43_wldev *dev); |
28 | 28 | ||
@@ -36,12 +36,6 @@ struct b43_rfkill { | |||
36 | /* empty */ | 36 | /* empty */ |
37 | }; | 37 | }; |
38 | 38 | ||
39 | static inline void b43_rfkill_alloc(struct b43_wldev *dev) | ||
40 | { | ||
41 | } | ||
42 | static inline void b43_rfkill_free(struct b43_wldev *dev) | ||
43 | { | ||
44 | } | ||
45 | static inline void b43_rfkill_init(struct b43_wldev *dev) | 39 | static inline void b43_rfkill_init(struct b43_wldev *dev) |
46 | { | 40 | { |
47 | } | 41 | } |