Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

b43legacy: rewrite and fix rfkill initialization

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.

The patch to b43 by Michael Buesch <mb@bu3sch.de> has been ported to
b43legacy.

Signed-off-by: Stefano Brivio <stefano.brivio@polimi.it>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Stefano Brivio and committed by
David S. Miller
db9683fb 33a3dc93

+14 -12
-2
drivers/net/wireless/b43legacy/main.c
··· 3384 3384 3385 3385 static void b43legacy_wireless_core_detach(struct b43legacy_wldev *dev) 3386 3386 { 3387 - b43legacy_rfkill_free(dev); 3388 3387 /* We release firmware that late to not be required to re-request 3389 3388 * is all the time when we reinit the core. */ 3390 3389 b43legacy_release_firmware(dev); ··· 3465 3466 if (!wl->current_dev) 3466 3467 wl->current_dev = dev; 3467 3468 INIT_WORK(&dev->restart_work, b43legacy_chip_reset); 3468 - b43legacy_rfkill_alloc(dev); 3469 3469 3470 3470 b43legacy_radio_turn_off(dev, 1); 3471 3471 b43legacy_switch_analog(dev, 0);
+10 -6
drivers/net/wireless/b43legacy/rfkill.c
··· 48 48 struct b43legacy_wldev *dev = poll_dev->private; 49 49 struct b43legacy_wl *wl = dev->wl; 50 50 bool enabled; 51 + bool report_change = 0; 51 52 52 53 mutex_lock(&wl->mutex); 53 54 B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); 54 55 enabled = b43legacy_is_hw_radio_enabled(dev); 55 56 if (unlikely(enabled != dev->radio_hw_enable)) { 56 57 dev->radio_hw_enable = enabled; 58 + report_change = 1; 57 59 b43legacyinfo(wl, "Radio hardware status changed to %s\n", 58 60 enabled ? "ENABLED" : "DISABLED"); 59 - mutex_unlock(&wl->mutex); 61 + } 62 + mutex_unlock(&wl->mutex); 63 + 64 + if (unlikely(report_change)) 60 65 input_report_key(poll_dev->input, KEY_WLAN, enabled); 61 - } else 62 - mutex_unlock(&wl->mutex); 63 66 } 64 67 65 68 /* Called when the RFKILL toggled in software. ··· 73 70 struct b43legacy_wl *wl = dev->wl; 74 71 int err = 0; 75 72 76 - mutex_lock(&wl->mutex); 77 - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) 78 - goto out_unlock; 73 + if (!wl->rfkill.registered) 74 + return 0; 79 75 76 + mutex_lock(&wl->mutex); 77 + B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); 80 78 switch (state) { 81 79 case RFKILL_STATE_ON: 82 80 if (!dev->radio_hw_enable) {
+4 -4
drivers/net/wireless/b43legacy/rfkill.h
··· 16 16 struct rfkill *rfkill; 17 17 /* The poll device for the RFKILL input button */ 18 18 struct input_polled_dev *poll_dev; 19 + /* Did initialization succeed? Used for freeing. */ 20 + bool registered; 19 21 /* The unique name of this rfkill switch */ 20 - char name[32]; 22 + char name[sizeof("b43legacy-phy4294967295")]; 21 23 }; 22 24 23 - /* All the init functions return void, because we are not interested 25 + /* The init function returns void, because we are not interested 24 26 * in failing the b43 init process when rfkill init failed. */ 25 - void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev); 26 - void b43legacy_rfkill_free(struct b43legacy_wldev *dev); 27 27 void b43legacy_rfkill_init(struct b43legacy_wldev *dev); 28 28 void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); 29 29