linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Ath9k: Add RF kill support.
@ 2008-09-06 12:38 Vasanthakumar Thiagarajan
  2008-09-06 17:15 ` Marcel Holtmann
  2008-09-07 12:09 ` Henrique de Moraes Holschuh
  0 siblings, 2 replies; 25+ messages in thread
From: Vasanthakumar Thiagarajan @ 2008-09-06 12:38 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Jouni Malinen, Luis Rodriguez

CONFIG_ATH9K_RFKILL needs to be set
to enable this support.

Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
---
 drivers/net/wireless/ath9k/Kconfig |    5 +
 drivers/net/wireless/ath9k/ath9k.h |    7 +-
 drivers/net/wireless/ath9k/core.h  |   25 ++++
 drivers/net/wireless/ath9k/hw.c    |   70 ++++++----
 drivers/net/wireless/ath9k/hw.h    |    2 -
 drivers/net/wireless/ath9k/main.c  |  259 ++++++++++++++++++++++++++++++++++++
 6 files changed, 335 insertions(+), 33 deletions(-)

diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig
index 80a6924..54ba25a 100644
--- a/drivers/net/wireless/ath9k/Kconfig
+++ b/drivers/net/wireless/ath9k/Kconfig
@@ -4,8 +4,13 @@ config ATH9K
 	select MAC80211_LEDS
 	select LEDS_CLASS
 	select NEW_LEDS
+	select RFKILL if ATH9K_RFKILL
 	---help---
 	  This module adds support for wireless adapters based on
 	  Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
 
 	  If you choose to build a module, it'll be called ath9k.
+
+config ATH9K_RFKILL
+	boolean "Ath9k RF kill support"
+	depends on ATH9K
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 28b8d84..5589094 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -802,7 +802,10 @@ struct ath_hal {
 	bool ah_rfkillEnabled;
 	bool ah_isPciExpress;
 	u16 ah_txTrigLevel;
-
+#ifdef CONFIG_ATH9K_RFKILL
+	u32 ah_rfkill_gpio ;
+	u32 ah_rfkill_polarity;
+#endif
 #ifndef ATH_NF_PER_CHAN
 	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
 #endif
@@ -1003,4 +1006,6 @@ bool ath9k_get_channel_edges(struct ath_hal *ah,
 void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
 			u32 ah_signal_type);
 void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
 #endif
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 1faa1ef..5bbf747 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -40,6 +40,9 @@
 #include <asm/page.h>
 #include <net/mac80211.h>
 #include <linux/leds.h>
+#ifdef CONFIG_ATH9K_RFKILL
+#include <linux/rfkill.h>
+#endif
 
 #include "ath9k.h"
 #include "rc.h"
@@ -823,6 +826,17 @@ struct ath_led {
 	bool registered;
 };
 
+#ifdef CONFIG_ATH9K_RFKILL
+/* Rfkill */
+#define ATH_RFKILL_POLL_INTERVAL	2000 /* msecs */
+
+struct ath_rfkill {
+	struct rfkill *rfkill;
+	struct delayed_work rfkill_poll;
+	char rfkill_name[32];
+};
+#endif
+
 /********************/
 /* Main driver core */
 /********************/
@@ -906,6 +920,12 @@ struct ath_ht_info {
 #define SC_OP_PROTECT_ENABLE	BIT(8)
 #define SC_OP_RXFLUSH		BIT(9)
 #define SC_OP_LED_ASSOCIATED	BIT(10)
+#ifdef CONFIG_ATH9K_RFKILL
+#define SC_OP_RFKILL_ALLOCATED	BIT(11)
+#define SC_OP_RFKILL_REGISTERED	BIT(12)
+#define SC_OP_RFKILL_SW_BLOCKED	BIT(13)
+#define SC_OP_RFKILL_HW_BLOCKED	BIT(14)
+#endif
 
 struct ath_softc {
 	struct ieee80211_hw *hw;
@@ -1015,6 +1035,11 @@ struct ath_softc {
 	struct ath_led assoc_led;
 	struct ath_led tx_led;
 	struct ath_led rx_led;
+
+#ifdef CONFIG_ATH9K_RFKILL
+	/* Rfkill */
+	struct ath_rfkill rf_kill;
+#endif
 };
 
 int ath_init(u16 devid, struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 4ccbbc0..9cc91e1 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -2821,7 +2821,38 @@ void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
 		AR_GPIO_BIT(gpio));
 }
 
-static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
+/*
+ * Configure GPIO Input lines
+ */
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
+{
+	u32 gpio_shift;
+
+	ASSERT(gpio < ah->ah_caps.num_gpio_pins);
+
+	gpio_shift = 2 * gpio;
+
+	REG_RMW(ah,
+		AR_GPIO_OE_OUT,
+		(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
+		(AR_GPIO_OE_OUT_DRV << gpio_shift));
+}
+
+#ifdef CONFIG_ATH9K_RFKILL
+static void ath9k_enable_rfkill(struct ath_hal *ah)
+{
+	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+		    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+
+	REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+		    AR_GPIO_INPUT_MUX2_RFSILENT);
+
+	ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
+	REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+}
+#endif
+
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
 {
 	if (gpio >= ah->ah_caps.num_gpio_pins)
 		return 0xffffffff;
@@ -3034,17 +3065,17 @@ static bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
 
 	pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
 
+#ifdef CONFIG_ATH9K_RFKILL
 	ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT);
 	if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
-		ahp->ah_gpioSelect =
+		ah->ah_rfkill_gpio =
 			MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
-		ahp->ah_polarity =
+		ah->ah_rfkill_polarity =
 			MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
 
-		ath9k_hw_setcapability(ah, ATH9K_CAP_RFSILENT, 1, true,
-				       NULL);
 		pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
 	}
+#endif
 
 	if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
 	    (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
@@ -5961,6 +5992,10 @@ bool ath9k_hw_reset(struct ath_hal *ah,
 	ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
 	ath9k_hw_init_qos(ah);
 
+#ifdef CONFIG_ATH9K_RFKILL
+	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		ath9k_enable_rfkill(ah);
+#endif
 	ath9k_hw_init_user_settings(ah);
 
 	REG_WRITE(ah, AR_STA_ID1,
@@ -6490,31 +6525,6 @@ ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
 	return true;
 }
 
-#ifdef CONFIG_ATH9K_RFKILL
-static void ath9k_enable_rfkill(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-		    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
-	REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
-		    AR_GPIO_INPUT_MUX2_RFSILENT);
-
-	ath9k_hw_cfg_gpio_input(ah, ahp->ah_gpioSelect);
-	REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-
-	if (ahp->ah_gpioBit == ath9k_hw_gpio_get(ah, ahp->ah_gpioSelect)) {
-
-		ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
-				       !ahp->ah_gpioBit);
-	} else {
-		ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
-				       ahp->ah_gpioBit);
-	}
-}
-#endif
-
 void
 ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
 		       u16 assocId)
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h
index 2113818..2134838 100644
--- a/drivers/net/wireless/ath9k/hw.h
+++ b/drivers/net/wireless/ath9k/hw.h
@@ -757,8 +757,6 @@ struct ath_hal_5416 {
 	u32 ah_ctstimeout;
 	u32 ah_globaltxtimeout;
 	u8 ah_gBeaconRate;
-	u32 ah_gpioSelect;
-	u32 ah_polarity;
 	u32 ah_gpioBit;
 
 	/* ANI */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 57d7cc8..836ccab 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -325,6 +325,213 @@ static u8 parse_mpdudensity(u8 mpdudensity)
 	}
 }
 
+#ifdef CONFIG_ATH9K_RFKILL
+
+/*******************/
+/*	Rfkill	   */
+/*******************/
+
+static void ath_radio_enable(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	int status;
+
+	spin_lock_bh(&sc->sc_resetlock);
+	if (!ath9k_hw_reset(ah, ah->ah_curchan,
+			    sc->sc_ht_info.tx_chan_width,
+			    sc->sc_tx_chainmask,
+			    sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing,
+			    false, &status)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to reset channel %u (%uMhz) "
+			"flags 0x%x hal status %u\n", __func__,
+			ath9k_hw_mhz2ieee(ah,
+					  ah->ah_curchan->channel,
+					  ah->ah_curchan->channelFlags),
+			ah->ah_curchan->channel,
+			ah->ah_curchan->channelFlags, status);
+	}
+	spin_unlock_bh(&sc->sc_resetlock);
+
+	ath_update_txpow(sc);
+	if (ath_startrecv(sc) != 0) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to restart recv logic\n", __func__);
+		return;
+	}
+
+	if (sc->sc_flags & SC_OP_BEACONS)
+		ath_beacon_config(sc, ATH_IF_ID_ANY);	/* restart beacons */
+
+	/* Re-Enable  interrupts */
+	ath9k_hw_set_interrupts(ah, sc->sc_imask);
+
+	/* Enable LED */
+	ath9k_hw_cfg_output(ah, ATH_LED_PIN,
+			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+	ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0);
+
+	ieee80211_wake_queues(sc->hw);
+}
+
+static void ath_radio_disable(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	int status;
+
+
+	ieee80211_stop_queues(sc->hw);
+
+	/* Disable LED */
+	ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1);
+	ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN);
+
+	/* Disable interrupts */
+	ath9k_hw_set_interrupts(ah, 0);
+
+	ath_draintxq(sc, false);	/* clear pending tx frames */
+	ath_stoprecv(sc);		/* turn off frame recv */
+	ath_flushrecv(sc);		/* flush recv queue */
+
+	spin_lock_bh(&sc->sc_resetlock);
+	if (!ath9k_hw_reset(ah, ah->ah_curchan,
+			    sc->sc_ht_info.tx_chan_width,
+			    sc->sc_tx_chainmask,
+			    sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing,
+			    false, &status)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to reset channel %u (%uMhz) "
+			"flags 0x%x hal status %u\n", __func__,
+			ath9k_hw_mhz2ieee(ah,
+				ah->ah_curchan->channel,
+				ah->ah_curchan->channelFlags),
+			ah->ah_curchan->channel,
+			ah->ah_curchan->channelFlags, status);
+	}
+	spin_unlock_bh(&sc->sc_resetlock);
+
+	ath9k_hw_phy_disable(ah);
+	ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+}
+
+static bool ath_get_rfkill(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+
+	return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) ==
+				  ah->ah_rfkill_polarity;
+}
+
+/* h/w rfkill poll function */
+static void ath_rfkill_poll(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc,
+					    rf_kill.rfkill_poll.work);
+	bool radio_on;
+
+	if (sc->sc_flags & SC_OP_INVALID)
+		return;
+
+	radio_on = !ath_get_rfkill(sc);
+	if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) {
+		if (radio_on)
+			sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED;
+		else
+			sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED;
+
+		if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
+			enum rfkill_state state;
+
+			if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) {
+				state = radio_on ? RFKILL_STATE_SOFT_BLOCKED
+					: RFKILL_STATE_HARD_BLOCKED;
+			} else if (radio_on) {
+				ath_radio_enable(sc);
+				state = RFKILL_STATE_UNBLOCKED;
+			} else {
+				ath_radio_disable(sc);
+				state = RFKILL_STATE_HARD_BLOCKED;
+			}
+			rfkill_force_state(sc->rf_kill.rfkill, state);
+		} else {
+			if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)
+				ath_radio_disable(sc);
+			else
+				ath_radio_enable(sc);
+		}
+	}
+
+	queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll,
+			   msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL));
+}
+
+/* s/w rfkill handler */
+static int ath_sw_toggle_radio(void *data, enum rfkill_state state)
+{
+	struct ath_softc *sc = data;
+
+	switch (state) {
+	case RFKILL_STATE_SOFT_BLOCKED:
+		if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED |
+		    SC_OP_RFKILL_SW_BLOCKED)))
+			ath_radio_disable(sc);
+		sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED;
+		return 0;
+	case RFKILL_STATE_UNBLOCKED:
+		if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) {
+			sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
+		    if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
+			DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the radio"
+				"as it is disabled by h/w \n");
+			return -EPERM;
+		    }
+		    ath_radio_enable(sc);
+		}
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/* Init s/w rfkill */
+static void ath_init_sw_rfkill(struct ath_softc *sc)
+{
+	sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy),
+					     RFKILL_TYPE_WLAN);
+	if (!sc->rf_kill.rfkill) {
+		DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
+		return;
+	}
+
+	snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
+		"ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy));
+	sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name;
+	sc->rf_kill.rfkill->data = sc;
+	sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
+	sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
+	sc->rf_kill.rfkill->user_claim_unsupported = 1;
+
+	sc->sc_flags |= SC_OP_RFKILL_ALLOCATED;
+}
+
+/* Deinitialize rfkill */
+static void ath_deinit_rfkill(struct ath_softc *sc)
+{
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+
+	if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
+		rfkill_unregister(sc->rf_kill.rfkill);
+		sc->sc_flags &= ~(SC_OP_RFKILL_REGISTERED |
+				  SC_OP_RFKILL_ALLOCATED);
+		sc->rf_kill.rfkill = NULL;
+	}
+}
+
+#endif /* CONFIG_ATH9K_RFKILL */
+
 static int ath9k_start(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
@@ -354,6 +561,26 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	}
 
 	ieee80211_wake_queues(hw);
+
+#ifdef CONFIG_ATH9K_RFKILL
+	/* Start rfkill polling */
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		queue_delayed_work(sc->hw->workqueue,
+				   &sc->rf_kill.rfkill_poll, 0);
+
+	if ((sc->sc_flags & SC_OP_RFKILL_ALLOCATED) &&
+	    !(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
+		if (rfkill_register(sc->rf_kill.rfkill)) {
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"Unable to register rfkill\n");
+			rfkill_free(sc->rf_kill.rfkill);
+			sc->sc_flags &= ~SC_OP_RFKILL_ALLOCATED;
+		} else {
+			sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
+		}
+	}
+#endif
+
 	return 0;
 }
 
@@ -414,6 +641,11 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 			"%s: Device is no longer present\n", __func__);
 
 	ieee80211_stop_queues(hw);
+
+#ifdef CONFIG_ATH9K_RFKILL
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
 }
 
 static int ath9k_add_interface(struct ieee80211_hw *hw,
@@ -1293,6 +1525,10 @@ static int ath_detach(struct ath_softc *sc)
 	/* Deinit LED control */
 	ath_deinit_leds(sc);
 
+#ifdef CONFIG_ATH9K_RFKILL
+	/* deinit rfkill */
+	ath_deinit_rfkill(sc);
+#endif
 	/* Unregister hw */
 
 	ieee80211_unregister_hw(hw);
@@ -1389,6 +1625,15 @@ static int ath_attach(u16 devid,
 	/* Initialize LED control */
 	ath_init_leds(sc);
 
+#ifdef CONFIG_ATH9K_RFKILL
+	/* Initialze h/w Rfkill */
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
+
+	/* Initialize s/w rfkill */
+	ath_init_sw_rfkill(sc);
+#endif
+
 	/* initialize tx/rx engine */
 
 	error = ath_tx_init(sc, ATH_TXBUF);
@@ -1554,6 +1799,10 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 	struct ath_softc *sc = hw->priv;
 
 	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+#ifdef CONFIG_ATH9K_RFKILL
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
 	pci_set_power_state(pdev, 3);
@@ -1586,6 +1835,16 @@ static int ath_pci_resume(struct pci_dev *pdev)
 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 
+#ifdef CONFIG_ATH9K_RFKILL
+	/*
+	 * check the h/w rfkill state on resume
+	 * and start the rfkill poll timer
+	 */
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		queue_delayed_work(sc->hw->workqueue,
+				   &sc->rf_kill.rfkill_poll, 0);
+#endif
+
 	return 0;
 }
 
-- 
1.5.5.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-06 12:38 [PATCH] Ath9k: Add RF kill support Vasanthakumar Thiagarajan
@ 2008-09-06 17:15 ` Marcel Holtmann
  2008-09-06 17:19   ` Johannes Berg
  2008-09-08  4:59   ` Vasanthakumar Thiagarajan
  2008-09-07 12:09 ` Henrique de Moraes Holschuh
  1 sibling, 2 replies; 25+ messages in thread
From: Marcel Holtmann @ 2008-09-06 17:15 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan
  Cc: linville, linux-wireless, Jouni Malinen, Luis Rodriguez

Hi Vasanthakumar,

> CONFIG_ATH9K_RFKILL needs to be set
> to enable this support.

why do we have to introduce yet another config option for this? What is
the advantage of disabling RFKILL support? I really don't see it and all
these extra config options are rather confusing than useful.

Regards

Marcel



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-06 17:15 ` Marcel Holtmann
@ 2008-09-06 17:19   ` Johannes Berg
  2008-09-06 17:23     ` Johannes Berg
  2008-09-07  0:57     ` Marcel Holtmann
  2008-09-08  4:59   ` Vasanthakumar Thiagarajan
  1 sibling, 2 replies; 25+ messages in thread
From: Johannes Berg @ 2008-09-06 17:19 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Vasanthakumar Thiagarajan, linville, linux-wireless,
	Jouni Malinen, Luis Rodriguez

[-- Attachment #1: Type: text/plain, Size: 465 bytes --]

On Sat, 2008-09-06 at 19:15 +0200, Marcel Holtmann wrote:
> Hi Vasanthakumar,
> 
> > CONFIG_ATH9K_RFKILL needs to be set
> > to enable this support.
> 
> why do we have to introduce yet another config option for this? What is
> the advantage of disabling RFKILL support? I really don't see it and all
> these extra config options are rather confusing than useful.

"if EMBEDDED", I think you may want to build a router without rfkill
stuff.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-06 17:19   ` Johannes Berg
@ 2008-09-06 17:23     ` Johannes Berg
  2008-09-07  1:00       ` Marcel Holtmann
  2008-09-07  0:57     ` Marcel Holtmann
  1 sibling, 1 reply; 25+ messages in thread
From: Johannes Berg @ 2008-09-06 17:23 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Vasanthakumar Thiagarajan, linville, linux-wireless,
	Jouni Malinen, Luis Rodriguez

[-- Attachment #1: Type: text/plain, Size: 820 bytes --]

On Sat, 2008-09-06 at 19:19 +0200, Johannes Berg wrote:
> On Sat, 2008-09-06 at 19:15 +0200, Marcel Holtmann wrote:
> > Hi Vasanthakumar,
> > 
> > > CONFIG_ATH9K_RFKILL needs to be set
> > > to enable this support.
> > 
> > why do we have to introduce yet another config option for this? What is
> > the advantage of disabling RFKILL support? I really don't see it and all
> > these extra config options are rather confusing than useful.
> 
> "if EMBEDDED", I think you may want to build a router without rfkill
> stuff.

Although I don't like all the select business, can't we just have this
be an invisible option and make it depend on RFKILL? That way, when
RFKILL isn't selected, ath9k-rfkill won't be compiled, but if it is, it
will be, and RFKILL can be "default y" and "if EMBEDDED"

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-06 17:19   ` Johannes Berg
  2008-09-06 17:23     ` Johannes Berg
@ 2008-09-07  0:57     ` Marcel Holtmann
  1 sibling, 0 replies; 25+ messages in thread
From: Marcel Holtmann @ 2008-09-07  0:57 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Vasanthakumar Thiagarajan, linville, linux-wireless,
	Jouni Malinen, Luis Rodriguez

Hi Johannes,

> > > CONFIG_ATH9K_RFKILL needs to be set
> > > to enable this support.
> > 
> > why do we have to introduce yet another config option for this? What is
> > the advantage of disabling RFKILL support? I really don't see it and all
> > these extra config options are rather confusing than useful.
> 
> "if EMBEDDED", I think you may want to build a router without rfkill
> stuff.

so what overhead is it to have RFKILL just enabled all the time. It is a
small subsystem and the extra code inside the drivers is also not that
much. So what are we really trying to save here?

I can see your router point, but does it really matter? I don't think so
and some routers allow to switch WiFi off and then they want the RFKILL
switch again. Also what about the LEDS subsystem. The same would apply
and we are not bothering in just enabling it.

Regards

Marcel



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-06 17:23     ` Johannes Berg
@ 2008-09-07  1:00       ` Marcel Holtmann
  2008-09-07  7:17         ` Johannes Berg
  0 siblings, 1 reply; 25+ messages in thread
From: Marcel Holtmann @ 2008-09-07  1:00 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Vasanthakumar Thiagarajan, linville, linux-wireless,
	Jouni Malinen, Luis Rodriguez

Hi Johannes,

> > > > CONFIG_ATH9K_RFKILL needs to be set
> > > > to enable this support.
> > > 
> > > why do we have to introduce yet another config option for this? What is
> > > the advantage of disabling RFKILL support? I really don't see it and all
> > > these extra config options are rather confusing than useful.
> > 
> > "if EMBEDDED", I think you may want to build a router without rfkill
> > stuff.
> 
> Although I don't like all the select business, can't we just have this
> be an invisible option and make it depend on RFKILL? That way, when
> RFKILL isn't selected, ath9k-rfkill won't be compiled, but if it is, it
> will be, and RFKILL can be "default y" and "if EMBEDDED"

that would be a good compromise. I hate all these extra options that are
basically useless since we enable them anyway. There have already been
various complains about useless options. So at least hide them inside
CONFIG_EMBEDDED if you really think it is worth it. My personal opinion
is that RFKILL support should not be optional. If the hardware supports
it then it should be enabled.

Regards

Marcel



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-07  1:00       ` Marcel Holtmann
@ 2008-09-07  7:17         ` Johannes Berg
  2008-09-07 11:56           ` Henrique de Moraes Holschuh
  0 siblings, 1 reply; 25+ messages in thread
From: Johannes Berg @ 2008-09-07  7:17 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Vasanthakumar Thiagarajan, linville, linux-wireless,
	Jouni Malinen, Luis Rodriguez

[-- Attachment #1: Type: text/plain, Size: 1704 bytes --]

Hi Marcel,

> so what overhead is it to have RFKILL just enabled all the time. It is a
> small subsystem and the extra code inside the drivers is also not that
> much. So what are we really trying to save here?
> 
> I can see your router point, but does it really matter? I don't think so
> and some routers allow to switch WiFi off and then they want the RFKILL
> switch again. Also what about the LEDS subsystem. The same would apply
> and we are not bothering in just enabling it.

Yeah I mostly agree with you, but those things do add up. Two kb .text
saved means we can handle a few more stations ;)

> > Although I don't like all the select business, can't we just have this
> > be an invisible option and make it depend on RFKILL? That way, when
> > RFKILL isn't selected, ath9k-rfkill won't be compiled, but if it is, it
> > will be, and RFKILL can be "default y" and "if EMBEDDED"
> 
> that would be a good compromise. I hate all these extra options that are
> basically useless since we enable them anyway. There have already been
> various complains about useless options. So at least hide them inside
> CONFIG_EMBEDDED if you really think it is worth it. My personal opinion
> is that RFKILL support should not be optional. If the hardware supports
> it then it should be enabled.

Then we'd be back at select, but I don't really care much either way. I
agree that this particular option and other driver options for this are
fairly useless.

On the other hand, if rfkill isn't optional but selected, I lose, udev
has been so buggy that I've had to disable rfkill to avoid having it go
into an endless loop on some rfkill (re-/de-?)registrations.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-07  7:17         ` Johannes Berg
@ 2008-09-07 11:56           ` Henrique de Moraes Holschuh
  2008-09-07 12:40             ` Johannes Berg
  0 siblings, 1 reply; 25+ messages in thread
From: Henrique de Moraes Holschuh @ 2008-09-07 11:56 UTC (permalink / raw)
  To: Johannes Berg
  Cc: Marcel Holtmann, Vasanthakumar Thiagarajan, linville,
	linux-wireless, Jouni Malinen, Luis Rodriguez

On Sun, 07 Sep 2008, Johannes Berg wrote:
> On the other hand, if rfkill isn't optional but selected, I lose, udev
> has been so buggy that I've had to disable rfkill to avoid having it go
> into an endless loop on some rfkill (re-/de-?)registrations.

Which udev?  I am working on rfkill now, and I torture the heck out of it
with re/de/registrations, and it never went berserk on me so far...

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-06 12:38 [PATCH] Ath9k: Add RF kill support Vasanthakumar Thiagarajan
  2008-09-06 17:15 ` Marcel Holtmann
@ 2008-09-07 12:09 ` Henrique de Moraes Holschuh
  2008-09-08  5:20   ` Vasanthakumar Thiagarajan
  1 sibling, 1 reply; 25+ messages in thread
From: Henrique de Moraes Holschuh @ 2008-09-07 12:09 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan
  Cc: linville, linux-wireless, Jouni Malinen, Luis Rodriguez

On Sat, 06 Sep 2008, Vasanthakumar Thiagarajan wrote:
> +/* Init s/w rfkill */
> +static void ath_init_sw_rfkill(struct ath_softc *sc)
> +{
> +	sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy),
> +					     RFKILL_TYPE_WLAN);
> +	if (!sc->rf_kill.rfkill) {
> +		DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
> +		return;
> +	}
> +
> +	snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
> +		"ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy));
> +	sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name;
> +	sc->rf_kill.rfkill->data = sc;
> +	sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
> +	sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
> +	sc->rf_kill.rfkill->user_claim_unsupported = 1;
> +
> +	sc->sc_flags |= SC_OP_RFKILL_ALLOCATED;
> +}

IMO, if a driver has added rfkill support, and it is enabled, that driver
must refuse to load if it cannot register with the rfkill subsystem (that
only happens due to bugs or OOM conditions, anyway).

Once you support rfkill in a piece of hardware and that support starts being
used, the configurations using your driver might start to depend on rfkill
being operational to be safe to operate in may user cases.

So, please consider shutting down the radio and aborting the driver load if
you cannot properly register rfkill support in ath9k.

Also, remember that you may get issued an immediate call to toggle_radio
trying to disable (since you default to enabled at power up -- can't you do
the inverse when rfkill support is compiled in? it is much safer) the radio
before rfkill_register() returns.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-07 11:56           ` Henrique de Moraes Holschuh
@ 2008-09-07 12:40             ` Johannes Berg
  0 siblings, 0 replies; 25+ messages in thread
From: Johannes Berg @ 2008-09-07 12:40 UTC (permalink / raw)
  To: Henrique de Moraes Holschuh
  Cc: Marcel Holtmann, Vasanthakumar Thiagarajan, linville,
	linux-wireless, Jouni Malinen, Luis Rodriguez

[-- Attachment #1: Type: text/plain, Size: 698 bytes --]

On Sun, 2008-09-07 at 08:56 -0300, Henrique de Moraes Holschuh wrote:
> On Sun, 07 Sep 2008, Johannes Berg wrote:
> > On the other hand, if rfkill isn't optional but selected, I lose, udev
> > has been so buggy that I've had to disable rfkill to avoid having it go
> > into an endless loop on some rfkill (re-/de-?)registrations.
> 
> Which udev?  I am working on rfkill now, and I torture the heck out of it
> with re/de/registrations, and it never went berserk on me so far...

Sorry, not udev, hal, specifically hal-input-addon-listener or something
like that, went into a loop selecting a bad FD of the input device that
had just vanished: http://bugs.debian.org/476086

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-06 17:15 ` Marcel Holtmann
  2008-09-06 17:19   ` Johannes Berg
@ 2008-09-08  4:59   ` Vasanthakumar Thiagarajan
  2008-09-08  5:22     ` Marcel Holtmann
  2008-09-08 15:10     ` Henrique de Moraes Holschuh
  1 sibling, 2 replies; 25+ messages in thread
From: Vasanthakumar Thiagarajan @ 2008-09-08  4:59 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Vasanth Thiagarajan, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org, Jouni Malinen, Luis Rodriguez

On Sat, Sep 06, 2008 at 10:45:47PM +0530, Marcel Holtmann wrote:
> Hi Vasanthakumar,
> 
> > CONFIG_ATH9K_RFKILL needs to be set
> > to enable this support.
> 
> why do we have to introduce yet another config option for this? What is
> the advantage of disabling RFKILL support? I really don't see it and all
> these extra config options are rather confusing than useful.
Normally home users may not hit a situation where they have to
disable the radio, so they can compile out the rf kill support
and essentially disable the periodic run of the work queue 
(rfkill_poll ,runs for every 2 secs).If this does not make 
any sense, I will remove this config option.
> 
> Regards
> 
> Marcel
> 
> 
Thanks for your comments.

Regards,
Vasanth

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-07 12:09 ` Henrique de Moraes Holschuh
@ 2008-09-08  5:20   ` Vasanthakumar Thiagarajan
  0 siblings, 0 replies; 25+ messages in thread
From: Vasanthakumar Thiagarajan @ 2008-09-08  5:20 UTC (permalink / raw)
  To: Henrique de Moraes Holschuh
  Cc: Vasanth Thiagarajan, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org, Jouni Malinen, Luis Rodriguez

> 
> IMO, if a driver has added rfkill support, and it is enabled, that driver
> must refuse to load if it cannot register with the rfkill subsystem (that
> only happens due to bugs or OOM conditions, anyway).
> 
> Once you support rfkill in a piece of hardware and that support starts being
> used, the configurations using your driver might start to depend on rfkill
> being operational to be safe to operate in may user cases.
> 
> So, please consider shutting down the radio and aborting the driver load if
> you cannot properly register rfkill support in ath9k.
ok, thanks.

-vasanth

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-08  4:59   ` Vasanthakumar Thiagarajan
@ 2008-09-08  5:22     ` Marcel Holtmann
  2008-09-08  5:38       ` Vasanthakumar Thiagarajan
  2008-09-08 15:10     ` Henrique de Moraes Holschuh
  1 sibling, 1 reply; 25+ messages in thread
From: Marcel Holtmann @ 2008-09-08  5:22 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan
  Cc: Vasanth Thiagarajan, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org, Jouni Malinen, Luis Rodriguez

Hi Vasanthakumar,

> > > CONFIG_ATH9K_RFKILL needs to be set
> > > to enable this support.
> > 
> > why do we have to introduce yet another config option for this? What is
> > the advantage of disabling RFKILL support? I really don't see it and all
> > these extra config options are rather confusing than useful.
> Normally home users may not hit a situation where they have to
> disable the radio, so they can compile out the rf kill support
> and essentially disable the periodic run of the work queue 
> (rfkill_poll ,runs for every 2 secs).If this does not make 
> any sense, I will remove this config option.

I don't know about the actual implementation, but if you use a polling
mechanism then it is wrong. Can't you make this interrupt driven.

The desktop use case needs RFKILL support, because that will be used for
switching off the radio. Just think about the flight mode case. So the
only case where disabling RFKILL support makes sense would be an
embedded system with specific constraints. However even in the embedded
case, I don't see that usefulness.

Regards

Marcel



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-08  5:22     ` Marcel Holtmann
@ 2008-09-08  5:38       ` Vasanthakumar Thiagarajan
  0 siblings, 0 replies; 25+ messages in thread
From: Vasanthakumar Thiagarajan @ 2008-09-08  5:38 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Vasanth Thiagarajan, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org, Jouni Malinen, Luis Rodriguez

On Mon, Sep 08, 2008 at 10:52:20AM +0530, Marcel Holtmann wrote:
> Hi Vasanthakumar,
> 
> > > > CONFIG_ATH9K_RFKILL needs to be set
> > > > to enable this support.
> > >
> > > why do we have to introduce yet another config option for this? What is
> > > the advantage of disabling RFKILL support? I really don't see it and all
> > > these extra config options are rather confusing than useful.
> > Normally home users may not hit a situation where they have to
> > disable the radio, so they can compile out the rf kill support
> > and essentially disable the periodic run of the work queue
> > (rfkill_poll ,runs for every 2 secs).If this does not make
> > any sense, I will remove this config option.
> 
> I don't know about the actual implementation, but if you use a polling
> mechanism then it is wrong. Can't you make this interrupt driven.
There is some issue in GPIO intrrupt genenration, we can't make it
interrupt driven.
> 
> The desktop use case needs RFKILL support, because that will be used for
> switching off the radio. Just think about the flight mode case. So the
> only case where disabling RFKILL support makes sense would be an
> embedded system with specific constraints. However even in the embedded
> case, I don't see that usefulness.
> 
Yeah, I understand.
> Regards
> 
> Marcel
> 

Regards

Vasanth

> 

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-08  4:59   ` Vasanthakumar Thiagarajan
  2008-09-08  5:22     ` Marcel Holtmann
@ 2008-09-08 15:10     ` Henrique de Moraes Holschuh
  2008-09-09  7:53       ` vasanthakumar thiagarajan
  1 sibling, 1 reply; 25+ messages in thread
From: Henrique de Moraes Holschuh @ 2008-09-08 15:10 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan
  Cc: Marcel Holtmann, Vasanth Thiagarajan, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org, Jouni Malinen, Luis Rodriguez

On Mon, 08 Sep 2008, Vasanthakumar Thiagarajan wrote:
> On Sat, Sep 06, 2008 at 10:45:47PM +0530, Marcel Holtmann wrote:
> > > CONFIG_ATH9K_RFKILL needs to be set
> > > to enable this support.
> > 
> > why do we have to introduce yet another config option for this? What is
> > the advantage of disabling RFKILL support? I really don't see it and all
> > these extra config options are rather confusing than useful.
> Normally home users may not hit a situation where they have to
> disable the radio, so they can compile out the rf kill support
> and essentially disable the periodic run of the work queue 
> (rfkill_poll ,runs for every 2 secs).If this does not make 
> any sense, I will remove this config option.

What doesn't make sense at all is to have it manually selectable.  Just
define it to the same value of CONFIG_RFKILL, or use CONFIG_RFKILL directly
outright.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
@ 2008-09-09  5:33 Mats Johannesson
  0 siblings, 0 replies; 25+ messages in thread
From: Mats Johannesson @ 2008-09-09  5:33 UTC (permalink / raw)
  To: linux-wireless, marcel, vasanth, johannes

On Mon, Sep 08, 2008 at 10:52:20AM +0530, Marcel Holtmann wrote:
And Vasanthakumar Thiagarajan replied:
[...]
> > > Normally home users may not hit a situation where they have to
> > > disable the radio, so they can compile out the rf kill support
> > > and essentially disable the periodic run of the work queue
> > > (rfkill_poll ,runs for every 2 secs).If this does not make
> > > any sense, I will remove this config option.
[...]
> > The desktop use case needs RFKILL support, because that will be used
> > for switching off the radio. Just think about the flight mode case.
> > So the only case where disabling RFKILL support makes sense would be
> > an embedded system with specific constraints. However even in the
> > embedded case, I don't see that usefulness.
> >
> Yeah, I understand.

My 'rfkill' solution is to pull the PCCard out of the notebook slot!
Please, make it configurable. I don't want useless code running in my
sleek kernel (especially polling code...)

Mvh
Mats Johannesson

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Ath9k: Add RF kill support.
  2008-09-08 15:10     ` Henrique de Moraes Holschuh
@ 2008-09-09  7:53       ` vasanthakumar thiagarajan
  0 siblings, 0 replies; 25+ messages in thread
From: vasanthakumar thiagarajan @ 2008-09-09  7:53 UTC (permalink / raw)
  To: Henrique de Moraes Holschuh
  Cc: Marcel Holtmann, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org, Jouni Malinen, Luis Rodriguez

Henrique de Moraes Holschuh wrote:
> On Mon, 08 Sep 2008, Vasanthakumar Thiagarajan wrote:
>   
>> On Sat, Sep 06, 2008 at 10:45:47PM +0530, Marcel Holtmann wrote:
>>     
>>>> CONFIG_ATH9K_RFKILL needs to be set
>>>> to enable this support.
>>>>         
>>> why do we have to introduce yet another config option for this? What is
>>> the advantage of disabling RFKILL support? I really don't see it and all
>>> these extra config options are rather confusing than useful.
>>>       
>> Normally home users may not hit a situation where they have to
>> disable the radio, so they can compile out the rf kill support
>> and essentially disable the periodic run of the work queue
>> (rfkill_poll ,runs for every 2 secs).If this does not make
>> any sense, I will remove this config option.
>>     
>
> What doesn't make sense at all is to have it manually selectable.  Just
> define it to the same value of CONFIG_RFKILL, or use CONFIG_RFKILL directly
> outright.
>   
ok, thanks.

Vasanth

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH] ath9k: Add RF kill support
@ 2008-09-09 15:34 Vasanthakumar Thiagarajan
  2008-09-09 15:42 ` Johannes Berg
                   ` (2 more replies)
  0 siblings, 3 replies; 25+ messages in thread
From: Vasanthakumar Thiagarajan @ 2008-09-09 15:34 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, Jouni Malinen, Luis Rodriguez

This support is compiled in if CONFIG_RFKILL
option is set.

Signed-off-by: Vasanthakumar Thiagarajan <vasanth@atheros.com>
---
 drivers/net/wireless/ath9k/Kconfig |    1 +
 drivers/net/wireless/ath9k/ath9k.h |    9 +-
 drivers/net/wireless/ath9k/core.h  |   24 +
 drivers/net/wireless/ath9k/hw.c    |   70 ++-
 drivers/net/wireless/ath9k/hw.h    |    2 -
 drivers/net/wireless/ath9k/main.c  | 1205 ++++++++++++++++++++++--------------
 6 files changed, 808 insertions(+), 503 deletions(-)

diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig
index 80a6924..9358e9a 100644
--- a/drivers/net/wireless/ath9k/Kconfig
+++ b/drivers/net/wireless/ath9k/Kconfig
@@ -4,6 +4,7 @@ config ATH9K
 	select MAC80211_LEDS
 	select LEDS_CLASS
 	select NEW_LEDS
+	select RFKILL
 	---help---
 	  This module adds support for wireless adapters based on
 	  Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets.
diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index 28b8d84..d92e1ed 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -798,10 +798,13 @@ struct ath_hal {
 	struct ath9k_channel *ah_curchan;
 	u32 ah_nchan;
 
-	u16 ah_rfsilent;
-	bool ah_rfkillEnabled;
 	bool ah_isPciExpress;
 	u16 ah_txTrigLevel;
+#ifdef CONFIG_RFKILL
+	u16 ah_rfsilent;
+	u32 ah_rfkill_gpio ;
+	u32 ah_rfkill_polarity;
+#endif
 
 #ifndef ATH_NF_PER_CHAN
 	struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
@@ -1003,4 +1006,6 @@ bool ath9k_get_channel_edges(struct ath_hal *ah,
 void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio,
 			u32 ah_signal_type);
 void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value);
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio);
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio);
 #endif
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 1faa1ef..aae5a4f 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -40,6 +40,9 @@
 #include <asm/page.h>
 #include <net/mac80211.h>
 #include <linux/leds.h>
+#ifdef CONFIG_RFKILL
+#include <linux/rfkill.h>
+#endif
 
 #include "ath9k.h"
 #include "rc.h"
@@ -823,6 +826,17 @@ struct ath_led {
 	bool registered;
 };
 
+#ifdef CONFIG_RFKILL
+/* Rfkill */
+#define ATH_RFKILL_POLL_INTERVAL	2000 /* msecs */
+
+struct ath_rfkill {
+	struct rfkill *rfkill;
+	struct delayed_work rfkill_poll;
+	char rfkill_name[32];
+};
+#endif
+
 /********************/
 /* Main driver core */
 /********************/
@@ -906,6 +920,11 @@ struct ath_ht_info {
 #define SC_OP_PROTECT_ENABLE	BIT(8)
 #define SC_OP_RXFLUSH		BIT(9)
 #define SC_OP_LED_ASSOCIATED	BIT(10)
+#ifdef CONFIG_RFKILL
+#define SC_OP_RFKILL_REGISTERED	BIT(11)
+#define SC_OP_RFKILL_SW_BLOCKED	BIT(12)
+#define SC_OP_RFKILL_HW_BLOCKED	BIT(13)
+#endif
 
 struct ath_softc {
 	struct ieee80211_hw *hw;
@@ -1015,6 +1034,11 @@ struct ath_softc {
 	struct ath_led assoc_led;
 	struct ath_led tx_led;
 	struct ath_led rx_led;
+
+#ifdef CONFIG_RFKILL
+	/* Rfkill */
+	struct ath_rfkill rf_kill;
+#endif
 };
 
 int ath_init(u16 devid, struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index 4ccbbc0..0251e59 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -2821,7 +2821,38 @@ void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val)
 		AR_GPIO_BIT(gpio));
 }
 
-static u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
+/*
+ * Configure GPIO Input lines
+ */
+void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio)
+{
+	u32 gpio_shift;
+
+	ASSERT(gpio < ah->ah_caps.num_gpio_pins);
+
+	gpio_shift = gpio << 1;
+
+	REG_RMW(ah,
+		AR_GPIO_OE_OUT,
+		(AR_GPIO_OE_OUT_DRV_NO << gpio_shift),
+		(AR_GPIO_OE_OUT_DRV << gpio_shift));
+}
+
+#ifdef CONFIG_RFKILL
+static void ath9k_enable_rfkill(struct ath_hal *ah)
+{
+	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
+		    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
+
+	REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
+		    AR_GPIO_INPUT_MUX2_RFSILENT);
+
+	ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio);
+	REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
+}
+#endif
+
+u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio)
 {
 	if (gpio >= ah->ah_caps.num_gpio_pins)
 		return 0xffffffff;
@@ -3034,17 +3065,17 @@ static bool ath9k_hw_fill_cap_info(struct ath_hal *ah)
 
 	pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM;
 
+#ifdef CONFIG_RFKILL
 	ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT);
 	if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) {
-		ahp->ah_gpioSelect =
+		ah->ah_rfkill_gpio =
 			MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL);
-		ahp->ah_polarity =
+		ah->ah_rfkill_polarity =
 			MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY);
 
-		ath9k_hw_setcapability(ah, ATH9K_CAP_RFSILENT, 1, true,
-				       NULL);
 		pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
 	}
+#endif
 
 	if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) ||
 	    (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) ||
@@ -5961,6 +5992,10 @@ bool ath9k_hw_reset(struct ath_hal *ah,
 	ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode);
 	ath9k_hw_init_qos(ah);
 
+#ifdef CONFIG_RFKILL
+	if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		ath9k_enable_rfkill(ah);
+#endif
 	ath9k_hw_init_user_settings(ah);
 
 	REG_WRITE(ah, AR_STA_ID1,
@@ -6490,31 +6525,6 @@ ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask)
 	return true;
 }
 
-#ifdef CONFIG_ATH9K_RFKILL
-static void ath9k_enable_rfkill(struct ath_hal *ah)
-{
-	struct ath_hal_5416 *ahp = AH5416(ah);
-
-	REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL,
-		    AR_GPIO_INPUT_EN_VAL_RFSILENT_BB);
-
-	REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2,
-		    AR_GPIO_INPUT_MUX2_RFSILENT);
-
-	ath9k_hw_cfg_gpio_input(ah, ahp->ah_gpioSelect);
-	REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB);
-
-	if (ahp->ah_gpioBit == ath9k_hw_gpio_get(ah, ahp->ah_gpioSelect)) {
-
-		ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
-				       !ahp->ah_gpioBit);
-	} else {
-		ath9k_hw_set_gpio_intr(ah, ahp->ah_gpioSelect,
-				       ahp->ah_gpioBit);
-	}
-}
-#endif
-
 void
 ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid,
 		       u16 assocId)
diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h
index 2113818..2134838 100644
--- a/drivers/net/wireless/ath9k/hw.h
+++ b/drivers/net/wireless/ath9k/hw.h
@@ -757,8 +757,6 @@ struct ath_hal_5416 {
 	u32 ah_ctstimeout;
 	u32 ah_globaltxtimeout;
 	u8 ah_gBeaconRate;
-	u32 ah_gpioSelect;
-	u32 ah_polarity;
 	u32 ah_gpioBit;
 
 	/* ANI */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 57d7cc8..6caecc5 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -325,6 +325,693 @@ static u8 parse_mpdudensity(u8 mpdudensity)
 	}
 }
 
+#ifdef CONFIG_RFKILL
+/*******************/
+/*	Rfkill	   */
+/*******************/
+
+static void ath_radio_enable(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	int status;
+
+	spin_lock_bh(&sc->sc_resetlock);
+	if (!ath9k_hw_reset(ah, ah->ah_curchan,
+			    sc->sc_ht_info.tx_chan_width,
+			    sc->sc_tx_chainmask,
+			    sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing,
+			    false, &status)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to reset channel %u (%uMhz) "
+			"flags 0x%x hal status %u\n", __func__,
+			ath9k_hw_mhz2ieee(ah,
+					  ah->ah_curchan->channel,
+					  ah->ah_curchan->channelFlags),
+			ah->ah_curchan->channel,
+			ah->ah_curchan->channelFlags, status);
+	}
+	spin_unlock_bh(&sc->sc_resetlock);
+
+	ath_update_txpow(sc);
+	if (ath_startrecv(sc) != 0) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to restart recv logic\n", __func__);
+		return;
+	}
+
+	if (sc->sc_flags & SC_OP_BEACONS)
+		ath_beacon_config(sc, ATH_IF_ID_ANY);	/* restart beacons */
+
+	/* Re-Enable  interrupts */
+	ath9k_hw_set_interrupts(ah, sc->sc_imask);
+
+	/* Enable LED */
+	ath9k_hw_cfg_output(ah, ATH_LED_PIN,
+			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+	ath9k_hw_set_gpio(ah, ATH_LED_PIN, 0);
+
+	ieee80211_wake_queues(sc->hw);
+}
+
+static void ath_radio_disable(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+	int status;
+
+
+	ieee80211_stop_queues(sc->hw);
+
+	/* Disable LED */
+	ath9k_hw_set_gpio(ah, ATH_LED_PIN, 1);
+	ath9k_hw_cfg_gpio_input(ah, ATH_LED_PIN);
+
+	/* Disable interrupts */
+	ath9k_hw_set_interrupts(ah, 0);
+
+	ath_draintxq(sc, false);	/* clear pending tx frames */
+	ath_stoprecv(sc);		/* turn off frame recv */
+	ath_flushrecv(sc);		/* flush recv queue */
+
+	spin_lock_bh(&sc->sc_resetlock);
+	if (!ath9k_hw_reset(ah, ah->ah_curchan,
+			    sc->sc_ht_info.tx_chan_width,
+			    sc->sc_tx_chainmask,
+			    sc->sc_rx_chainmask,
+			    sc->sc_ht_extprotspacing,
+			    false, &status)) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: unable to reset channel %u (%uMhz) "
+			"flags 0x%x hal status %u\n", __func__,
+			ath9k_hw_mhz2ieee(ah,
+				ah->ah_curchan->channel,
+				ah->ah_curchan->channelFlags),
+			ah->ah_curchan->channel,
+			ah->ah_curchan->channelFlags, status);
+	}
+	spin_unlock_bh(&sc->sc_resetlock);
+
+	ath9k_hw_phy_disable(ah);
+	ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP);
+}
+
+static bool ath_is_rfkill_set(struct ath_softc *sc)
+{
+	struct ath_hal *ah = sc->sc_ah;
+
+	return ath9k_hw_gpio_get(ah, ah->ah_rfkill_gpio) ==
+				  ah->ah_rfkill_polarity;
+}
+
+/* h/w rfkill poll function */
+static void ath_rfkill_poll(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc,
+					    rf_kill.rfkill_poll.work);
+	bool radio_on;
+
+	if (sc->sc_flags & SC_OP_INVALID)
+		return;
+
+	radio_on = !ath_is_rfkill_set(sc);
+
+	/*
+	 * enable/disable radio only when there is a
+	 * state change in RF switch
+	 */
+	if (radio_on == !!(sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED)) {
+		enum rfkill_state state;
+
+		if (sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED) {
+			state = radio_on ? RFKILL_STATE_SOFT_BLOCKED
+				: RFKILL_STATE_HARD_BLOCKED;
+		} else if (radio_on) {
+			ath_radio_enable(sc);
+			state = RFKILL_STATE_UNBLOCKED;
+		} else {
+			ath_radio_disable(sc);
+			state = RFKILL_STATE_HARD_BLOCKED;
+		}
+
+		if (state == RFKILL_STATE_HARD_BLOCKED)
+			sc->sc_flags |= SC_OP_RFKILL_HW_BLOCKED;
+		else
+			sc->sc_flags &= ~SC_OP_RFKILL_HW_BLOCKED;
+
+		rfkill_force_state(sc->rf_kill.rfkill, state);
+	}
+
+	queue_delayed_work(sc->hw->workqueue, &sc->rf_kill.rfkill_poll,
+			   msecs_to_jiffies(ATH_RFKILL_POLL_INTERVAL));
+}
+
+/* s/w rfkill handler */
+static int ath_sw_toggle_radio(void *data, enum rfkill_state state)
+{
+	struct ath_softc *sc = data;
+
+	switch (state) {
+	case RFKILL_STATE_SOFT_BLOCKED:
+		if (!(sc->sc_flags & (SC_OP_RFKILL_HW_BLOCKED |
+		    SC_OP_RFKILL_SW_BLOCKED)))
+			ath_radio_disable(sc);
+		sc->sc_flags |= SC_OP_RFKILL_SW_BLOCKED;
+		return 0;
+	case RFKILL_STATE_UNBLOCKED:
+		if ((sc->sc_flags & SC_OP_RFKILL_SW_BLOCKED)) {
+			sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED;
+			if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) {
+				DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the"
+					"radio as it is disabled by h/w \n");
+				return -EPERM;
+			}
+			ath_radio_enable(sc);
+		}
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+/* Init s/w rfkill */
+static int ath_init_sw_rfkill(struct ath_softc *sc)
+{
+	sc->rf_kill.rfkill = rfkill_allocate(wiphy_dev(sc->hw->wiphy),
+					     RFKILL_TYPE_WLAN);
+	if (!sc->rf_kill.rfkill) {
+		DPRINTF(sc, ATH_DBG_FATAL, "Failed to allocate rfkill\n");
+		return -ENOMEM;
+	}
+
+	snprintf(sc->rf_kill.rfkill_name, sizeof(sc->rf_kill.rfkill_name),
+		"ath9k-%s:rfkill", wiphy_name(sc->hw->wiphy));
+	sc->rf_kill.rfkill->name = sc->rf_kill.rfkill_name;
+	sc->rf_kill.rfkill->data = sc;
+	sc->rf_kill.rfkill->toggle_radio = ath_sw_toggle_radio;
+	sc->rf_kill.rfkill->state = RFKILL_STATE_UNBLOCKED;
+	sc->rf_kill.rfkill->user_claim_unsupported = 1;
+
+	return 0;
+}
+
+/* Deinitialize rfkill */
+static void ath_deinit_rfkill(struct ath_softc *sc)
+{
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+
+	if (sc->sc_flags & SC_OP_RFKILL_REGISTERED) {
+		rfkill_unregister(sc->rf_kill.rfkill);
+		sc->sc_flags &= ~SC_OP_RFKILL_REGISTERED;
+		sc->rf_kill.rfkill = NULL;
+	}
+}
+#endif /* CONFIG_RFKILL */
+
+static void ath9k_ht_conf(struct ath_softc *sc,
+			  struct ieee80211_bss_conf *bss_conf)
+{
+#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14)
+	struct ath_ht_info *ht_info = &sc->sc_ht_info;
+
+	if (bss_conf->assoc_ht) {
+		ht_info->ext_chan_offset =
+			bss_conf->ht_bss_conf->bss_cap &
+				IEEE80211_HT_IE_CHA_SEC_OFFSET;
+
+		if (!(bss_conf->ht_conf->cap &
+			IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
+			    (bss_conf->ht_bss_conf->bss_cap &
+				IEEE80211_HT_IE_CHA_WIDTH))
+			ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040;
+		else
+			ht_info->tx_chan_width = ATH9K_HT_MACMODE_20;
+
+		ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width);
+		ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
+					bss_conf->ht_conf->ampdu_factor);
+		ht_info->mpdudensity =
+			parse_mpdudensity(bss_conf->ht_conf->ampdu_density);
+
+	}
+
+#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT
+}
+
+static void ath9k_bss_assoc_info(struct ath_softc *sc,
+				 struct ieee80211_bss_conf *bss_conf)
+{
+	struct ieee80211_hw *hw = sc->hw;
+	struct ieee80211_channel *curchan = hw->conf.channel;
+	struct ath_vap *avp;
+	int pos;
+	DECLARE_MAC_BUF(mac);
+
+	if (bss_conf->assoc) {
+		DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n",
+			__func__,
+			bss_conf->aid);
+
+		avp = sc->sc_vaps[0];
+		if (avp == NULL) {
+			DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
+				__func__);
+			return;
+		}
+
+		/* New association, store aid */
+		if (avp->av_opmode == ATH9K_M_STA) {
+			sc->sc_curaid = bss_conf->aid;
+			ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
+					       sc->sc_curaid);
+		}
+
+		/* Configure the beacon */
+		ath_beacon_config(sc, 0);
+		sc->sc_flags |= SC_OP_BEACONS;
+
+		/* Reset rssi stats */
+		sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
+		sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
+		sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
+		sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
+
+		/* Update chainmask */
+		ath_update_chainmask(sc, bss_conf->assoc_ht);
+
+		DPRINTF(sc, ATH_DBG_CONFIG,
+			"%s: bssid %s aid 0x%x\n",
+			__func__,
+			print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
+
+		DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
+			__func__,
+			curchan->center_freq);
+
+		pos = ath_get_channel(sc, curchan);
+		if (pos == -1) {
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"%s: Invalid channel\n", __func__);
+			return;
+		}
+
+		if (hw->conf.ht_conf.ht_supported)
+			sc->sc_ah->ah_channels[pos].chanmode =
+				ath_get_extchanmode(sc, curchan);
+		else
+			sc->sc_ah->ah_channels[pos].chanmode =
+				(curchan->band == IEEE80211_BAND_2GHZ) ?
+				CHANNEL_G : CHANNEL_A;
+
+		/* set h/w channel */
+		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
+			DPRINTF(sc, ATH_DBG_FATAL,
+				"%s: Unable to set channel\n",
+				__func__);
+
+		ath_rate_newstate(sc, avp);
+		/* Update ratectrl about the new state */
+		ath_rc_node_update(hw, avp->rc_node);
+	} else {
+		DPRINTF(sc, ATH_DBG_CONFIG,
+		"%s: Bss Info DISSOC\n", __func__);
+		sc->sc_curaid = 0;
+	}
+}
+
+void ath_get_beaconconfig(struct ath_softc *sc,
+			  int if_id,
+			  struct ath_beacon_config *conf)
+{
+	struct ieee80211_hw *hw = sc->hw;
+
+	/* fill in beacon config data */
+
+	conf->beacon_interval = hw->conf.beacon_int;
+	conf->listen_interval = 100;
+	conf->dtim_count = 1;
+	conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
+}
+
+void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
+		     struct ath_xmit_status *tx_status, struct ath_node *an)
+{
+	struct ieee80211_hw *hw = sc->hw;
+	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+
+	DPRINTF(sc, ATH_DBG_XMIT,
+		"%s: TX complete: skb: %p\n", __func__, skb);
+
+	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
+		tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
+		/* free driver's private data area of tx_info */
+		if (tx_info->driver_data[0] != NULL)
+			kfree(tx_info->driver_data[0]);
+			tx_info->driver_data[0] = NULL;
+	}
+
+	if (tx_status->flags & ATH_TX_BAR) {
+		tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
+		tx_status->flags &= ~ATH_TX_BAR;
+	}
+
+	if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
+		if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+			/* Frame was not ACKed, but an ACK was expected */
+			tx_info->status.excessive_retries = 1;
+		}
+	} else {
+		/* Frame was ACKed */
+		tx_info->flags |= IEEE80211_TX_STAT_ACK;
+	}
+
+	tx_info->status.retry_count = tx_status->retries;
+
+	ieee80211_tx_status(hw, skb);
+	if (an)
+		ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE);
+}
+
+int _ath_rx_indicate(struct ath_softc *sc,
+		     struct sk_buff *skb,
+		     struct ath_recv_status *status,
+		     u16 keyix)
+{
+	struct ieee80211_hw *hw = sc->hw;
+	struct ath_node *an = NULL;
+	struct ieee80211_rx_status rx_status;
+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+	int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+	int padsize;
+	enum ATH_RX_TYPE st;
+
+	/* see if any padding is done by the hw and remove it */
+	if (hdrlen & 3) {
+		padsize = hdrlen % 4;
+		memmove(skb->data + padsize, skb->data, hdrlen);
+		skb_pull(skb, padsize);
+	}
+
+	/* Prepare rx status */
+	ath9k_rx_prepare(sc, skb, status, &rx_status);
+
+	if (!(keyix == ATH9K_RXKEYIX_INVALID) &&
+	    !(status->flags & ATH_RX_DECRYPT_ERROR)) {
+		rx_status.flag |= RX_FLAG_DECRYPTED;
+	} else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
+		   && !(status->flags & ATH_RX_DECRYPT_ERROR)
+		   && skb->len >= hdrlen + 4) {
+		keyix = skb->data[hdrlen + 3] >> 6;
+
+		if (test_bit(keyix, sc->sc_keymap))
+			rx_status.flag |= RX_FLAG_DECRYPTED;
+	}
+
+	spin_lock_bh(&sc->node_lock);
+	an = ath_node_find(sc, hdr->addr2);
+	spin_unlock_bh(&sc->node_lock);
+
+	if (an) {
+		ath_rx_input(sc, an,
+			     hw->conf.ht_conf.ht_supported,
+			     skb, status, &st);
+	}
+	if (!an || (st != ATH_RX_CONSUMED))
+		__ieee80211_rx(hw, skb, &rx_status);
+
+	return 0;
+}
+
+int ath_rx_subframe(struct ath_node *an,
+		    struct sk_buff *skb,
+		    struct ath_recv_status *status)
+{
+	struct ath_softc *sc = an->an_sc;
+	struct ieee80211_hw *hw = sc->hw;
+	struct ieee80211_rx_status rx_status;
+
+	/* Prepare rx status */
+	ath9k_rx_prepare(sc, skb, status, &rx_status);
+	if (!(status->flags & ATH_RX_DECRYPT_ERROR))
+		rx_status.flag |= RX_FLAG_DECRYPTED;
+
+	__ieee80211_rx(hw, skb, &rx_status);
+
+	return 0;
+}
+
+/********************************/
+/*	 LED functions		*/
+/********************************/
+
+static void ath_led_brightness(struct led_classdev *led_cdev,
+			       enum led_brightness brightness)
+{
+	struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
+	struct ath_softc *sc = led->sc;
+
+	switch (brightness) {
+	case LED_OFF:
+		if (led->led_type == ATH_LED_ASSOC ||
+		    led->led_type == ATH_LED_RADIO)
+			sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
+		ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
+				(led->led_type == ATH_LED_RADIO) ? 1 :
+				!!(sc->sc_flags & SC_OP_LED_ASSOCIATED));
+		break;
+	case LED_FULL:
+		if (led->led_type == ATH_LED_ASSOC)
+			sc->sc_flags |= SC_OP_LED_ASSOCIATED;
+		ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
+		break;
+	default:
+		break;
+	}
+}
+
+static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
+			    char *trigger)
+{
+	int ret;
+
+	led->sc = sc;
+	led->led_cdev.name = led->name;
+	led->led_cdev.default_trigger = trigger;
+	led->led_cdev.brightness_set = ath_led_brightness;
+
+	ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
+	if (ret)
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"Failed to register led:%s", led->name);
+	else
+		led->registered = 1;
+	return ret;
+}
+
+static void ath_unregister_led(struct ath_led *led)
+{
+	if (led->registered) {
+		led_classdev_unregister(&led->led_cdev);
+		led->registered = 0;
+	}
+}
+
+static void ath_deinit_leds(struct ath_softc *sc)
+{
+	ath_unregister_led(&sc->assoc_led);
+	sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
+	ath_unregister_led(&sc->tx_led);
+	ath_unregister_led(&sc->rx_led);
+	ath_unregister_led(&sc->radio_led);
+	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+}
+
+static void ath_init_leds(struct ath_softc *sc)
+{
+	char *trigger;
+	int ret;
+
+	/* Configure gpio 1 for output */
+	ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+	/* LED off, active low */
+	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+
+	trigger = ieee80211_get_radio_led_name(sc->hw);
+	snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
+		"ath9k-%s:radio", wiphy_name(sc->hw->wiphy));
+	ret = ath_register_led(sc, &sc->radio_led, trigger);
+	sc->radio_led.led_type = ATH_LED_RADIO;
+	if (ret)
+		goto fail;
+
+	trigger = ieee80211_get_assoc_led_name(sc->hw);
+	snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
+		"ath9k-%s:assoc", wiphy_name(sc->hw->wiphy));
+	ret = ath_register_led(sc, &sc->assoc_led, trigger);
+	sc->assoc_led.led_type = ATH_LED_ASSOC;
+	if (ret)
+		goto fail;
+
+	trigger = ieee80211_get_tx_led_name(sc->hw);
+	snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
+		"ath9k-%s:tx", wiphy_name(sc->hw->wiphy));
+	ret = ath_register_led(sc, &sc->tx_led, trigger);
+	sc->tx_led.led_type = ATH_LED_TX;
+	if (ret)
+		goto fail;
+
+	trigger = ieee80211_get_rx_led_name(sc->hw);
+	snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
+		"ath9k-%s:rx", wiphy_name(sc->hw->wiphy));
+	ret = ath_register_led(sc, &sc->rx_led, trigger);
+	sc->rx_led.led_type = ATH_LED_RX;
+	if (ret)
+		goto fail;
+
+	return;
+
+fail:
+	ath_deinit_leds(sc);
+}
+
+static int ath_detach(struct ath_softc *sc)
+{
+	struct ieee80211_hw *hw = sc->hw;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
+
+	/* Deinit LED control */
+	ath_deinit_leds(sc);
+
+#ifdef CONFIG_RFKILL
+	/* deinit rfkill */
+	ath_deinit_rfkill(sc);
+#endif
+
+	/* Unregister hw */
+
+	ieee80211_unregister_hw(hw);
+
+	/* unregister Rate control */
+	ath_rate_control_unregister();
+
+	/* tx/rx cleanup */
+
+	ath_rx_cleanup(sc);
+	ath_tx_cleanup(sc);
+
+	/* Deinit */
+
+	ath_deinit(sc);
+
+	return 0;
+}
+
+static int ath_attach(u16 devid,
+		      struct ath_softc *sc)
+{
+	struct ieee80211_hw *hw = sc->hw;
+	int error = 0;
+
+	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__);
+
+	error = ath_init(devid, sc);
+	if (error != 0)
+		return error;
+
+	/* Init nodes */
+
+	INIT_LIST_HEAD(&sc->node_list);
+	spin_lock_init(&sc->node_lock);
+
+	/* get mac address from hardware and set in mac80211 */
+
+	SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
+
+	/* setup channels and rates */
+
+	sc->sbands[IEEE80211_BAND_2GHZ].channels =
+		sc->channels[IEEE80211_BAND_2GHZ];
+	sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
+		sc->rates[IEEE80211_BAND_2GHZ];
+	sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
+
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
+		/* Setup HT capabilities for 2.4Ghz*/
+		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info);
+
+	hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+		&sc->sbands[IEEE80211_BAND_2GHZ];
+
+	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
+		sc->sbands[IEEE80211_BAND_5GHZ].channels =
+			sc->channels[IEEE80211_BAND_5GHZ];
+		sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
+			sc->rates[IEEE80211_BAND_5GHZ];
+		sc->sbands[IEEE80211_BAND_5GHZ].band =
+			IEEE80211_BAND_5GHZ;
+
+		if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
+			/* Setup HT capabilities for 5Ghz*/
+			setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info);
+
+		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+			&sc->sbands[IEEE80211_BAND_5GHZ];
+	}
+
+	/* FIXME: Have to figure out proper hw init values later */
+
+	hw->queues = 4;
+	hw->ampdu_queues = 1;
+
+	/* Register rate control */
+	hw->rate_control_algorithm = "ath9k_rate_control";
+	error = ath_rate_control_register();
+	if (error != 0) {
+		DPRINTF(sc, ATH_DBG_FATAL,
+			"%s: Unable to register rate control "
+			"algorithm:%d\n", __func__, error);
+		ath_rate_control_unregister();
+		goto bad;
+	}
+
+	error = ieee80211_register_hw(hw);
+	if (error != 0) {
+		ath_rate_control_unregister();
+		goto bad;
+	}
+
+	/* Initialize LED control */
+	ath_init_leds(sc);
+
+#ifdef CONFIG_RFKILL
+	/* Initialze h/w Rfkill */
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
+
+	/* Initialize s/w rfkill */
+	if (ath_init_sw_rfkill(sc))
+		goto detach;
+#endif
+
+	/* initialize tx/rx engine */
+
+	error = ath_tx_init(sc, ATH_TXBUF);
+	if (error != 0)
+		goto detach;
+
+	error = ath_rx_init(sc, ATH_RXBUF);
+	if (error != 0)
+		goto detach;
+
+	return 0;
+detach:
+	ath_detach(sc);
+bad:
+	return error;
+}
+
 static int ath9k_start(struct ieee80211_hw *hw)
 {
 	struct ath_softc *sc = hw->priv;
@@ -354,6 +1041,34 @@ static int ath9k_start(struct ieee80211_hw *hw)
 	}
 
 	ieee80211_wake_queues(hw);
+
+#ifdef CONFIG_RFKILL
+	/* Start rfkill polling */
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		queue_delayed_work(sc->hw->workqueue,
+				   &sc->rf_kill.rfkill_poll, 0);
+
+	if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) {
+		if (rfkill_register(sc->rf_kill.rfkill)) {
+			DPRINTF(sc, ATH_DBG_FATAL,
+					"Unable to register rfkill\n");
+			rfkill_free(sc->rf_kill.rfkill);
+
+			/* Deinitialize the device */
+			if (sc->pdev->irq)
+				free_irq(sc->pdev->irq, sc);
+			ath_detach(sc);
+			pci_iounmap(sc->pdev, sc->mem);
+			pci_release_region(sc->pdev, 0);
+			pci_disable_device(sc->pdev);
+			ieee80211_free_hw(hw);
+			return -EIO;
+		} else {
+			sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
+		}
+	}
+#endif
+
 	return 0;
 }
 
@@ -414,6 +1129,11 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 			"%s: Device is no longer present\n", __func__);
 
 	ieee80211_stop_queues(hw);
+
+#ifdef CONFIG_RFKILL
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
 }
 
 static int ath9k_add_interface(struct ieee80211_hw *hw,
@@ -798,117 +1518,6 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
 	return ret;
 }
 
-static void ath9k_ht_conf(struct ath_softc *sc,
-			  struct ieee80211_bss_conf *bss_conf)
-{
-#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14)
-	struct ath_ht_info *ht_info = &sc->sc_ht_info;
-
-	if (bss_conf->assoc_ht) {
-		ht_info->ext_chan_offset =
-			bss_conf->ht_bss_conf->bss_cap &
-				IEEE80211_HT_IE_CHA_SEC_OFFSET;
-
-		if (!(bss_conf->ht_conf->cap &
-			IEEE80211_HT_CAP_40MHZ_INTOLERANT) &&
-			    (bss_conf->ht_bss_conf->bss_cap &
-				IEEE80211_HT_IE_CHA_WIDTH))
-			ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040;
-		else
-			ht_info->tx_chan_width = ATH9K_HT_MACMODE_20;
-
-		ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width);
-		ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR +
-					bss_conf->ht_conf->ampdu_factor);
-		ht_info->mpdudensity =
-			parse_mpdudensity(bss_conf->ht_conf->ampdu_density);
-
-	}
-
-#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT
-}
-
-static void ath9k_bss_assoc_info(struct ath_softc *sc,
-				 struct ieee80211_bss_conf *bss_conf)
-{
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_channel *curchan = hw->conf.channel;
-	struct ath_vap *avp;
-	int pos;
-	DECLARE_MAC_BUF(mac);
-
-	if (bss_conf->assoc) {
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n",
-			__func__,
-			bss_conf->aid);
-
-		avp = sc->sc_vaps[0];
-		if (avp == NULL) {
-			DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n",
-				__func__);
-			return;
-		}
-
-		/* New association, store aid */
-		if (avp->av_opmode == ATH9K_M_STA) {
-			sc->sc_curaid = bss_conf->aid;
-			ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid,
-					       sc->sc_curaid);
-		}
-
-		/* Configure the beacon */
-		ath_beacon_config(sc, 0);
-		sc->sc_flags |= SC_OP_BEACONS;
-
-		/* Reset rssi stats */
-		sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
-		sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
-		sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
-		sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER;
-
-		/* Update chainmask */
-		ath_update_chainmask(sc, bss_conf->assoc_ht);
-
-		DPRINTF(sc, ATH_DBG_CONFIG,
-			"%s: bssid %s aid 0x%x\n",
-			__func__,
-			print_mac(mac, sc->sc_curbssid), sc->sc_curaid);
-
-		DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n",
-			__func__,
-			curchan->center_freq);
-
-		pos = ath_get_channel(sc, curchan);
-		if (pos == -1) {
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Invalid channel\n", __func__);
-			return;
-		}
-
-		if (hw->conf.ht_conf.ht_supported)
-			sc->sc_ah->ah_channels[pos].chanmode =
-				ath_get_extchanmode(sc, curchan);
-		else
-			sc->sc_ah->ah_channels[pos].chanmode =
-				(curchan->band == IEEE80211_BAND_2GHZ) ?
-				CHANNEL_G : CHANNEL_A;
-
-		/* set h/w channel */
-		if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0)
-			DPRINTF(sc, ATH_DBG_FATAL,
-				"%s: Unable to set channel\n",
-				__func__);
-
-		ath_rate_newstate(sc, avp);
-		/* Update ratectrl about the new state */
-		ath_rc_node_update(hw, avp->rc_node);
-	} else {
-		DPRINTF(sc, ATH_DBG_CONFIG,
-		"%s: Bss Info DISSOC\n", __func__);
-		sc->sc_curaid = 0;
-	}
-}
-
 static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
 				   struct ieee80211_vif *vif,
 				   struct ieee80211_bss_conf *bss_conf,
@@ -1048,364 +1657,6 @@ static struct ieee80211_ops ath9k_ops = {
 	.ampdu_action       = ath9k_ampdu_action
 };
 
-void ath_get_beaconconfig(struct ath_softc *sc,
-			  int if_id,
-			  struct ath_beacon_config *conf)
-{
-	struct ieee80211_hw *hw = sc->hw;
-
-	/* fill in beacon config data */
-
-	conf->beacon_interval = hw->conf.beacon_int;
-	conf->listen_interval = 100;
-	conf->dtim_count = 1;
-	conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
-}
-
-void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
-		     struct ath_xmit_status *tx_status, struct ath_node *an)
-{
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-
-	DPRINTF(sc, ATH_DBG_XMIT,
-		"%s: TX complete: skb: %p\n", __func__, skb);
-
-	if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
-		tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
-		/* free driver's private data area of tx_info */
-		if (tx_info->driver_data[0] != NULL)
-			kfree(tx_info->driver_data[0]);
-			tx_info->driver_data[0] = NULL;
-	}
-
-	if (tx_status->flags & ATH_TX_BAR) {
-		tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-		tx_status->flags &= ~ATH_TX_BAR;
-	}
-
-	if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) {
-		if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) {
-			/* Frame was not ACKed, but an ACK was expected */
-			tx_info->status.excessive_retries = 1;
-		}
-	} else {
-		/* Frame was ACKed */
-		tx_info->flags |= IEEE80211_TX_STAT_ACK;
-	}
-
-	tx_info->status.retry_count = tx_status->retries;
-
-	ieee80211_tx_status(hw, skb);
-	if (an)
-		ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE);
-}
-
-int _ath_rx_indicate(struct ath_softc *sc,
-		     struct sk_buff *skb,
-		     struct ath_recv_status *status,
-		     u16 keyix)
-{
-	struct ieee80211_hw *hw = sc->hw;
-	struct ath_node *an = NULL;
-	struct ieee80211_rx_status rx_status;
-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-	int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
-	int padsize;
-	enum ATH_RX_TYPE st;
-
-	/* see if any padding is done by the hw and remove it */
-	if (hdrlen & 3) {
-		padsize = hdrlen % 4;
-		memmove(skb->data + padsize, skb->data, hdrlen);
-		skb_pull(skb, padsize);
-	}
-
-	/* Prepare rx status */
-	ath9k_rx_prepare(sc, skb, status, &rx_status);
-
-	if (!(keyix == ATH9K_RXKEYIX_INVALID) &&
-	    !(status->flags & ATH_RX_DECRYPT_ERROR)) {
-		rx_status.flag |= RX_FLAG_DECRYPTED;
-	} else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED)
-		   && !(status->flags & ATH_RX_DECRYPT_ERROR)
-		   && skb->len >= hdrlen + 4) {
-		keyix = skb->data[hdrlen + 3] >> 6;
-
-		if (test_bit(keyix, sc->sc_keymap))
-			rx_status.flag |= RX_FLAG_DECRYPTED;
-	}
-
-	spin_lock_bh(&sc->node_lock);
-	an = ath_node_find(sc, hdr->addr2);
-	spin_unlock_bh(&sc->node_lock);
-
-	if (an) {
-		ath_rx_input(sc, an,
-			     hw->conf.ht_conf.ht_supported,
-			     skb, status, &st);
-	}
-	if (!an || (st != ATH_RX_CONSUMED))
-		__ieee80211_rx(hw, skb, &rx_status);
-
-	return 0;
-}
-
-int ath_rx_subframe(struct ath_node *an,
-		    struct sk_buff *skb,
-		    struct ath_recv_status *status)
-{
-	struct ath_softc *sc = an->an_sc;
-	struct ieee80211_hw *hw = sc->hw;
-	struct ieee80211_rx_status rx_status;
-
-	/* Prepare rx status */
-	ath9k_rx_prepare(sc, skb, status, &rx_status);
-	if (!(status->flags & ATH_RX_DECRYPT_ERROR))
-		rx_status.flag |= RX_FLAG_DECRYPTED;
-
-	__ieee80211_rx(hw, skb, &rx_status);
-
-	return 0;
-}
-
-/********************************/
-/*	 LED functions		*/
-/********************************/
-
-static void ath_led_brightness(struct led_classdev *led_cdev,
-			       enum led_brightness brightness)
-{
-	struct ath_led *led = container_of(led_cdev, struct ath_led, led_cdev);
-	struct ath_softc *sc = led->sc;
-
-	switch (brightness) {
-	case LED_OFF:
-		if (led->led_type == ATH_LED_ASSOC ||
-		    led->led_type == ATH_LED_RADIO)
-			sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
-		ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN,
-				(led->led_type == ATH_LED_RADIO) ? 1 :
-				!!(sc->sc_flags & SC_OP_LED_ASSOCIATED));
-		break;
-	case LED_FULL:
-		if (led->led_type == ATH_LED_ASSOC)
-			sc->sc_flags |= SC_OP_LED_ASSOCIATED;
-		ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 0);
-		break;
-	default:
-		break;
-	}
-}
-
-static int ath_register_led(struct ath_softc *sc, struct ath_led *led,
-			    char *trigger)
-{
-	int ret;
-
-	led->sc = sc;
-	led->led_cdev.name = led->name;
-	led->led_cdev.default_trigger = trigger;
-	led->led_cdev.brightness_set = ath_led_brightness;
-
-	ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &led->led_cdev);
-	if (ret)
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"Failed to register led:%s", led->name);
-	else
-		led->registered = 1;
-	return ret;
-}
-
-static void ath_unregister_led(struct ath_led *led)
-{
-	if (led->registered) {
-		led_classdev_unregister(&led->led_cdev);
-		led->registered = 0;
-	}
-}
-
-static void ath_deinit_leds(struct ath_softc *sc)
-{
-	ath_unregister_led(&sc->assoc_led);
-	sc->sc_flags &= ~SC_OP_LED_ASSOCIATED;
-	ath_unregister_led(&sc->tx_led);
-	ath_unregister_led(&sc->rx_led);
-	ath_unregister_led(&sc->radio_led);
-	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
-}
-
-static void ath_init_leds(struct ath_softc *sc)
-{
-	char *trigger;
-	int ret;
-
-	/* Configure gpio 1 for output */
-	ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
-			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
-	/* LED off, active low */
-	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
-
-	trigger = ieee80211_get_radio_led_name(sc->hw);
-	snprintf(sc->radio_led.name, sizeof(sc->radio_led.name),
-		"ath9k-%s:radio", wiphy_name(sc->hw->wiphy));
-	ret = ath_register_led(sc, &sc->radio_led, trigger);
-	sc->radio_led.led_type = ATH_LED_RADIO;
-	if (ret)
-		goto fail;
-
-	trigger = ieee80211_get_assoc_led_name(sc->hw);
-	snprintf(sc->assoc_led.name, sizeof(sc->assoc_led.name),
-		"ath9k-%s:assoc", wiphy_name(sc->hw->wiphy));
-	ret = ath_register_led(sc, &sc->assoc_led, trigger);
-	sc->assoc_led.led_type = ATH_LED_ASSOC;
-	if (ret)
-		goto fail;
-
-	trigger = ieee80211_get_tx_led_name(sc->hw);
-	snprintf(sc->tx_led.name, sizeof(sc->tx_led.name),
-		"ath9k-%s:tx", wiphy_name(sc->hw->wiphy));
-	ret = ath_register_led(sc, &sc->tx_led, trigger);
-	sc->tx_led.led_type = ATH_LED_TX;
-	if (ret)
-		goto fail;
-
-	trigger = ieee80211_get_rx_led_name(sc->hw);
-	snprintf(sc->rx_led.name, sizeof(sc->rx_led.name),
-		"ath9k-%s:rx", wiphy_name(sc->hw->wiphy));
-	ret = ath_register_led(sc, &sc->rx_led, trigger);
-	sc->rx_led.led_type = ATH_LED_RX;
-	if (ret)
-		goto fail;
-
-	return;
-
-fail:
-	ath_deinit_leds(sc);
-}
-
-static int ath_detach(struct ath_softc *sc)
-{
-	struct ieee80211_hw *hw = sc->hw;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__);
-
-	/* Deinit LED control */
-	ath_deinit_leds(sc);
-
-	/* Unregister hw */
-
-	ieee80211_unregister_hw(hw);
-
-	/* unregister Rate control */
-	ath_rate_control_unregister();
-
-	/* tx/rx cleanup */
-
-	ath_rx_cleanup(sc);
-	ath_tx_cleanup(sc);
-
-	/* Deinit */
-
-	ath_deinit(sc);
-
-	return 0;
-}
-
-static int ath_attach(u16 devid,
-		      struct ath_softc *sc)
-{
-	struct ieee80211_hw *hw = sc->hw;
-	int error = 0;
-
-	DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__);
-
-	error = ath_init(devid, sc);
-	if (error != 0)
-		return error;
-
-	/* Init nodes */
-
-	INIT_LIST_HEAD(&sc->node_list);
-	spin_lock_init(&sc->node_lock);
-
-	/* get mac address from hardware and set in mac80211 */
-
-	SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr);
-
-	/* setup channels and rates */
-
-	sc->sbands[IEEE80211_BAND_2GHZ].channels =
-		sc->channels[IEEE80211_BAND_2GHZ];
-	sc->sbands[IEEE80211_BAND_2GHZ].bitrates =
-		sc->rates[IEEE80211_BAND_2GHZ];
-	sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ;
-
-	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-		/* Setup HT capabilities for 2.4Ghz*/
-		setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info);
-
-	hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-		&sc->sbands[IEEE80211_BAND_2GHZ];
-
-	if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) {
-		sc->sbands[IEEE80211_BAND_5GHZ].channels =
-			sc->channels[IEEE80211_BAND_5GHZ];
-		sc->sbands[IEEE80211_BAND_5GHZ].bitrates =
-			sc->rates[IEEE80211_BAND_5GHZ];
-		sc->sbands[IEEE80211_BAND_5GHZ].band =
-			IEEE80211_BAND_5GHZ;
-
-		if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)
-			/* Setup HT capabilities for 5Ghz*/
-			setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info);
-
-		hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-			&sc->sbands[IEEE80211_BAND_5GHZ];
-	}
-
-	/* FIXME: Have to figure out proper hw init values later */
-
-	hw->queues = 4;
-	hw->ampdu_queues = 1;
-
-	/* Register rate control */
-	hw->rate_control_algorithm = "ath9k_rate_control";
-	error = ath_rate_control_register();
-	if (error != 0) {
-		DPRINTF(sc, ATH_DBG_FATAL,
-			"%s: Unable to register rate control "
-			"algorithm:%d\n", __func__, error);
-		ath_rate_control_unregister();
-		goto bad;
-	}
-
-	error = ieee80211_register_hw(hw);
-	if (error != 0) {
-		ath_rate_control_unregister();
-		goto bad;
-	}
-
-	/* Initialize LED control */
-	ath_init_leds(sc);
-
-	/* initialize tx/rx engine */
-
-	error = ath_tx_init(sc, ATH_TXBUF);
-	if (error != 0)
-		goto detach;
-
-	error = ath_rx_init(sc, ATH_RXBUF);
-	if (error != 0)
-		goto detach;
-
-	return 0;
-detach:
-	ath_detach(sc);
-bad:
-	return error;
-}
-
 static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	void __iomem *mem;
@@ -1554,6 +1805,12 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 	struct ath_softc *sc = hw->priv;
 
 	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+
+#ifdef CONFIG_RFKILL
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
+
 	pci_save_state(pdev);
 	pci_disable_device(pdev);
 	pci_set_power_state(pdev, 3);
@@ -1586,6 +1843,16 @@ static int ath_pci_resume(struct pci_dev *pdev)
 			    AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
 	ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 
+#ifdef CONFIG_RFKILL
+	/*
+	 * check the h/w rfkill state on resume
+	 * and start the rfkill poll timer
+	 */
+	if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+		queue_delayed_work(sc->hw->workqueue,
+				   &sc->rf_kill.rfkill_poll, 0);
+#endif
+
 	return 0;
 }
 
-- 
1.5.5.1


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] ath9k: Add RF kill support
  2008-09-09 15:34 [PATCH] ath9k: " Vasanthakumar Thiagarajan
@ 2008-09-09 15:42 ` Johannes Berg
  2008-09-09 16:22   ` vasanthakumar thiagarajan
  2008-09-09 15:46 ` Johannes Berg
  2008-09-09 16:19 ` Henrique de Moraes Holschuh
  2 siblings, 1 reply; 25+ messages in thread
From: Johannes Berg @ 2008-09-09 15:42 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan
  Cc: linville, linux-wireless, Jouni Malinen, Luis Rodriguez

[-- Attachment #1: Type: text/plain, Size: 359 bytes --]

On Tue, 2008-09-09 at 21:04 +0530, Vasanthakumar Thiagarajan wrote:
> This support is compiled in if CONFIG_RFKILL
> option is set.

> +++ b/drivers/net/wireless/ath9k/Kconfig
> @@ -4,6 +4,7 @@ config ATH9K
>  	select MAC80211_LEDS
>  	select LEDS_CLASS
>  	select NEW_LEDS
> +	select RFKILL

You really want to drop that then though.

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] ath9k: Add RF kill support
  2008-09-09 15:34 [PATCH] ath9k: " Vasanthakumar Thiagarajan
  2008-09-09 15:42 ` Johannes Berg
@ 2008-09-09 15:46 ` Johannes Berg
  2008-09-09 16:02   ` vasanthakumar thiagarajan
  2008-09-09 16:19 ` Henrique de Moraes Holschuh
  2 siblings, 1 reply; 25+ messages in thread
From: Johannes Berg @ 2008-09-09 15:46 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan
  Cc: linville, linux-wireless, Jouni Malinen, Luis Rodriguez

[-- Attachment #1: Type: text/plain, Size: 1239 bytes --]


> +#ifdef CONFIG_RFKILL
> +	u16 ah_rfsilent;
> +	u32 ah_rfkill_gpio ;

small typo, space too much.

> --- a/drivers/net/wireless/ath9k/core.h
> +++ b/drivers/net/wireless/ath9k/core.h
> @@ -40,6 +40,9 @@
>  #include <asm/page.h>
>  #include <net/mac80211.h>
>  #include <linux/leds.h>
> +#ifdef CONFIG_RFKILL
> +#include <linux/rfkill.h>
> +#endif
>  
>  #include "ath9k.h"
>  #include "rc.h"
> @@ -823,6 +826,17 @@ struct ath_led {
>  	bool registered;
>  };
>  
> +#ifdef CONFIG_RFKILL
> +/* Rfkill */
> +#define ATH_RFKILL_POLL_INTERVAL	2000 /* msecs */
> +
> +struct ath_rfkill {
> +	struct rfkill *rfkill;
> +	struct delayed_work rfkill_poll;
> +	char rfkill_name[32];
> +};
> +#endif
> +

No need to protect any of this with an #ifdef.

> +#ifdef CONFIG_RFKILL
> +#define SC_OP_RFKILL_REGISTERED	BIT(11)
> +#define SC_OP_RFKILL_SW_BLOCKED	BIT(12)
> +#define SC_OP_RFKILL_HW_BLOCKED	BIT(13)
> +#endif

Nor that.
 
> +static void ath9k_ht_conf(struct ath_softc *sc,
> +			  struct ieee80211_bss_conf *bss_conf)
> +{
> +#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14)
> +	struct ath_ht_info *ht_info = &sc->sc_ht_info;

All that doesn't seem to belong into this patch?

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] ath9k: Add RF kill support
  2008-09-09 15:46 ` Johannes Berg
@ 2008-09-09 16:02   ` vasanthakumar thiagarajan
  2008-09-09 16:15     ` Henrique de Moraes Holschuh
  0 siblings, 1 reply; 25+ messages in thread
From: vasanthakumar thiagarajan @ 2008-09-09 16:02 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org,
	Jouni Malinen, Luis Rodriguez

Johannes Berg wrote:
>> +#ifdef CONFIG_RFKILL
>> +	u16 ah_rfsilent;
>> +	u32 ah_rfkill_gpio ;
>>     
>
> small typo, space too much.
>
>   
ok, thanks.
>> --- a/drivers/net/wireless/ath9k/core.h
>> +++ b/drivers/net/wireless/ath9k/core.h
>> @@ -40,6 +40,9 @@
>>  #include <asm/page.h>
>>  #include <net/mac80211.h>
>>  #include <linux/leds.h>
>> +#ifdef CONFIG_RFKILL
>> +#include <linux/rfkill.h>
>> +#endif
>>  
>>  #include "ath9k.h"
>>  #include "rc.h"
>> @@ -823,6 +826,17 @@ struct ath_led {
>>  	bool registered;
>>  };
>>  
>> +#ifdef CONFIG_RFKILL
>> +/* Rfkill */
>> +#define ATH_RFKILL_POLL_INTERVAL	2000 /* msecs */
>> +
>> +struct ath_rfkill {
>> +	struct rfkill *rfkill;
>> +	struct delayed_work rfkill_poll;
>> +	char rfkill_name[32];
>> +};
>> +#endif
>> +
>>     
>
> No need to protect any of this with an #ifdef.
>
>   
>> +#ifdef CONFIG_RFKILL
>> +#define SC_OP_RFKILL_REGISTERED	BIT(11)
>> +#define SC_OP_RFKILL_SW_BLOCKED	BIT(12)
>> +#define SC_OP_RFKILL_HW_BLOCKED	BIT(13)
>> +#endif
>>     
>
> Nor that.
>  
>   
ok.
>> +static void ath9k_ht_conf(struct ath_softc *sc,
>> +			  struct ieee80211_bss_conf *bss_conf)
>> +{
>> +#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14)
>> +	struct ath_ht_info *ht_info = &sc->sc_ht_info;
>>     
>
> All that doesn't seem to belong into this patch?
>
> johannes
>   
I just rearranged (purely change in the location of few static functions
in the file) the code to avoid
the prototype declaration of the functions which are called (before
their definition) in case of any
failure during rfkill_register().

Thanks for your comments.

Regards

Vasanth


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] ath9k: Add RF kill support
  2008-09-09 16:15     ` Henrique de Moraes Holschuh
@ 2008-09-09 16:15       ` vasanthakumar thiagarajan
  0 siblings, 0 replies; 25+ messages in thread
From: vasanthakumar thiagarajan @ 2008-09-09 16:15 UTC (permalink / raw)
  To: Henrique de Moraes Holschuh
  Cc: Johannes Berg, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org, Jouni Malinen, Luis Rodriguez

Henrique de Moraes Holschuh wrote:
> On Tue, 09 Sep 2008, vasanthakumar thiagarajan wrote:
>   
>> I just rearranged (purely change in the location of few static functions
>> in the file) the code to avoid
>> the prototype declaration of the functions which are called (before
>> their definition) in case of any
>> failure during rfkill_register().
>>     
>
> That's much better done in two patches.
>
> The first patch should just move code around without changing *anything*.
> You can check the resulting binary to be sure you didn't change any code by
> mistake.
>
> The second patch does the real code changes.
>
> --
>   "One disk to rule them all, One disk to find them. One disk to bring
>   them all and in the darkness grind them. In the Land of Redmond
>   where the shadows lie." -- The Silicon Valley Tarot
>   Henrique Holschuh
>   
Yeah, I got it. Thanks.

Vasanth



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] ath9k: Add RF kill support
  2008-09-09 16:02   ` vasanthakumar thiagarajan
@ 2008-09-09 16:15     ` Henrique de Moraes Holschuh
  2008-09-09 16:15       ` vasanthakumar thiagarajan
  0 siblings, 1 reply; 25+ messages in thread
From: Henrique de Moraes Holschuh @ 2008-09-09 16:15 UTC (permalink / raw)
  To: vasanthakumar thiagarajan
  Cc: Johannes Berg, linville@tuxdriver.com,
	linux-wireless@vger.kernel.org, Jouni Malinen, Luis Rodriguez

On Tue, 09 Sep 2008, vasanthakumar thiagarajan wrote:
> I just rearranged (purely change in the location of few static functions
> in the file) the code to avoid
> the prototype declaration of the functions which are called (before
> their definition) in case of any
> failure during rfkill_register().

That's much better done in two patches.

The first patch should just move code around without changing *anything*.
You can check the resulting binary to be sure you didn't change any code by
mistake.

The second patch does the real code changes.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] ath9k: Add RF kill support
  2008-09-09 15:34 [PATCH] ath9k: " Vasanthakumar Thiagarajan
  2008-09-09 15:42 ` Johannes Berg
  2008-09-09 15:46 ` Johannes Berg
@ 2008-09-09 16:19 ` Henrique de Moraes Holschuh
  2 siblings, 0 replies; 25+ messages in thread
From: Henrique de Moraes Holschuh @ 2008-09-09 16:19 UTC (permalink / raw)
  To: Vasanthakumar Thiagarajan
  Cc: linville, linux-wireless, Jouni Malinen, Luis Rodriguez

This is much better, the rfkill bits seem fine at first glance.

-- 
  "One disk to rule them all, One disk to find them. One disk to bring
  them all and in the darkness grind them. In the Land of Redmond
  where the shadows lie." -- The Silicon Valley Tarot
  Henrique Holschuh

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] ath9k: Add RF kill support
  2008-09-09 15:42 ` Johannes Berg
@ 2008-09-09 16:22   ` vasanthakumar thiagarajan
  0 siblings, 0 replies; 25+ messages in thread
From: vasanthakumar thiagarajan @ 2008-09-09 16:22 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linville@tuxdriver.com, linux-wireless@vger.kernel.org,
	Jouni Malinen, Luis Rodriguez

Johannes Berg wrote:
> On Tue, 2008-09-09 at 21:04 +0530, Vasanthakumar Thiagarajan wrote:
>   
>> This support is compiled in if CONFIG_RFKILL
>> option is set.
>>     
>
>   
>> +++ b/drivers/net/wireless/ath9k/Kconfig
>> @@ -4,6 +4,7 @@ config ATH9K
>>  	select MAC80211_LEDS
>>  	select LEDS_CLASS
>>  	select NEW_LEDS
>> +	select RFKILL
>>     
>
> You really want to drop that then though.
>
> johannes
>   
Yeah, I missed this one. Thanks.

Vasanth

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2008-09-09 16:29 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-06 12:38 [PATCH] Ath9k: Add RF kill support Vasanthakumar Thiagarajan
2008-09-06 17:15 ` Marcel Holtmann
2008-09-06 17:19   ` Johannes Berg
2008-09-06 17:23     ` Johannes Berg
2008-09-07  1:00       ` Marcel Holtmann
2008-09-07  7:17         ` Johannes Berg
2008-09-07 11:56           ` Henrique de Moraes Holschuh
2008-09-07 12:40             ` Johannes Berg
2008-09-07  0:57     ` Marcel Holtmann
2008-09-08  4:59   ` Vasanthakumar Thiagarajan
2008-09-08  5:22     ` Marcel Holtmann
2008-09-08  5:38       ` Vasanthakumar Thiagarajan
2008-09-08 15:10     ` Henrique de Moraes Holschuh
2008-09-09  7:53       ` vasanthakumar thiagarajan
2008-09-07 12:09 ` Henrique de Moraes Holschuh
2008-09-08  5:20   ` Vasanthakumar Thiagarajan
  -- strict thread matches above, loose matches on Subject: below --
2008-09-09  5:33 Mats Johannesson
2008-09-09 15:34 [PATCH] ath9k: " Vasanthakumar Thiagarajan
2008-09-09 15:42 ` Johannes Berg
2008-09-09 16:22   ` vasanthakumar thiagarajan
2008-09-09 15:46 ` Johannes Berg
2008-09-09 16:02   ` vasanthakumar thiagarajan
2008-09-09 16:15     ` Henrique de Moraes Holschuh
2008-09-09 16:15       ` vasanthakumar thiagarajan
2008-09-09 16:19 ` Henrique de Moraes Holschuh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).