diff options
| -rw-r--r-- | drivers/net/wireless/b43legacy/leds.c | 4 | ||||
| -rw-r--r-- | drivers/net/wireless/b43legacy/main.c | 20 | ||||
| -rw-r--r-- | drivers/net/wireless/b43legacy/rfkill.c | 133 | 
3 files changed, 88 insertions, 69 deletions
diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index f0affb78100..cacb786d971 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,  		b43legacy_register_led(dev, &dev->led_radio, name,  				 b43legacy_rfkill_led_name(dev),  				 led_index, activelow); +		/* Sync the RF-kill LED state with the switch state. */ +		if (dev->radio_hw_enable) +			b43legacy_led_turn_on(dev, led_index, activelow);  		break;  	case B43legacy_LED_WEIRD:  	case B43legacy_LED_ASSOC: @@ -234,4 +237,5 @@ void b43legacy_leds_exit(struct b43legacy_wldev *dev)  	b43legacy_unregister_led(&dev->led_tx);  	b43legacy_unregister_led(&dev->led_rx);  	b43legacy_unregister_led(&dev->led_assoc); +	b43legacy_unregister_led(&dev->led_radio);  } diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index aa723effcf2..14087fc20f3 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,  static void b43legacy_chip_exit(struct b43legacy_wldev *dev)  {  	b43legacy_radio_turn_off(dev, 1); -	b43legacy_leds_exit(dev);  	b43legacy_gpio_cleanup(dev);  	/* firmware is released later */  } @@ -2025,11 +2024,10 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)  	err = b43legacy_gpio_init(dev);  	if (err)  		goto out; /* firmware is released later */ -	b43legacy_leds_init(dev);  	err = b43legacy_upload_initvals(dev);  	if (err) -		goto err_leds_exit; +		goto err_gpio_clean;  	b43legacy_radio_turn_on(dev);  	b43legacy_write16(dev, 0x03E6, 0x0000); @@ -2111,8 +2109,7 @@ out:  err_radio_off:  	b43legacy_radio_turn_off(dev, 1); -err_leds_exit: -	b43legacy_leds_exit(dev); +err_gpio_clean:  	b43legacy_gpio_cleanup(dev);  	goto out;  } @@ -2969,10 +2966,7 @@ static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev)  	cancel_work_sync(&dev->restart_work);  	mutex_lock(&wl->mutex); -	mutex_unlock(&dev->wl->mutex); -	b43legacy_rfkill_exit(dev); -	mutex_lock(&dev->wl->mutex); - +	b43legacy_leds_exit(dev);  	b43legacy_rng_exit(dev->wl);  	b43legacy_pio_free(dev);  	b43legacy_dma_free(dev); @@ -3138,11 +3132,11 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)  	memset(wl->mac_addr, 0, ETH_ALEN);  	b43legacy_upload_card_macaddress(dev);  	b43legacy_security_init(dev); -	b43legacy_rfkill_init(dev);  	b43legacy_rng_init(wl);  	b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED); +	b43legacy_leds_init(dev);  out:  	return err; @@ -3231,6 +3225,10 @@ static int b43legacy_op_start(struct ieee80211_hw *hw)  	int did_init = 0;  	int err = 0; +	/* First register RFkill. +	 * LEDs that are registered later depend on it. */ +	b43legacy_rfkill_init(dev); +  	mutex_lock(&wl->mutex);  	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { @@ -3260,6 +3258,8 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw)  	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);  	struct b43legacy_wldev *dev = wl->current_dev; +	b43legacy_rfkill_exit(dev); +  	mutex_lock(&wl->mutex);  	if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)  		b43legacy_wireless_core_stop(dev); diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index b9d38a4f286..520910fd5c4 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -26,6 +26,8 @@  #include "radio.h"  #include "b43legacy.h" +#include <linux/kmod.h> +  /* Returns TRUE, if the radio is enabled in hardware. */  static 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)  	bool report_change = 0;  	mutex_lock(&wl->mutex); -	B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); +	if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { +		mutex_unlock(&wl->mutex); +		return; +	}  	enabled = b43legacy_is_hw_radio_enabled(dev);  	if (unlikely(enabled != dev->radio_hw_enable)) {  		dev->radio_hw_enable = enabled; @@ -61,8 +66,12 @@ static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev)  	}  	mutex_unlock(&wl->mutex); -	if (unlikely(report_change)) -		input_report_key(poll_dev->input, KEY_WLAN, enabled); +	/* send the radio switch event to the system - note both a key press +	 * and a release are required */ +	if (unlikely(report_change)) { +		input_report_key(poll_dev->input, KEY_WLAN, 1); +		input_report_key(poll_dev->input, KEY_WLAN, 0); +	}  }  /* Called when the RFKILL toggled in software. @@ -71,13 +80,15 @@ static int b43legacy_rfkill_soft_toggle(void *data, enum rfkill_state state)  {  	struct b43legacy_wldev *dev = data;  	struct b43legacy_wl *wl = dev->wl; -	int err = 0; +	int err = -EBUSY;  	if (!wl->rfkill.registered)  		return 0;  	mutex_lock(&wl->mutex); -	B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); +	if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) +		goto out_unlock; +	err = 0;  	switch (state) {  	case RFKILL_STATE_ON:  		if (!dev->radio_hw_enable) { @@ -103,11 +114,11 @@ out_unlock:  char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev)  { -	struct b43legacy_wl *wl = dev->wl; +	struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); -	if (!wl->rfkill.rfkill) +	if (!rfk->registered)  		return NULL; -	return rfkill_get_led_name(wl->rfkill.rfkill); +	return rfkill_get_led_name(rfk->rfkill);  }  void b43legacy_rfkill_init(struct b43legacy_wldev *dev) @@ -116,53 +127,13 @@ void b43legacy_rfkill_init(struct b43legacy_wldev *dev)  	struct b43legacy_rfkill *rfk = &(wl->rfkill);  	int err; -	if (rfk->rfkill) { -		err = rfkill_register(rfk->rfkill); -		if (err) { -			b43legacywarn(wl, "Failed to register RF-kill button\n"); -			goto err_free_rfk; -		} -	} -	if (rfk->poll_dev) { -		err = input_register_polled_device(rfk->poll_dev); -		if (err) { -			b43legacywarn(wl, "Failed to register RF-kill polldev\n"); -			goto err_free_polldev; -		} -	} - -	return; -err_free_rfk: -	rfkill_free(rfk->rfkill); -	rfk->rfkill = NULL; -err_free_polldev: -	input_free_polled_device(rfk->poll_dev); -	rfk->poll_dev = NULL; -} - -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) -{ -	struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - -	if (rfk->poll_dev) -		input_unregister_polled_device(rfk->poll_dev); -	if (rfk->rfkill) -		rfkill_unregister(rfk->rfkill); -} - -void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) -{ -	struct b43legacy_wl *wl = dev->wl; -	struct b43legacy_rfkill *rfk = &(wl->rfkill); +	rfk->registered = 0; +	rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); +	if (!rfk->rfkill) +		goto out_error;  	snprintf(rfk->name, sizeof(rfk->name),  		 "b43legacy-%s", wiphy_name(wl->hw->wiphy)); - -	rfk->rfkill = rfkill_allocate(dev->dev->dev, RFKILL_TYPE_WLAN); -	if (!rfk->rfkill) { -		b43legacywarn(wl, "Failed to allocate RF-kill button\n"); -		return; -	}  	rfk->rfkill->name = rfk->name;  	rfk->rfkill->state = RFKILL_STATE_ON;  	rfk->rfkill->data = dev; @@ -170,20 +141,64 @@ void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev)  	rfk->rfkill->user_claim_unsupported = 1;  	rfk->poll_dev = input_allocate_polled_device(); -	if (rfk->poll_dev) { -		rfk->poll_dev->private = dev; -		rfk->poll_dev->poll = b43legacy_rfkill_poll; -		rfk->poll_dev->poll_interval = 1000; /* msecs */ -	} else -		b43legacywarn(wl, "Failed to allocate RF-kill polldev\n"); +	if (!rfk->poll_dev) +		goto err_free_rfk; +	rfk->poll_dev->private = dev; +	rfk->poll_dev->poll = b43legacy_rfkill_poll; +	rfk->poll_dev->poll_interval = 1000; /* msecs */ + +	rfk->poll_dev->input->name = rfk->name; +	rfk->poll_dev->input->id.bustype = BUS_HOST; +	rfk->poll_dev->input->id.vendor = dev->dev->bus->boardinfo.vendor; +	rfk->poll_dev->input->evbit[0] = BIT(EV_KEY); +	set_bit(KEY_WLAN, rfk->poll_dev->input->keybit); + +	err = rfkill_register(rfk->rfkill); +	if (err) +		goto err_free_polldev; + +#ifdef CONFIG_RFKILL_INPUT_MODULE +	/* B43legacy RF-kill isn't useful without the rfkill-input subsystem. +	 * Try to load the module. */ +	err = request_module("rfkill-input"); +	if (err) +		b43legacywarn(wl, "Failed to load the rfkill-input module." +			"The built-in radio LED will not work.\n"); +#endif /* CONFIG_RFKILL_INPUT */ + +	err = input_register_polled_device(rfk->poll_dev); +	if (err) +		goto err_unreg_rfk; + +	rfk->registered = 1; + +	return; +err_unreg_rfk: +	rfkill_unregister(rfk->rfkill); +err_free_polldev: +	input_free_polled_device(rfk->poll_dev); +	rfk->poll_dev = NULL; +err_free_rfk: +	rfkill_free(rfk->rfkill); +	rfk->rfkill = NULL; +out_error: +	rfk->registered = 0; +	b43legacywarn(wl, "RF-kill button init failed\n");  } -void b43legacy_rfkill_free(struct b43legacy_wldev *dev) +void b43legacy_rfkill_exit(struct b43legacy_wldev *dev)  {  	struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); +	if (!rfk->registered) +		return; +	rfk->registered = 0; + +	input_unregister_polled_device(rfk->poll_dev); +	rfkill_unregister(rfk->rfkill);  	input_free_polled_device(rfk->poll_dev);  	rfk->poll_dev = NULL;  	rfkill_free(rfk->rfkill);  	rfk->rfkill = NULL;  } +  |