From ba48f7bb8062982ec916868cc8c90360aad82e53 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Fri, 12 Oct 2007 23:04:51 -0500 Subject: b43legacy: LED triggers support Drive the LEDs through the generic LED triggers. The patch to b43 by Michael Buesch has been ported to b43legacy. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net/wireless/b43legacy/Kconfig') diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 7e23ec23fc98..1bf777578e5f 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -34,6 +34,12 @@ config B43LEGACY_PCICORE_AUTOSELECT select SSB_DRIVER_PCICORE default y +# LED support +config B43LEGACY_LEDS + bool + depends on MAC80211_LEDS + default y + config B43LEGACY_DEBUG bool "Broadcom 43xx-legacy debugging" depends on B43LEGACY -- cgit v1.2.3 From 93bb7f3a7bb5c95da10242d9763994a466c90b1d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 10 Oct 2007 22:44:22 -0500 Subject: b43legacy: RF-kill support This adds full support for the RFKILL button and the RFKILL LED trigger. This is a port to b43legacy of a patch by Michael Buesch for b43. Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/Kconfig | 8 +- drivers/net/wireless/b43legacy/Makefile | 2 + drivers/net/wireless/b43legacy/b43legacy.h | 5 + drivers/net/wireless/b43legacy/leds.c | 8 +- drivers/net/wireless/b43legacy/main.c | 18 ++-- drivers/net/wireless/b43legacy/radio.c | 13 ++- drivers/net/wireless/b43legacy/radio.h | 2 +- drivers/net/wireless/b43legacy/rfkill.c | 158 +++++++++++++++++++++++++++++ drivers/net/wireless/b43legacy/rfkill.h | 51 ++++++++++ 9 files changed, 250 insertions(+), 15 deletions(-) create mode 100644 drivers/net/wireless/b43legacy/rfkill.c create mode 100644 drivers/net/wireless/b43legacy/rfkill.h (limited to 'drivers/net/wireless/b43legacy/Kconfig') diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 1bf777578e5f..68e05f06b33f 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -37,7 +37,13 @@ config B43LEGACY_PCICORE_AUTOSELECT # LED support config B43LEGACY_LEDS bool - depends on MAC80211_LEDS + depends on B43LEGACY && MAC80211_LEDS + default y + +# RFKILL support +config B43LEGACY_RFKILL + bool + depends on B43LEGACY && RFKILL default y config B43LEGACY_DEBUG diff --git a/drivers/net/wireless/b43legacy/Makefile b/drivers/net/wireless/b43legacy/Makefile index abaa404bb148..80cdb73bd140 100644 --- a/drivers/net/wireless/b43legacy/Makefile +++ b/drivers/net/wireless/b43legacy/Makefile @@ -5,6 +5,8 @@ b43legacy-y += phy.o b43legacy-y += radio.o b43legacy-y += sysfs.o b43legacy-y += xmit.o +# b43 RFKILL button support +b43legacy-$(CONFIG_B43LEGACY_RFKILL) += rfkill.o # b43legacy LED support b43legacy-$(CONFIG_B43LEGACY_LEDS) += leds.o # b43legacy debugging diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 41243ba821ac..fe2af06f5599 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -19,6 +19,7 @@ #include "debugfs.h" #include "leds.h" +#include "rfkill.h" #include "phy.h" @@ -592,6 +593,9 @@ struct b43legacy_wl { u8 rng_initialized; char rng_name[30 + 1]; + /* The RF-kill button */ + struct b43legacy_rfkill rfkill; + /* List of all wireless devices on this chip */ struct list_head devlist; u8 nr_devs; @@ -667,6 +671,7 @@ struct b43legacy_wldev { struct b43legacy_led led_tx; struct b43legacy_led led_rx; struct b43legacy_led led_assoc; + struct b43legacy_led led_radio; /* Reason code of the last interrupt. */ u32 irq_reason; diff --git a/drivers/net/wireless/b43legacy/leds.c b/drivers/net/wireless/b43legacy/leds.c index 1e30919582c5..9ef284fda80e 100644 --- a/drivers/net/wireless/b43legacy/leds.c +++ b/drivers/net/wireless/b43legacy/leds.c @@ -156,12 +156,16 @@ static void b43legacy_map_led(struct b43legacy_wldev *dev, ieee80211_get_rx_led_name(hw), led_index, activelow); break; - /*FIXME: We need another trigger for the "radio-on" LEDs below. - * Wiggle that somehow into the rfkill subsystem. */ case B43legacy_LED_RADIO_ALL: case B43legacy_LED_RADIO_A: case B43legacy_LED_RADIO_B: case B43legacy_LED_MODE_BG: + snprintf(name, sizeof(name), + "b43legacy-%s:radio", wiphy_name(hw->wiphy)); + b43legacy_register_led(dev, &dev->led_radio, name, + b43legacy_rfkill_led_name(dev), + led_index, activelow); + break; case B43legacy_LED_WEIRD: case B43legacy_LED_ASSOC: snprintf(name, sizeof(name), diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 43edd08297a4..04bc3f6c5e63 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1993,7 +1993,7 @@ static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) /* This is the opposite of b43legacy_chip_init() */ static void b43legacy_chip_exit(struct b43legacy_wldev *dev) { - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_leds_exit(dev); b43legacy_gpio_cleanup(dev); /* firmware is released later */ @@ -2106,7 +2106,7 @@ out: return err; err_radio_off: - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); err_leds_exit: b43legacy_leds_exit(dev); b43legacy_gpio_cleanup(dev); @@ -2154,8 +2154,7 @@ static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev) radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { dev->radio_hw_enable = radio_hw_enable; - b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n", - (radio_hw_enable) ? "enabled" : "disabled"); + b43legacy_rfkill_toggled(dev, radio_hw_enable); } } @@ -2647,7 +2646,7 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw, " physically off. Press the" " button to turn it on.\n"); } else { - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 0); b43legacyinfo(dev->wl, "Radio turned off by" " software\n"); } @@ -3034,11 +3033,15 @@ 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_rng_exit(dev->wl); b43legacy_pio_free(dev); b43legacy_dma_free(dev); b43legacy_chip_exit(dev); - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_switch_analog(dev, 0); if (phy->dyn_tssi_tbl) kfree(phy->tssi2dbm); @@ -3206,6 +3209,7 @@ 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); @@ -3527,7 +3531,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43legacy_chip_reset); - b43legacy_radio_turn_off(dev); + b43legacy_radio_turn_off(dev, 1); b43legacy_switch_analog(dev, 0); ssb_device_disable(dev->dev, 0); ssb_bus_may_powerdown(bus); diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index 34cb0d801ce1..1dc351ca883c 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -2115,18 +2115,23 @@ void b43legacy_radio_turn_on(struct b43legacy_wldev *dev) phy->radio_on = 1; } -void b43legacy_radio_turn_off(struct b43legacy_wldev *dev) +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force) { struct b43legacy_phy *phy = &dev->phy; + if (!phy->radio_on && !force) + return; + if (phy->type == B43legacy_PHYTYPE_G && dev->dev->id.revision >= 5) { u16 rfover, rfoverval; rfover = b43legacy_phy_read(dev, B43legacy_PHY_RFOVER); rfoverval = b43legacy_phy_read(dev, B43legacy_PHY_RFOVERVAL); - phy->radio_off_context.rfover = rfover; - phy->radio_off_context.rfoverval = rfoverval; - phy->radio_off_context.valid = 1; + if (!force) { + phy->radio_off_context.rfover = rfover; + phy->radio_off_context.rfoverval = rfoverval; + phy->radio_off_context.valid = 1; + } b43legacy_phy_write(dev, B43legacy_PHY_RFOVER, rfover | 0x008C); b43legacy_phy_write(dev, B43legacy_PHY_RFOVERVAL, rfoverval & 0xFF73); diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h index 6c6a203439e1..ad90d9c03462 100644 --- a/drivers/net/wireless/b43legacy/radio.h +++ b/drivers/net/wireless/b43legacy/radio.h @@ -61,7 +61,7 @@ void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val); u16 b43legacy_radio_init2050(struct b43legacy_wldev *dev); void b43legacy_radio_turn_on(struct b43legacy_wldev *dev); -void b43legacy_radio_turn_off(struct b43legacy_wldev *dev); +void b43legacy_radio_turn_off(struct b43legacy_wldev *dev, bool force); int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev, u8 channel, int synthetic_pu_workaround); diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c new file mode 100644 index 000000000000..db6292642057 --- /dev/null +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -0,0 +1,158 @@ +/* + + Broadcom B43legacy wireless driver + RFKILL support + + Copyright (c) 2007 Michael Buesch + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "rfkill.h" +#include "radio.h" +#include "b43legacy.h" + + +static void b43legacy_notify_rfkill_press(struct work_struct *work) +{ + struct b43legacy_rfkill *rfk = container_of(work, + struct b43legacy_rfkill, + notify_work); + struct b43legacy_wl *wl = container_of(rfk, struct b43legacy_wl, + rfkill); + struct b43legacy_wldev *dev; + enum rfkill_state state; + + mutex_lock(&wl->mutex); + dev = wl->current_dev; + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { + mutex_unlock(&wl->mutex); + return; + } + if (dev->radio_hw_enable) + state = RFKILL_STATE_ON; + else + state = RFKILL_STATE_OFF; + b43legacyinfo(wl, "Radio hardware status changed to %s\n", + dev->radio_hw_enable ? "ENABLED" : "DISABLED"); + mutex_unlock(&wl->mutex); + + if (rfk->rfkill) { + /* Be careful. This calls back into the software toggle + * routines. So we must unlock before calling. */ + rfkill_switch_all(rfk->rfkill->type, state); + } +} + +/* Called when the RFKILL toggled in hardware. + * This is called with the mutex locked. */ +void b43legacy_rfkill_toggled(struct b43legacy_wldev *dev, bool on) +{ + struct b43legacy_wl *wl = dev->wl; + + B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); + /* Update the RF status asynchronously, as rfkill will + * call back into the software toggle handler. + * This would deadlock if done synchronously. */ + queue_work(wl->hw->workqueue, &wl->rfkill.notify_work); +} + +/* Called when the RFKILL toggled in software. + * This is called without locking. */ +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; + + mutex_lock(&wl->mutex); + if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) + goto out_unlock; + + switch (state) { + case RFKILL_STATE_ON: + if (!dev->radio_hw_enable) { + /* No luck. We can't toggle the hardware RF-kill + * button from software. */ + err = -EBUSY; + goto out_unlock; + } + if (!dev->phy.radio_on) + b43legacy_radio_turn_on(dev); + break; + case RFKILL_STATE_OFF: + if (dev->phy.radio_on) + b43legacy_radio_turn_off(dev, 0); + break; + } + +out_unlock: + mutex_unlock(&wl->mutex); + + return err; +} + +char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + + if (!wl->rfkill.rfkill) + return NULL; + return rfkill_get_led_name(wl->rfkill.rfkill); +} + +void b43legacy_rfkill_init(struct b43legacy_wldev *dev) +{ + struct b43legacy_wl *wl = dev->wl; + struct b43legacy_rfkill *rfk = &(wl->rfkill); + int err; + + 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) + goto error; + rfk->rfkill->name = rfk->name; + rfk->rfkill->state = RFKILL_STATE_ON; + rfk->rfkill->data = dev; + rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; + rfk->rfkill->user_claim_unsupported = 1; + + INIT_WORK(&rfk->notify_work, b43legacy_notify_rfkill_press); + + err = rfkill_register(rfk->rfkill); + if (err) + goto error; + + return; +error: + b43legacywarn(dev->wl, "Failed to initialize the RF-kill button\n"); + rfkill_free(rfk->rfkill); + rfk->rfkill = NULL; +} + +void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) +{ + struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); + + if (!rfk->rfkill) + return; + cancel_work_sync(&rfk->notify_work); + rfkill_unregister(rfk->rfkill); + rfkill_free(rfk->rfkill); + rfk->rfkill = NULL; +} diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h new file mode 100644 index 000000000000..388ee0b855a6 --- /dev/null +++ b/drivers/net/wireless/b43legacy/rfkill.h @@ -0,0 +1,51 @@ +#ifndef B43legacy_RFKILL_H_ +#define B43legacy_RFKILL_H_ + +struct b43legacy_wldev; + +#ifdef CONFIG_B43LEGACY_RFKILL + +#include +#include + + +struct b43legacy_rfkill { + /* The RFKILL subsystem data structure */ + struct rfkill *rfkill; + /* The unique name of this rfkill switch */ + char name[32]; + /* Workqueue for asynchronous notification. */ + struct work_struct notify_work; +}; + +void b43legacy_rfkill_init(struct b43legacy_wldev *dev); +void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); +void b43legacy_rfkill_toggled(struct b43legacy_wldev *dev, bool on); +char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); + + +#else /* CONFIG_B43LEGACY_RFKILL */ +/* No RFKILL support. */ + +struct b43legacy_rfkill { + /* empty */ +}; + +static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_rfkill_toggled(struct b43legacy_wldev *dev, + bool on) +{ +} +static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +{ + return NULL; +} + +#endif /* CONFIG_B43LEGACY_RFKILL */ + +#endif /* B43legacy_RFKILL_H_ */ -- cgit v1.2.3 From 6be50837e303c53b1e5a0138dfed132ccbabcdad Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 10 Oct 2007 22:48:17 -0500 Subject: b43legacy: Use input-polldev for the rfkill switch This removes the direct call to rfkill on an rfkill event and replaces it with an input device. This way userspace is also notified about the event. This patch is the port to b43legacy of a patch for b43 by Michael Buesch . Signed-off-by: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/Kconfig | 2 +- drivers/net/wireless/b43legacy/main.c | 49 +++--------- drivers/net/wireless/b43legacy/rfkill.c | 135 +++++++++++++++++++------------- drivers/net/wireless/b43legacy/rfkill.h | 26 +++--- 4 files changed, 109 insertions(+), 103 deletions(-) (limited to 'drivers/net/wireless/b43legacy/Kconfig') diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 68e05f06b33f..9718529af660 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -43,7 +43,7 @@ config B43LEGACY_LEDS # RFKILL support config B43LEGACY_RFKILL bool - depends on B43LEGACY && RFKILL + depends on B43LEGACY && RFKILL && RFKILL_INPUT && INPUT_POLLDEV default y config B43LEGACY_DEBUG diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 04bc3f6c5e63..069abe5fb8ee 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1975,21 +1975,6 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev, B43legacy_SHM_SH_PRPHYCTL, tmp); } -/* Returns TRUE, if the radio is enabled in hardware. */ -static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) -{ - if (dev->phy.rev >= 3) { - if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) - & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) - return 1; - } else { - if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) - & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) - return 1; - } - return 0; -} - /* This is the opposite of b43legacy_chip_init() */ static void b43legacy_chip_exit(struct b43legacy_wldev *dev) { @@ -2146,32 +2131,18 @@ static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev) b43legacy_phy_xmitpower(dev); /* FIXME: unless scanning? */ } -static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev) -{ - bool radio_hw_enable; - - /* check if radio hardware enabled status changed */ - radio_hw_enable = b43legacy_is_hw_radio_enabled(dev); - if (unlikely(dev->radio_hw_enable != radio_hw_enable)) { - dev->radio_hw_enable = radio_hw_enable; - b43legacy_rfkill_toggled(dev, radio_hw_enable); - } -} - static void do_periodic_work(struct b43legacy_wldev *dev) { unsigned int state; state = dev->periodic_state; - if (state % 120 == 0) + if (state % 8 == 0) b43legacy_periodic_every120sec(dev); - if (state % 60 == 0) + if (state % 4 == 0) b43legacy_periodic_every60sec(dev); - if (state % 30 == 0) + if (state % 2 == 0) b43legacy_periodic_every30sec(dev); - if (state % 15 == 0) - b43legacy_periodic_every15sec(dev); - b43legacy_periodic_every1sec(dev); + b43legacy_periodic_every15sec(dev); } /* Estimate a "Badness" value based on the periodic work @@ -2182,13 +2153,11 @@ static int estimate_periodic_work_badness(unsigned int state) { int badness = 0; - if (state % 120 == 0) /* every 120 sec */ + if (state % 8 == 0) /* every 120 sec */ badness += 10; - if (state % 60 == 0) /* every 60 sec */ + if (state % 4 == 0) /* every 60 sec */ badness += 5; - if (state % 30 == 0) /* every 30 sec */ - badness += 1; - if (state % 15 == 0) /* every 15 sec */ + if (state % 2 == 0) /* every 30 sec */ badness += 1; #define BADNESS_LIMIT 4 @@ -2246,7 +2215,7 @@ out_requeue: if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST)) delay = msecs_to_jiffies(50); else - delay = round_jiffies_relative(HZ); + delay = round_jiffies_relative(HZ * 15); queue_delayed_work(dev->wl->hw->workqueue, &dev->periodic_work, delay); out: @@ -3449,6 +3418,7 @@ static int b43legacy_setup_modes(struct b43legacy_wldev *dev, static void b43legacy_wireless_core_detach(struct b43legacy_wldev *dev) { + b43legacy_rfkill_free(dev); /* We release firmware that late to not be required to re-request * is all the time when we reinit the core. */ b43legacy_release_firmware(dev); @@ -3530,6 +3500,7 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev) if (!wl->current_dev) wl->current_dev = dev; INIT_WORK(&dev->restart_work, b43legacy_chip_reset); + b43legacy_rfkill_alloc(dev); b43legacy_radio_turn_off(dev, 1); b43legacy_switch_analog(dev, 0); diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c index db6292642057..b6bf205c6455 100644 --- a/drivers/net/wireless/b43legacy/rfkill.c +++ b/drivers/net/wireless/b43legacy/rfkill.c @@ -1,6 +1,6 @@ /* - Broadcom B43legacy wireless driver + Broadcom B43 wireless driver RFKILL support Copyright (c) 2007 Michael Buesch @@ -27,48 +27,39 @@ #include "b43legacy.h" -static void b43legacy_notify_rfkill_press(struct work_struct *work) +/* Returns TRUE, if the radio is enabled in hardware. */ +static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) { - struct b43legacy_rfkill *rfk = container_of(work, - struct b43legacy_rfkill, - notify_work); - struct b43legacy_wl *wl = container_of(rfk, struct b43legacy_wl, - rfkill); - struct b43legacy_wldev *dev; - enum rfkill_state state; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) { - mutex_unlock(&wl->mutex); - return; - } - if (dev->radio_hw_enable) - state = RFKILL_STATE_ON; - else - state = RFKILL_STATE_OFF; - b43legacyinfo(wl, "Radio hardware status changed to %s\n", - dev->radio_hw_enable ? "ENABLED" : "DISABLED"); - mutex_unlock(&wl->mutex); - - if (rfk->rfkill) { - /* Be careful. This calls back into the software toggle - * routines. So we must unlock before calling. */ - rfkill_switch_all(rfk->rfkill->type, state); + if (dev->phy.rev >= 3) { + if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) + & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) + return 1; + } else { + if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) + & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) + return 1; } + return 0; } -/* Called when the RFKILL toggled in hardware. - * This is called with the mutex locked. */ -void b43legacy_rfkill_toggled(struct b43legacy_wldev *dev, bool on) +/* The poll callback for the hardware button. */ +static void b43legacy_rfkill_poll(struct input_polled_dev *poll_dev) { + struct b43legacy_wldev *dev = poll_dev->private; struct b43legacy_wl *wl = dev->wl; + bool enabled; + mutex_lock(&wl->mutex); B43legacy_WARN_ON(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED); - /* Update the RF status asynchronously, as rfkill will - * call back into the software toggle handler. - * This would deadlock if done synchronously. */ - queue_work(wl->hw->workqueue, &wl->rfkill.notify_work); + enabled = b43legacy_is_hw_radio_enabled(dev); + if (unlikely(enabled != dev->radio_hw_enable)) { + dev->radio_hw_enable = enabled; + b43legacyinfo(wl, "Radio hardware status changed to %s\n", + enabled ? "ENABLED" : "DISABLED"); + mutex_unlock(&wl->mutex); + input_report_key(poll_dev->input, KEY_WLAN, enabled); + } else + mutex_unlock(&wl->mutex); } /* Called when the RFKILL toggled in software. @@ -106,7 +97,7 @@ out_unlock: return err; } -char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +char * b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) { struct b43legacy_wl *wl = dev->wl; @@ -121,38 +112,74 @@ 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); + 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) - goto error; + 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; rfk->rfkill->toggle_radio = b43legacy_rfkill_soft_toggle; rfk->rfkill->user_claim_unsupported = 1; - INIT_WORK(&rfk->notify_work, b43legacy_notify_rfkill_press); - - err = rfkill_register(rfk->rfkill); - if (err) - goto error; - - return; -error: - b43legacywarn(dev->wl, "Failed to initialize the RF-kill button\n"); - rfkill_free(rfk->rfkill); - rfk->rfkill = NULL; + 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"); } -void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) +void b43legacy_rfkill_free(struct b43legacy_wldev *dev) { struct b43legacy_rfkill *rfk = &(dev->wl->rfkill); - if (!rfk->rfkill) - return; - cancel_work_sync(&rfk->notify_work); - rfkill_unregister(rfk->rfkill); + input_free_polled_device(rfk->poll_dev); + rfk->poll_dev = NULL; rfkill_free(rfk->rfkill); rfk->rfkill = NULL; } diff --git a/drivers/net/wireless/b43legacy/rfkill.h b/drivers/net/wireless/b43legacy/rfkill.h index 388ee0b855a6..4a81ba3f54f2 100644 --- a/drivers/net/wireless/b43legacy/rfkill.h +++ b/drivers/net/wireless/b43legacy/rfkill.h @@ -7,21 +7,27 @@ struct b43legacy_wldev; #include #include +#include + struct b43legacy_rfkill { /* The RFKILL subsystem data structure */ struct rfkill *rfkill; + /* The poll device for the RFKILL input button */ + struct input_polled_dev *poll_dev; /* The unique name of this rfkill switch */ char name[32]; - /* Workqueue for asynchronous notification. */ - struct work_struct notify_work; }; +/* All the init functions return void, because we are not interested + * in failing the b43 init process when rfkill init failed. */ +void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev); +void b43legacy_rfkill_free(struct b43legacy_wldev *dev); void b43legacy_rfkill_init(struct b43legacy_wldev *dev); void b43legacy_rfkill_exit(struct b43legacy_wldev *dev); -void b43legacy_rfkill_toggled(struct b43legacy_wldev *dev, bool on); -char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); + +char * b43legacy_rfkill_led_name(struct b43legacy_wldev *dev); #else /* CONFIG_B43LEGACY_RFKILL */ @@ -31,17 +37,19 @@ struct b43legacy_rfkill { /* empty */ }; -static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev) +static inline void b43legacy_rfkill_alloc(struct b43legacy_wldev *dev) { } -static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) +static inline void b43legacy_rfkill_free(struct b43legacy_wldev *dev) { } -static inline void b43legacy_rfkill_toggled(struct b43legacy_wldev *dev, - bool on) +static inline void b43legacy_rfkill_init(struct b43legacy_wldev *dev) +{ +} +static inline void b43legacy_rfkill_exit(struct b43legacy_wldev *dev) { } -static inline char *b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) +static inline char * b43legacy_rfkill_led_name(struct b43legacy_wldev *dev) { return NULL; } -- cgit v1.2.3 From 59f1b154653d961d3ace72a4a5311c395cf7d779 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Thu, 8 Nov 2007 00:28:00 +0100 Subject: b43legacy: fix kconfig dependecies for rfkill and leds Fix dependencies for built-in b43legacy. The patch to b43 by Michael Buesch has been ported to b43legacy. Signed-off-by: Stefano Brivio Signed-off-by: John W. Linville --- drivers/net/wireless/b43legacy/Kconfig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/b43legacy/Kconfig') diff --git a/drivers/net/wireless/b43legacy/Kconfig b/drivers/net/wireless/b43legacy/Kconfig index 9718529af660..6745579ba96d 100644 --- a/drivers/net/wireless/b43legacy/Kconfig +++ b/drivers/net/wireless/b43legacy/Kconfig @@ -35,15 +35,19 @@ config B43LEGACY_PCICORE_AUTOSELECT default y # LED support +# This config option automatically enables b43legacy LEDS support, +# if it's possible. config B43LEGACY_LEDS bool - depends on B43LEGACY && MAC80211_LEDS + depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY) default y # RFKILL support +# This config option automatically enables b43legacy RFKILL support, +# if it's possible. config B43LEGACY_RFKILL bool - depends on B43LEGACY && RFKILL && RFKILL_INPUT && INPUT_POLLDEV + depends on B43LEGACY && (RFKILL = y || RFKILL = B43LEGACY) && RFKILL_INPUT && (INPUT_POLLDEV = y || INPUT_POLLDEV = B43LEGACY) default y config B43LEGACY_DEBUG -- cgit v1.2.3