瀏覽代碼

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-2.6

David S. Miller 17 年之前
父節點
當前提交
e9e80ea5f2

+ 1 - 0
drivers/net/wireless/Kconfig

@@ -649,6 +649,7 @@ config RTL8187
 	  Trendnet TEW-424UB
 	  Trendnet TEW-424UB
 	  ASUS P5B Deluxe
 	  ASUS P5B Deluxe
 	  Toshiba Satellite Pro series of laptops
 	  Toshiba Satellite Pro series of laptops
+	  Asus Wireless Link
 
 
 	  Thanks to Realtek for their support!
 	  Thanks to Realtek for their support!
 
 

+ 5 - 3
drivers/net/wireless/ath5k/ath5k.h

@@ -186,11 +186,13 @@ struct ath5k_srev_name {
 #define AR5K_SREV_RAD_2111	0x20
 #define AR5K_SREV_RAD_2111	0x20
 #define AR5K_SREV_RAD_5112	0x30
 #define AR5K_SREV_RAD_5112	0x30
 #define AR5K_SREV_RAD_5112A	0x35
 #define AR5K_SREV_RAD_5112A	0x35
+#define	AR5K_SREV_RAD_5112B	0x36
 #define AR5K_SREV_RAD_2112	0x40
 #define AR5K_SREV_RAD_2112	0x40
 #define AR5K_SREV_RAD_2112A	0x45
 #define AR5K_SREV_RAD_2112A	0x45
-#define AR5K_SREV_RAD_SC0	0x56	/* Found on 2413/2414 */
-#define AR5K_SREV_RAD_SC1	0x63	/* Found on 5413/5414 */
-#define AR5K_SREV_RAD_SC2	0xa2	/* Found on 2424-5/5424 */
+#define	AR5K_SREV_RAD_2112B	0x46
+#define AR5K_SREV_RAD_SC0	0x50	/* Found on 2413/2414 */
+#define AR5K_SREV_RAD_SC1	0x60	/* Found on 5413/5414 */
+#define AR5K_SREV_RAD_SC2	0xa0	/* Found on 2424-5/5424 */
 #define AR5K_SREV_RAD_5133	0xc0	/* MIMO found on 5418 */
 #define AR5K_SREV_RAD_5133	0xc0	/* MIMO found on 5418 */
 
 
 /* IEEE defs */
 /* IEEE defs */

+ 1 - 0
drivers/net/wireless/ath5k/base.c

@@ -2170,6 +2170,7 @@ ath5k_beacon_config(struct ath5k_softc *sc)
 
 
 	ath5k_hw_set_intr(ah, 0);
 	ath5k_hw_set_intr(ah, 0);
 	sc->bmisscount = 0;
 	sc->bmisscount = 0;
+	sc->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
 
 
 	if (sc->opmode == IEEE80211_IF_TYPE_STA) {
 	if (sc->opmode == IEEE80211_IF_TYPE_STA) {
 		sc->imask |= AR5K_INT_BMISS;
 		sc->imask |= AR5K_INT_BMISS;

+ 1 - 1
drivers/net/wireless/ath5k/debug.c

@@ -129,7 +129,7 @@ static struct reg regs[] = {
 	REG_STRUCT_INIT(AR5K_CPC1),
 	REG_STRUCT_INIT(AR5K_CPC1),
 	REG_STRUCT_INIT(AR5K_CPC2),
 	REG_STRUCT_INIT(AR5K_CPC2),
 	REG_STRUCT_INIT(AR5K_CPC3),
 	REG_STRUCT_INIT(AR5K_CPC3),
-	REG_STRUCT_INIT(AR5K_CPCORN),
+	REG_STRUCT_INIT(AR5K_CPCOVF),
 	REG_STRUCT_INIT(AR5K_RESET_CTL),
 	REG_STRUCT_INIT(AR5K_RESET_CTL),
 	REG_STRUCT_INIT(AR5K_SLEEP_CTL),
 	REG_STRUCT_INIT(AR5K_SLEEP_CTL),
 	REG_STRUCT_INIT(AR5K_INTPEND),
 	REG_STRUCT_INIT(AR5K_INTPEND),

+ 0 - 1
drivers/net/wireless/ath5k/debug.h

@@ -63,7 +63,6 @@
 
 
 struct ath5k_softc;
 struct ath5k_softc;
 struct ath5k_hw;
 struct ath5k_hw;
-struct ieee80211_hw_mode;
 struct sk_buff;
 struct sk_buff;
 struct ath5k_buf;
 struct ath5k_buf;
 
 

+ 149 - 90
drivers/net/wireless/ath5k/hw.c

@@ -139,6 +139,8 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
 	for (c = 0; c < 2; c++) {
 	for (c = 0; c < 2; c++) {
 
 
 		cur_reg = regs[c];
 		cur_reg = regs[c];
+
+		/* Save previous value */
 		init_val = ath5k_hw_reg_read(ah, cur_reg);
 		init_val = ath5k_hw_reg_read(ah, cur_reg);
 
 
 		for (i = 0; i < 256; i++) {
 		for (i = 0; i < 256; i++) {
@@ -170,6 +172,10 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
 			var_pattern = 0x003b080f;
 			var_pattern = 0x003b080f;
 			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
 			ath5k_hw_reg_write(ah, var_pattern, cur_reg);
 		}
 		}
+
+		/* Restore previous value */
+		ath5k_hw_reg_write(ah, init_val, cur_reg);
+
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -287,67 +293,42 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
 	/* Identify the radio chip*/
 	/* Identify the radio chip*/
 	if (ah->ah_version == AR5K_AR5210) {
 	if (ah->ah_version == AR5K_AR5210) {
 		ah->ah_radio = AR5K_RF5110;
 		ah->ah_radio = AR5K_RF5110;
+	/*
+	 * Register returns 0x0/0x04 for radio revision
+	 * so ath5k_hw_radio_revision doesn't parse the value
+	 * correctly. For now we are based on mac's srev to
+	 * identify RF2425 radio.
+	 */
+	} else if (srev == AR5K_SREV_VER_AR2425) {
+		ah->ah_radio = AR5K_RF2425;
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2425;
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) {
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112) {
 		ah->ah_radio = AR5K_RF5111;
 		ah->ah_radio = AR5K_RF5111;
 		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
 		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5111;
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) {
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC0) {
-
 		ah->ah_radio = AR5K_RF5112;
 		ah->ah_radio = AR5K_RF5112;
-
-		if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5112A) {
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
-		} else {
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
-		}
-
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC1) {
 		ah->ah_radio = AR5K_RF2413;
 		ah->ah_radio = AR5K_RF2413;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) {
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_SC2) {
 		ah->ah_radio = AR5K_RF5413;
 		ah->ah_radio = AR5K_RF5413;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) {
 	} else if (ah->ah_radio_5ghz_revision < AR5K_SREV_RAD_5133) {
-
 		/* AR5424 */
 		/* AR5424 */
 		if (srev >= AR5K_SREV_VER_AR5424) {
 		if (srev >= AR5K_SREV_VER_AR5424) {
 			ah->ah_radio = AR5K_RF5413;
 			ah->ah_radio = AR5K_RF5413;
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5424;
+			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5413;
 		/* AR2424 */
 		/* AR2424 */
 		} else {
 		} else {
 			ah->ah_radio = AR5K_RF2413; /* For testing */
 			ah->ah_radio = AR5K_RF2413; /* For testing */
-			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112A;
+			ah->ah_phy_spending = AR5K_PHY_SPENDING_RF2413;
 		}
 		}
-
-	/*
-	 * Register returns 0x4 for radio revision
-	 * so ath5k_hw_radio_revision doesn't parse the value
-	 * correctly. For now we are based on mac's srev to
-	 * identify RF2425 radio.
-	 */
-	} else if (srev == AR5K_SREV_VER_AR2425) {
-		ah->ah_radio = AR5K_RF2425;
-		ah->ah_phy_spending = AR5K_PHY_SPENDING_RF5112;
 	}
 	}
-
 	ah->ah_phy = AR5K_PHY(0);
 	ah->ah_phy = AR5K_PHY(0);
 
 
 	/*
 	/*
-	 * Identify AR5212-based PCI-E cards
-	 * And write some initial settings.
-	 *
-	 * (doing a "strings" on ndis driver
-	 * -ar5211.sys- reveals the following
-	 * pci-e related functions:
-	 *
-	 * pcieClockReq
-	 * pcieRxErrNotify
-	 * pcieL1SKPEnable
-	 * pcieAspm
-	 * pcieDisableAspmOnRfWake
-	 * pciePowerSaveEnable
-	 *
-	 * I guess these point to ClockReq but
-	 * i'm not sure.)
+	 * Write PCI-E power save settings
 	 */
 	 */
 	if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
 	if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
 		ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080);
 		ath5k_hw_reg_write(ah, 0x9248fc00, 0x4080);
@@ -369,10 +350,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
 	if (ret)
 	if (ret)
 		goto err_free;
 		goto err_free;
 
 
+	/* Write AR5K_PCICFG_UNK on 2112B and later chips */
+	if (ah->ah_radio_5ghz_revision > AR5K_SREV_RAD_2112B ||
+	srev > AR5K_SREV_VER_AR2413) {
+		ath5k_hw_reg_write(ah, AR5K_PCICFG_UNK, AR5K_PCICFG);
+	}
+
 	/*
 	/*
 	 * Get card capabilities, values, ...
 	 * Get card capabilities, values, ...
 	 */
 	 */
-
 	ret = ath5k_eeprom_init(ah);
 	ret = ath5k_eeprom_init(ah);
 	if (ret) {
 	if (ret) {
 		ATH5K_ERR(sc, "unable to init EEPROM\n");
 		ATH5K_ERR(sc, "unable to init EEPROM\n");
@@ -843,27 +829,41 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
 		 * Write some more initial register settings
 		 * Write some more initial register settings
 		 */
 		 */
 		if (ah->ah_version == AR5K_AR5212) {
 		if (ah->ah_version == AR5K_AR5212) {
-			ath5k_hw_reg_write(ah, 0x0002a002, AR5K_PHY(11));
+			ath5k_hw_reg_write(ah, 0x0002a002, 0x982c);
 
 
 			if (channel->hw_value == CHANNEL_G)
 			if (channel->hw_value == CHANNEL_G)
 				if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413)
 				if (ah->ah_mac_srev < AR5K_SREV_VER_AR2413)
 					ath5k_hw_reg_write(ah, 0x00f80d80,
 					ath5k_hw_reg_write(ah, 0x00f80d80,
-						AR5K_PHY(83));
+								0x994c);
 				else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424)
 				else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2424)
 					ath5k_hw_reg_write(ah, 0x00380140,
 					ath5k_hw_reg_write(ah, 0x00380140,
-						AR5K_PHY(83));
+								0x994c);
 				else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425)
 				else if (ah->ah_mac_srev < AR5K_SREV_VER_AR2425)
 					ath5k_hw_reg_write(ah, 0x00fc0ec0,
 					ath5k_hw_reg_write(ah, 0x00fc0ec0,
-						AR5K_PHY(83));
+								0x994c);
 				else /* 2425 */
 				else /* 2425 */
 					ath5k_hw_reg_write(ah, 0x00fc0fc0,
 					ath5k_hw_reg_write(ah, 0x00fc0fc0,
-						AR5K_PHY(83));
+								0x994c);
 			else
 			else
-				ath5k_hw_reg_write(ah, 0x00000000,
-					AR5K_PHY(83));
-
-			ath5k_hw_reg_write(ah, 0x000009b5, 0xa228);
-			ath5k_hw_reg_write(ah, 0x0000000f, 0x8060);
+				ath5k_hw_reg_write(ah, 0x00000000, 0x994c);
+
+			/* Some bits are disabled here, we know nothing about
+			 * register 0xa228 yet, most of the times this ends up
+			 * with a value 0x9b5 -haven't seen any dump with
+			 * a different value- */
+			/* Got this from decompiling binary HAL */
+			data = ath5k_hw_reg_read(ah, 0xa228);
+			data &= 0xfffffdff;
+			ath5k_hw_reg_write(ah, data, 0xa228);
+
+			data = ath5k_hw_reg_read(ah, 0xa228);
+			data &= 0xfffe03ff;
+			ath5k_hw_reg_write(ah, data, 0xa228);
+			data = 0;
+
+			/* Just write 0x9b5 ? */
+			/* ath5k_hw_reg_write(ah, 0x000009b5, 0xa228); */
+			ath5k_hw_reg_write(ah, 0x0000000f, AR5K_SEQ_MASK);
 			ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
 			ath5k_hw_reg_write(ah, 0x00000000, 0xa254);
 			ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
 			ath5k_hw_reg_write(ah, 0x0000000e, AR5K_PHY_SCAL);
 		}
 		}
@@ -879,6 +879,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
 			else
 			else
 				data = 0xffb80d20;
 				data = 0xffb80d20;
 			ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
 			ath5k_hw_reg_write(ah, data, AR5K_PHY_FRAME_CTL);
+			data = 0;
 		}
 		}
 
 
 		/*
 		/*
@@ -898,7 +899,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
 
 
 		/*
 		/*
 		 * Write RF registers
 		 * Write RF registers
-		 * TODO:Does this work on 5211 (5111) ?
 		 */
 		 */
 		ret = ath5k_hw_rfregs(ah, channel, mode);
 		ret = ath5k_hw_rfregs(ah, channel, mode);
 		if (ret)
 		if (ret)
@@ -935,7 +935,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
 			return ret;
 			return ret;
 
 
 		/* Set antenna mode */
 		/* Set antenna mode */
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x44),
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_ANT_CTL,
 			ah->ah_antenna[ee_mode][0], 0xfffffc06);
 			ah->ah_antenna[ee_mode][0], 0xfffffc06);
 
 
 		/*
 		/*
@@ -965,15 +965,15 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
 
 
 		ath5k_hw_reg_write(ah,
 		ath5k_hw_reg_write(ah,
 			AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
 			AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
-			AR5K_PHY(0x5a));
+			AR5K_PHY_NFTHRES);
 
 
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x11),
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_SETTLING,
 			(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
 			(ee->ee_switch_settling[ee_mode] << 7) & 0x3f80,
 			0xffffc07f);
 			0xffffc07f);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x12),
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN,
 			(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
 			(ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000,
 			0xfffc0fff);
 			0xfffc0fff);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x14),
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE,
 			(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
 			(ee->ee_adc_desired_size[ee_mode] & 0x00ff) |
 			((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
 			((ee->ee_pga_desired_size[ee_mode] << 8) & 0xff00),
 			0xffff0000);
 			0xffff0000);
@@ -982,13 +982,13 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
 			(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
 			(ee->ee_tx_end2xpa_disable[ee_mode] << 24) |
 			(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
 			(ee->ee_tx_end2xpa_disable[ee_mode] << 16) |
 			(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
 			(ee->ee_tx_frm2xpa_enable[ee_mode] << 8) |
-			(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY(0x0d));
+			(ee->ee_tx_frm2xpa_enable[ee_mode]), AR5K_PHY_RF_CTL4);
 
 
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x0a),
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_RF_CTL3,
 			ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
 			ee->ee_tx_end2xlna_enable[ee_mode] << 8, 0xffff00ff);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x19),
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_NF,
 			(ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
 			(ee->ee_thr_62[ee_mode] << 12) & 0x7f000, 0xfff80fff);
-		AR5K_REG_MASKED_BITS(ah, AR5K_PHY(0x49), 4, 0xffffff01);
+		AR5K_REG_MASKED_BITS(ah, AR5K_PHY_OFDM_SELFCORR, 4, 0xffffff01);
 
 
 		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
 		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
 		    AR5K_PHY_IQ_CORR_ENABLE |
 		    AR5K_PHY_IQ_CORR_ENABLE |
@@ -1063,7 +1063,8 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
 	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
 	ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
 
 
 	/*
 	/*
-	 * 5111/5112 Specific
+	 * On 5211+ read activation -> rx delay
+	 * and use it.
 	 */
 	 */
 	if (ah->ah_version != AR5K_AR5210) {
 	if (ah->ah_version != AR5K_AR5210) {
 		data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
 		data = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
@@ -1071,40 +1072,77 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
 		data = (channel->hw_value & CHANNEL_CCK) ?
 		data = (channel->hw_value & CHANNEL_CCK) ?
 			((data << 2) / 22) : (data / 10);
 			((data << 2) / 22) : (data / 10);
 
 
-		udelay(100 + data);
+		udelay(100 + (2 * data));
+		data = 0;
 	} else {
 	} else {
 		mdelay(1);
 		mdelay(1);
 	}
 	}
 
 
 	/*
 	/*
-	 * Enable calibration and wait until completion
+	 * Perform ADC test (?)
+	 */
+	data = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+	ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
+	for (i = 0; i <= 20; i++) {
+		if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
+			break;
+		udelay(200);
+	}
+	ath5k_hw_reg_write(ah, data, AR5K_PHY_TST1);
+	data = 0;
+
+	/*
+	 * Start automatic gain calibration
+	 *
+	 * During AGC calibration RX path is re-routed to
+	 * a signal detector so we don't receive anything.
+	 *
+	 * This method is used to calibrate some static offsets
+	 * used together with on-the fly I/Q calibration (the
+	 * one performed via ath5k_hw_phy_calibrate), that doesn't
+	 * interrupt rx path.
+	 *
+	 * If we are in a noisy environment AGC calibration may time
+	 * out.
 	 */
 	 */
 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
 				AR5K_PHY_AGCCTL_CAL);
 				AR5K_PHY_AGCCTL_CAL);
 
 
+	/* At the same time start I/Q calibration for QAM constellation
+	 * -no need for CCK- */
+	ah->ah_calibration = false;
+	if (!(mode == AR5K_MODE_11B)) {
+		ah->ah_calibration = true;
+		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+				AR5K_PHY_IQ_RUN);
+	}
+
+	/* Wait for gain calibration to finish (we check for I/Q calibration
+	 * during ath5k_phy_calibrate) */
 	if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
 	if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
 			AR5K_PHY_AGCCTL_CAL, 0, false)) {
 			AR5K_PHY_AGCCTL_CAL, 0, false)) {
-		ATH5K_ERR(ah->ah_sc, "calibration timeout (%uMHz)\n",
+		ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
 			channel->center_freq);
 			channel->center_freq);
 		return -EAGAIN;
 		return -EAGAIN;
 	}
 	}
 
 
+	/*
+	 * Start noise floor calibration
+	 *
+	 * If we run NF calibration before AGC, it always times out.
+	 * Binary HAL starts NF and AGC calibration at the same time
+	 * and only waits for AGC to finish. I believe that's wrong because
+	 * during NF calibration, rx path is also routed to a detector, so if
+	 * it doesn't finish we won't have RX.
+	 *
+	 * XXX: Find an interval that's OK for all cards...
+	 */
 	ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 	ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	ah->ah_calibration = false;
-
-	/* A and G modes can use QAM modulation which requires enabling
-	 * I and Q calibration. Don't bother in B mode. */
-	if (!(mode == AR5K_MODE_11B)) {
-		ah->ah_calibration = true;
-		AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
-				AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
-		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
-				AR5K_PHY_IQ_RUN);
-	}
-
 	/*
 	/*
 	 * Reset queues and start beacon timers at the end of the reset routine
 	 * Reset queues and start beacon timers at the end of the reset routine
 	 */
 	 */
@@ -1154,6 +1192,12 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum ieee80211_if_types op_mode,
 		ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
 		ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
 		ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
 		ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
 		ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING);
 		ath5k_hw_reg_write(ah, ah->ah_phy_spending, AR5K_PHY_SPENDING);
+
+		data = ath5k_hw_reg_read(ah, AR5K_USEC_5211) & 0xffffc07f ;
+		data |= (ah->ah_phy_spending == AR5K_PHY_SPENDING_18) ?
+						0x00000f80 : 0x00001380 ;
+		ath5k_hw_reg_write(ah, data, AR5K_USEC_5211);
+		data = 0;
 	}
 	}
 
 
 	if (ah->ah_version == AR5K_AR5212) {
 	if (ah->ah_version == AR5K_AR5212) {
@@ -1226,7 +1270,7 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
 		bool set_chip, u16 sleep_duration)
 		bool set_chip, u16 sleep_duration)
 {
 {
 	unsigned int i;
 	unsigned int i;
-	u32 staid;
+	u32 staid, data;
 
 
 	ATH5K_TRACE(ah->ah_sc);
 	ATH5K_TRACE(ah->ah_sc);
 	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
 	staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
@@ -1238,7 +1282,8 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
 	case AR5K_PM_NETWORK_SLEEP:
 	case AR5K_PM_NETWORK_SLEEP:
 		if (set_chip)
 		if (set_chip)
 			ath5k_hw_reg_write(ah,
 			ath5k_hw_reg_write(ah,
-				AR5K_SLEEP_CTL_SLE | sleep_duration,
+				AR5K_SLEEP_CTL_SLE_ALLOW |
+				sleep_duration,
 				AR5K_SLEEP_CTL);
 				AR5K_SLEEP_CTL);
 
 
 		staid |= AR5K_STA_ID1_PWR_SV;
 		staid |= AR5K_STA_ID1_PWR_SV;
@@ -1253,13 +1298,24 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
 		break;
 		break;
 
 
 	case AR5K_PM_AWAKE:
 	case AR5K_PM_AWAKE:
+
+		staid &= ~AR5K_STA_ID1_PWR_SV;
+
 		if (!set_chip)
 		if (!set_chip)
 			goto commit;
 			goto commit;
 
 
-		ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
-				AR5K_SLEEP_CTL);
+		/* Preserve sleep duration */
+		data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
+		if( data & 0xffc00000 ){
+			data = 0;
+		} else {
+			data = data & 0xfffcffff;
+		}
+
+		ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+		udelay(15);
 
 
-		for (i = 5000; i > 0; i--) {
+		for (i = 50; i > 0; i--) {
 			/* Check if the chip did wake up */
 			/* Check if the chip did wake up */
 			if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
 			if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
 					AR5K_PCICFG_SPWR_DN) == 0)
 					AR5K_PCICFG_SPWR_DN) == 0)
@@ -1267,15 +1323,13 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
 
 
 			/* Wait a bit and retry */
 			/* Wait a bit and retry */
 			udelay(200);
 			udelay(200);
-			ath5k_hw_reg_write(ah, AR5K_SLEEP_CTL_SLE_WAKE,
-				AR5K_SLEEP_CTL);
+			ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
 		}
 		}
 
 
 		/* Fail if the chip didn't wake up */
 		/* Fail if the chip didn't wake up */
 		if (i <= 0)
 		if (i <= 0)
 			return -EIO;
 			return -EIO;
 
 
-		staid &= ~AR5K_STA_ID1_PWR_SV;
 		break;
 		break;
 
 
 	default:
 	default:
@@ -1304,6 +1358,7 @@ void ath5k_hw_start_rx(struct ath5k_hw *ah)
 {
 {
 	ATH5K_TRACE(ah->ah_sc);
 	ATH5K_TRACE(ah->ah_sc);
 	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
 	ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
+	ath5k_hw_reg_read(ah, AR5K_CR);
 }
 }
 
 
 /*
 /*
@@ -1390,6 +1445,7 @@ int ath5k_hw_tx_start(struct ath5k_hw *ah, unsigned int queue)
 		}
 		}
 		/* Start queue */
 		/* Start queue */
 		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
 		ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
+		ath5k_hw_reg_read(ah, AR5K_CR);
 	} else {
 	} else {
 		/* Return if queue is disabled */
 		/* Return if queue is disabled */
 		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
 		if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXD, queue))
@@ -1687,6 +1743,7 @@ enum ath5k_int ath5k_hw_set_intr(struct ath5k_hw *ah, enum ath5k_int new_mask)
 	 * (they will be re-enabled afterwards).
 	 * (they will be re-enabled afterwards).
 	 */
 	 */
 	ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
 	ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER);
+	ath5k_hw_reg_read(ah, AR5K_IER);
 
 
 	old_mask = ah->ah_imr;
 	old_mask = ah->ah_imr;
 
 
@@ -3363,11 +3420,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
 		ath5k_hw_reg_write(ah, ah->ah_turbo ?
 		ath5k_hw_reg_write(ah, ah->ah_turbo ?
 			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
 			AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
 			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
 			AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
-		/* Set PHY register 0x9844 (??) */
+		/* Set AR5K_PHY_SETTLING */
 		ath5k_hw_reg_write(ah, ah->ah_turbo ?
 		ath5k_hw_reg_write(ah, ah->ah_turbo ?
-			(ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x38 :
-			(ath5k_hw_reg_read(ah, AR5K_PHY(17)) & ~0x7F) | 0x1C,
-			AR5K_PHY(17));
+			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+			| 0x38 :
+			(ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
+			| 0x1C,
+			AR5K_PHY_SETTLING);
 		/* Set Frame Control Register */
 		/* Set Frame Control Register */
 		ath5k_hw_reg_write(ah, ah->ah_turbo ?
 		ath5k_hw_reg_write(ah, ah->ah_turbo ?
 			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
 			(AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
@@ -3488,7 +3547,7 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
 			if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
 			if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
 				AR5K_REG_ENABLE_BITS(ah,
 				AR5K_REG_ENABLE_BITS(ah,
 					AR5K_QUEUE_MISC(queue),
 					AR5K_QUEUE_MISC(queue),
-					AR5K_QCU_MISC_TXE);
+					AR5K_QCU_MISC_RDY_VEOL_POLICY);
 		}
 		}
 
 
 		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
 		if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)

+ 2 - 2
drivers/net/wireless/ath5k/initvals.c

@@ -489,7 +489,7 @@ static const struct ath5k_ini ar5212_ini[] = {
 	{ AR5K_QUEUE_TXDP(9),	0x00000000 },
 	{ AR5K_QUEUE_TXDP(9),	0x00000000 },
 	{ AR5K_DCU_FP,		0x00000000 },
 	{ AR5K_DCU_FP,		0x00000000 },
 	{ AR5K_DCU_TXP,		0x00000000 },
 	{ AR5K_DCU_TXP,		0x00000000 },
-	{ AR5K_DCU_TX_FILTER,	0x00000000 },
+	{ AR5K_DCU_TX_FILTER_0_BASE,	0x00000000 },
 	/* Unknown table */
 	/* Unknown table */
 	{ 0x1078, 0x00000000 },
 	{ 0x1078, 0x00000000 },
 	{ 0x10b8, 0x00000000 },
 	{ 0x10b8, 0x00000000 },
@@ -679,7 +679,7 @@ static const struct ath5k_ini ar5212_ini[] = {
 	{ AR5K_PHY(645), 0x00106c10 },
 	{ AR5K_PHY(645), 0x00106c10 },
 	{ AR5K_PHY(646), 0x009c4060 },
 	{ AR5K_PHY(646), 0x009c4060 },
 	{ AR5K_PHY(647), 0x1483800a },
 	{ AR5K_PHY(647), 0x1483800a },
-	/* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413 */
+	/* { AR5K_PHY(648), 0x018830c6 },*/ /* 2413/2425 */
 	{ AR5K_PHY(648), 0x01831061 },
 	{ AR5K_PHY(648), 0x01831061 },
 	{ AR5K_PHY(649), 0x00000400 },
 	{ AR5K_PHY(649), 0x00000400 },
 	/*{ AR5K_PHY(650), 0x000001b5 },*/
 	/*{ AR5K_PHY(650), 0x000001b5 },*/

+ 167 - 18
drivers/net/wireless/ath5k/phy.c

@@ -1020,6 +1020,74 @@ static const struct ath5k_ini_rfgain rfgain_2413[] = {
 	{ AR5K_RF_GAIN(63), { 0x000000f9 } },
 	{ AR5K_RF_GAIN(63), { 0x000000f9 } },
 };
 };
 
 
+/* Initial RF Gain settings for RF2425 */
+static const struct ath5k_ini_rfgain rfgain_2425[] = {
+	{ AR5K_RF_GAIN(0), { 0x00000000 } },
+	{ AR5K_RF_GAIN(1), { 0x00000040 } },
+	{ AR5K_RF_GAIN(2), { 0x00000080 } },
+	{ AR5K_RF_GAIN(3), { 0x00000181 } },
+	{ AR5K_RF_GAIN(4), { 0x000001c1 } },
+	{ AR5K_RF_GAIN(5), { 0x00000001 } },
+	{ AR5K_RF_GAIN(6), { 0x00000041 } },
+	{ AR5K_RF_GAIN(7), { 0x00000081 } },
+	{ AR5K_RF_GAIN(8), { 0x00000188 } },
+	{ AR5K_RF_GAIN(9), { 0x000001c8 } },
+	{ AR5K_RF_GAIN(10), { 0x00000008 } },
+	{ AR5K_RF_GAIN(11), { 0x00000048 } },
+	{ AR5K_RF_GAIN(12), { 0x00000088 } },
+	{ AR5K_RF_GAIN(13), { 0x00000189 } },
+	{ AR5K_RF_GAIN(14), { 0x000001c9 } },
+	{ AR5K_RF_GAIN(15), { 0x00000009 } },
+	{ AR5K_RF_GAIN(16), { 0x00000049 } },
+	{ AR5K_RF_GAIN(17), { 0x00000089 } },
+	{ AR5K_RF_GAIN(18), { 0x000001b0 } },
+	{ AR5K_RF_GAIN(19), { 0x000001f0 } },
+	{ AR5K_RF_GAIN(20), { 0x00000030 } },
+	{ AR5K_RF_GAIN(21), { 0x00000070 } },
+	{ AR5K_RF_GAIN(22), { 0x00000171 } },
+	{ AR5K_RF_GAIN(23), { 0x000001b1 } },
+	{ AR5K_RF_GAIN(24), { 0x000001f1 } },
+	{ AR5K_RF_GAIN(25), { 0x00000031 } },
+	{ AR5K_RF_GAIN(26), { 0x00000071 } },
+	{ AR5K_RF_GAIN(27), { 0x000001b8 } },
+	{ AR5K_RF_GAIN(28), { 0x000001f8 } },
+	{ AR5K_RF_GAIN(29), { 0x00000038 } },
+	{ AR5K_RF_GAIN(30), { 0x00000078 } },
+	{ AR5K_RF_GAIN(31), { 0x000000b8 } },
+	{ AR5K_RF_GAIN(32), { 0x000001b9 } },
+	{ AR5K_RF_GAIN(33), { 0x000001f9 } },
+	{ AR5K_RF_GAIN(34), { 0x00000039 } },
+	{ AR5K_RF_GAIN(35), { 0x00000079 } },
+	{ AR5K_RF_GAIN(36), { 0x000000b9 } },
+	{ AR5K_RF_GAIN(37), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(38), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(39), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(40), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(41), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(42), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(43), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(44), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(45), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(46), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(47), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(48), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(49), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(50), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(51), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(52), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(53), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(54), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(55), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(56), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(57), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(58), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(59), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(60), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(61), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(62), { 0x000000f9 } },
+	{ AR5K_RF_GAIN(63), { 0x000000f9 } },
+};
+
 static const struct ath5k_gain_opt rfgain_opt_5112 = {
 static const struct ath5k_gain_opt rfgain_opt_5112 = {
 	1,
 	1,
 	8,
 	8,
@@ -1588,8 +1656,8 @@ int ath5k_hw_rfgain(struct ath5k_hw *ah, unsigned int freq)
 		freq = 0; /* only 2Ghz */
 		freq = 0; /* only 2Ghz */
 		break;
 		break;
 	case AR5K_RF2425:
 	case AR5K_RF2425:
-		ath5k_rfg = rfgain_2413;
-		size = ARRAY_SIZE(rfgain_2413);
+		ath5k_rfg = rfgain_2425;
+		size = ARRAY_SIZE(rfgain_2425);
 		freq = 0; /* only 2Ghz */
 		freq = 0; /* only 2Ghz */
 		break;
 		break;
 	default:
 	default:
@@ -1830,9 +1898,6 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
 	data = data0 = data1 = data2 = 0;
 	data = data0 = data1 = data2 = 0;
 	c = channel->center_freq;
 	c = channel->center_freq;
 
 
-	/*
-	 * Set the channel on the RF5112 or newer
-	 */
 	if (c < 4800) {
 	if (c < 4800) {
 		if (!((c - 2224) % 5)) {
 		if (!((c - 2224) % 5)) {
 			data0 = ((2 * (c - 704)) - 3040) / 10;
 			data0 = ((2 * (c - 704)) - 3040) / 10;
@@ -1844,7 +1909,7 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
 			return -EINVAL;
 			return -EINVAL;
 
 
 		data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
 		data0 = ath5k_hw_bitswap((data0 << 2) & 0xff, 8);
-	} else {
+	} else if ((c - (c % 5)) != 2 || c > 5435) {
 		if (!(c % 20) && c >= 5120) {
 		if (!(c % 20) && c >= 5120) {
 			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
 			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
 			data2 = ath5k_hw_bitswap(3, 2);
 			data2 = ath5k_hw_bitswap(3, 2);
@@ -1856,6 +1921,9 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
 			data2 = ath5k_hw_bitswap(1, 2);
 			data2 = ath5k_hw_bitswap(1, 2);
 		} else
 		} else
 			return -EINVAL;
 			return -EINVAL;
+	} else {
+		data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+		data2 = ath5k_hw_bitswap(0, 2);
 	}
 	}
 
 
 	data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
 	data = (data0 << 4) | (data1 << 1) | (data2 << 2) | 0x1001;
@@ -1866,6 +1934,45 @@ static int ath5k_hw_rf5112_channel(struct ath5k_hw *ah,
 	return 0;
 	return 0;
 }
 }
 
 
+/*
+ * Set the channel on the RF2425
+ */
+static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
+		struct ieee80211_channel *channel)
+{
+	u32 data, data0, data2;
+	u16 c;
+
+	data = data0 = data2 = 0;
+	c = channel->center_freq;
+
+	if (c < 4800) {
+		data0 = ath5k_hw_bitswap((c - 2272), 8);
+		data2 = 0;
+	/* ? 5GHz ? */
+	} else if ((c - (c % 5)) != 2 || c > 5435) {
+		if (!(c % 20) && c < 5120)
+			data0 = ath5k_hw_bitswap(((c - 4800) / 20 << 2), 8);
+		else if (!(c % 10))
+			data0 = ath5k_hw_bitswap(((c - 4800) / 10 << 1), 8);
+		else if (!(c % 5))
+			data0 = ath5k_hw_bitswap((c - 4800) / 5, 8);
+		else
+			return -EINVAL;
+		data2 = ath5k_hw_bitswap(1, 2);
+	} else {
+		data0 = ath5k_hw_bitswap((10 * (c - 2) - 4800) / 25 + 1, 8);
+		data2 = ath5k_hw_bitswap(0, 2);
+	}
+
+	data = (data0 << 4) | data2 << 2 | 0x1001;
+
+	ath5k_hw_reg_write(ah, data & 0xff, AR5K_RF_BUFFER);
+	ath5k_hw_reg_write(ah, (data >> 8) & 0x7f, AR5K_RF_BUFFER_CONTROL_5);
+
+	return 0;
+}
+
 /*
 /*
  * Set a channel on the radio chip
  * Set a channel on the radio chip
  */
  */
@@ -1895,6 +2002,9 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
 	case AR5K_RF5111:
 	case AR5K_RF5111:
 		ret = ath5k_hw_rf5111_channel(ah, channel);
 		ret = ath5k_hw_rf5111_channel(ah, channel);
 		break;
 		break;
+	case AR5K_RF2425:
+		ret = ath5k_hw_rf2425_channel(ah, channel);
+		break;
 	default:
 	default:
 		ret = ath5k_hw_rf5112_channel(ah, channel);
 		ret = ath5k_hw_rf5112_channel(ah, channel);
 		break;
 		break;
@@ -1903,6 +2013,15 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
+	/* Set JAPAN setting for channel 14 */
+	if (channel->center_freq == 2484) {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
+				AR5K_PHY_CCKTXCTL_JAPAN);
+	} else {
+		AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_CCKTXCTL,
+				AR5K_PHY_CCKTXCTL_WORLD);
+	}
+
 	ah->ah_current_channel.center_freq = channel->center_freq;
 	ah->ah_current_channel.center_freq = channel->center_freq;
 	ah->ah_current_channel.hw_value = channel->hw_value;
 	ah->ah_current_channel.hw_value = channel->hw_value;
 	ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
 	ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
@@ -1933,6 +2052,8 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
  * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
  * http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO1&Sect2=HITOFF&d=PALL \
  * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
  * &p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=1&f=G&l=50&s1=7245893.PN.&OS=PN/7
  *
  *
+ * XXX: Since during noise floor calibration antennas are detached according to
+ * the patent, we should stop tx queues here.
  */
  */
 int
 int
 ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
 ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
@@ -1942,7 +2063,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
 	s32 noise_floor;
 	s32 noise_floor;
 
 
 	/*
 	/*
-	 * Enable noise floor calibration and wait until completion
+	 * Enable noise floor calibration
 	 */
 	 */
 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
 				AR5K_PHY_AGCCTL_NF);
 				AR5K_PHY_AGCCTL_NF);
@@ -1952,7 +2073,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
 	if (ret) {
 	if (ret) {
 		ATH5K_ERR(ah->ah_sc,
 		ATH5K_ERR(ah->ah_sc,
 			"noise floor calibration timeout (%uMHz)\n", freq);
 			"noise floor calibration timeout (%uMHz)\n", freq);
-		return ret;
+		return -EAGAIN;
 	}
 	}
 
 
 	/* Wait until the noise floor is calibrated and read the value */
 	/* Wait until the noise floor is calibrated and read the value */
@@ -1974,7 +2095,7 @@ ath5k_hw_noise_floor_calibration(struct ath5k_hw *ah, short freq)
 	if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
 	if (noise_floor > AR5K_TUNE_NOISE_FLOOR) {
 		ATH5K_ERR(ah->ah_sc,
 		ATH5K_ERR(ah->ah_sc,
 			"noise floor calibration failed (%uMHz)\n", freq);
 			"noise floor calibration failed (%uMHz)\n", freq);
-		return -EIO;
+		return -EAGAIN;
 	}
 	}
 
 
 	ah->ah_noise_floor = noise_floor;
 	ah->ah_noise_floor = noise_floor;
@@ -2087,38 +2208,66 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
 }
 }
 
 
 /*
 /*
- * Perform a PHY calibration on RF5111/5112
+ * Perform a PHY calibration on RF5111/5112 and newer chips
  */
  */
 static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
 static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
 		struct ieee80211_channel *channel)
 		struct ieee80211_channel *channel)
 {
 {
 	u32 i_pwr, q_pwr;
 	u32 i_pwr, q_pwr;
 	s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
 	s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
+	int i;
 	ATH5K_TRACE(ah->ah_sc);
 	ATH5K_TRACE(ah->ah_sc);
 
 
 	if (!ah->ah_calibration ||
 	if (!ah->ah_calibration ||
-			ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
+		ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
 		goto done;
 		goto done;
 
 
-	ah->ah_calibration = false;
+	/* Calibration has finished, get the results and re-run */
+	for (i = 0; i <= 10; i++) {
+		iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
+		i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
+		q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
+	}
 
 
-	iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
-	i_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_I);
-	q_pwr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_PWR_Q);
 	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
 	i_coffd = ((i_pwr >> 1) + (q_pwr >> 1)) >> 7;
-	q_coffd = q_pwr >> 6;
+	q_coffd = q_pwr >> 7;
 
 
+	/* No correction */
 	if (i_coffd == 0 || q_coffd == 0)
 	if (i_coffd == 0 || q_coffd == 0)
 		goto done;
 		goto done;
 
 
 	i_coff = ((-iq_corr) / i_coffd) & 0x3f;
 	i_coff = ((-iq_corr) / i_coffd) & 0x3f;
-	q_coff = (((s32)i_pwr / q_coffd) - 64) & 0x1f;
 
 
-	/* Commit new IQ value */
+	/* Boundary check */
+	if (i_coff > 31)
+		i_coff = 31;
+	if (i_coff < -32)
+		i_coff = -32;
+
+	q_coff = (((s32)i_pwr / q_coffd) - 128) & 0x1f;
+
+	/* Boundary check */
+	if (q_coff > 15)
+		q_coff = 15;
+	if (q_coff < -16)
+		q_coff = -16;
+
+	/* Commit new I/Q value */
 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
 	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_CORR_ENABLE |
 		((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
 		((u32)q_coff) | ((u32)i_coff << AR5K_PHY_IQ_CORR_Q_I_COFF_S));
 
 
+	/* Re-enable calibration -if we don't we'll commit
+	 * the same values again and again */
+	AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+			AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+	AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
+
 done:
 done:
+
+	/* TODO: Separate noise floor calibration from I/Q calibration
+	 * since noise floor calibration interrupts rx path while I/Q
+	 * calibration doesn't. We don't need to run noise floor calibration
+	 * as often as I/Q calibration.*/
 	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 	ath5k_hw_noise_floor_calibration(ah, channel->center_freq);
 
 
 	/* Request RF gain */
 	/* Request RF gain */

文件差異過大導致無法顯示
+ 410 - 191
drivers/net/wireless/ath5k/reg.h


+ 3 - 2
drivers/net/wireless/ipw2200.c

@@ -305,9 +305,10 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c)
 #define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs))
 #define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs))
 
 
 /* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
 /* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write8(ipw, ofs, val) \
+#define ipw_write8(ipw, ofs, val) do { \
  IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
  IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write8(ipw, ofs, val)
+ _ipw_write8(ipw, ofs, val); \
+ } while (0)
 
 
 /* 16-bit direct write (low 4K) */
 /* 16-bit direct write (low 4K) */
 #define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs))
 #define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs))

+ 6 - 4
drivers/net/wireless/iwlwifi/iwl-3945.c

@@ -710,10 +710,7 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
 		return;
 		return;
 	}
 	}
 
 
-	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
-		iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
-		return;
-	}
+
 
 
 	/* Convert 3945's rssi indicator to dBm */
 	/* Convert 3945's rssi indicator to dBm */
 	rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET;
 	rx_status.signal = rx_stats->rssi - IWL_RSSI_OFFSET;
@@ -775,6 +772,11 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv,
 		priv->last_rx_noise = rx_status.noise;
 		priv->last_rx_noise = rx_status.noise;
 	}
 	}
 
 
+	if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
+		iwl3945_pass_packet_to_mac80211(priv, rxb, &rx_status);
+		return;
+	}
+
 	switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
 	switch (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FTYPE) {
 	case IEEE80211_FTYPE_MGMT:
 	case IEEE80211_FTYPE_MGMT:
 		switch (le16_to_cpu(header->frame_control) &
 		switch (le16_to_cpu(header->frame_control) &

+ 4 - 4
drivers/net/wireless/iwlwifi/iwl-tx.c

@@ -962,16 +962,16 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	if ((iwl_queue_space(q) < q->high_mark)
-	    && priv->mac80211_registered) {
+	if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
 		if (wait_write_ptr) {
 		if (wait_write_ptr) {
 			spin_lock_irqsave(&priv->lock, flags);
 			spin_lock_irqsave(&priv->lock, flags);
 			txq->need_update = 1;
 			txq->need_update = 1;
 			iwl_txq_update_write_ptr(priv, txq);
 			iwl_txq_update_write_ptr(priv, txq);
 			spin_unlock_irqrestore(&priv->lock, flags);
 			spin_unlock_irqrestore(&priv->lock, flags);
+		} else {
+			ieee80211_stop_queue(priv->hw,
+					     skb_get_queue_mapping(skb));
 		}
 		}
-
-		ieee80211_stop_queue(priv->hw, skb_get_queue_mapping(skb));
 	}
 	}
 
 
 	return 0;
 	return 0;

+ 9 - 6
drivers/net/wireless/libertas/main.c

@@ -297,9 +297,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
 			lbs_add_rtap(priv);
 			lbs_add_rtap(priv);
 		}
 		}
 		priv->monitormode = monitor_mode;
 		priv->monitormode = monitor_mode;
-	}
-
-	else {
+	} else {
 		if (!priv->monitormode)
 		if (!priv->monitormode)
 			return strlen(buf);
 			return strlen(buf);
 		priv->monitormode = 0;
 		priv->monitormode = 0;
@@ -1242,8 +1240,6 @@ int lbs_start_card(struct lbs_private *priv)
 		lbs_pr_err("cannot register ethX device\n");
 		lbs_pr_err("cannot register ethX device\n");
 		goto done;
 		goto done;
 	}
 	}
-	if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
-		lbs_pr_err("cannot register lbs_rtap attribute\n");
 
 
 	lbs_update_channel(priv);
 	lbs_update_channel(priv);
 
 
@@ -1275,6 +1271,13 @@ int lbs_start_card(struct lbs_private *priv)
 
 
 			if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
 			if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
 				lbs_pr_err("cannot register lbs_mesh attribute\n");
 				lbs_pr_err("cannot register lbs_mesh attribute\n");
+
+			/* While rtap isn't related to mesh, only mesh-enabled
+			 * firmware implements the rtap functionality via
+			 * CMD_802_11_MONITOR_MODE.
+			 */
+			if (device_create_file(&dev->dev, &dev_attr_lbs_rtap))
+				lbs_pr_err("cannot register lbs_rtap attribute\n");
 		}
 		}
 	}
 	}
 
 
@@ -1306,9 +1309,9 @@ void lbs_stop_card(struct lbs_private *priv)
 	netif_carrier_off(priv->dev);
 	netif_carrier_off(priv->dev);
 
 
 	lbs_debugfs_remove_one(priv);
 	lbs_debugfs_remove_one(priv);
-	device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
 	if (priv->mesh_tlv) {
 	if (priv->mesh_tlv) {
 		device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
 		device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
+		device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
 	}
 	}
 
 
 	/* Flush pending command nodes */
 	/* Flush pending command nodes */

+ 1 - 1
drivers/net/wireless/prism54/isl_ioctl.c

@@ -2518,7 +2518,7 @@ enum {
 
 
 #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
 #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
 #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
 #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+	offsetof(struct prism2_hostapd_param, u.generic_elem.data)
 
 
 /* Maximum length for algorithm names (-1 for nul termination)
 /* Maximum length for algorithm names (-1 for nul termination)
  * used in ioctl() */
  * used in ioctl() */

+ 1 - 0
drivers/net/wireless/rt2x00/rt2500pci.c

@@ -1220,6 +1220,7 @@ static void rt2500pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
 	rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
 	rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs);
 	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
 	rt2x00_set_field32(&word, TXD_W0_RETRY_MODE,
 			   test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
 			   test_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags));
+	rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len);
 	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
 	rt2x00_set_field32(&word, TXD_W0_CIPHER_ALG, CIPHER_NONE);
 	rt2x00_desc_write(txd, 0, word);
 	rt2x00_desc_write(txd, 0, word);
 }
 }

+ 3 - 3
drivers/net/wireless/rt2x00/rt2500usb.c

@@ -1376,6 +1376,9 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 		rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
 		rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
 		EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word);
 		EEPROM(rt2x00dev, "BBPtune vgc: 0x%04x\n", word);
+	} else {
+		rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
+		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
 	}
 	}
 
 
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word);
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R17, &word);
@@ -1384,9 +1387,6 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41);
 		rt2x00_set_field16(&word, EEPROM_BBPTUNE_R17_HIGH, 0x41);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word);
 		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_R17, word);
 		EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word);
 		EEPROM(rt2x00dev, "BBPtune r17: 0x%04x\n", word);
-	} else {
-		rt2x00_set_field16(&word, EEPROM_BBPTUNE_VGCLOWER, bbp);
-		rt2x00_eeprom_write(rt2x00dev, EEPROM_BBPTUNE_VGC, word);
 	}
 	}
 
 
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word);
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_BBPTUNE_R24, &word);

+ 6 - 0
drivers/net/wireless/rt2x00/rt2x00.h

@@ -368,6 +368,12 @@ struct rt2x00_intf {
 #define DELAYED_CONFIG_ERP		0x00000002
 #define DELAYED_CONFIG_ERP		0x00000002
 #define DELAYED_LED_ASSOC		0x00000004
 #define DELAYED_LED_ASSOC		0x00000004
 
 
+	/*
+	 * Software sequence counter, this is only required
+	 * for hardware which doesn't support hardware
+	 * sequence counting.
+	 */
+	spinlock_t seqlock;
 	u16 seqno;
 	u16 seqno;
 };
 };
 
 

+ 4 - 0
drivers/net/wireless/rt2x00/rt2x00config.c

@@ -254,6 +254,8 @@ config:
 			libconf.ant.rx = default_ant->rx;
 			libconf.ant.rx = default_ant->rx;
 		else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
 		else if (active_ant->rx == ANTENNA_SW_DIVERSITY)
 			libconf.ant.rx = ANTENNA_B;
 			libconf.ant.rx = ANTENNA_B;
+		else
+			libconf.ant.rx = active_ant->rx;
 
 
 		if (conf->antenna_sel_tx)
 		if (conf->antenna_sel_tx)
 			libconf.ant.tx = conf->antenna_sel_tx;
 			libconf.ant.tx = conf->antenna_sel_tx;
@@ -261,6 +263,8 @@ config:
 			libconf.ant.tx = default_ant->tx;
 			libconf.ant.tx = default_ant->tx;
 		else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
 		else if (active_ant->tx == ANTENNA_SW_DIVERSITY)
 			libconf.ant.tx = ANTENNA_B;
 			libconf.ant.tx = ANTENNA_B;
+		else
+			libconf.ant.tx = active_ant->tx;
 	}
 	}
 
 
 	if (flags & CONFIG_UPDATE_SLOT_TIME) {
 	if (flags & CONFIG_UPDATE_SLOT_TIME) {

+ 7 - 10
drivers/net/wireless/rt2x00/rt2x00debug.c

@@ -372,9 +372,6 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,	\
 	if (*offset)						\
 	if (*offset)						\
 		return 0;					\
 		return 0;					\
 								\
 								\
-	if (!capable(CAP_NET_ADMIN))				\
-		return -EPERM;					\
-								\
 	if (intf->offset_##__name >= debug->__name.word_count)	\
 	if (intf->offset_##__name >= debug->__name.word_count)	\
 		return -EINVAL;					\
 		return -EINVAL;					\
 								\
 								\
@@ -454,7 +451,7 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name,
 	data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__);
 	data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__);
 	blob->size = strlen(blob->data);
 	blob->size = strlen(blob->data);
 
 
-	return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+	return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
 }
 }
 
 
 static struct dentry *rt2x00debug_create_file_chipset(const char *name,
 static struct dentry *rt2x00debug_create_file_chipset(const char *name,
@@ -482,7 +479,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
 	data += sprintf(data, "rf length: %d\n", debug->rf.word_count);
 	data += sprintf(data, "rf length: %d\n", debug->rf.word_count);
 	blob->size = strlen(blob->data);
 	blob->size = strlen(blob->data);
 
 
-	return debugfs_create_blob(name, S_IRUGO, intf->driver_folder, blob);
+	return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
 }
 }
 
 
 void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
@@ -517,7 +514,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 	if (IS_ERR(intf->chipset_entry))
 	if (IS_ERR(intf->chipset_entry))
 		goto exit;
 		goto exit;
 
 
-	intf->dev_flags = debugfs_create_file("dev_flags", S_IRUGO,
+	intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR,
 					      intf->driver_folder, intf,
 					      intf->driver_folder, intf,
 					      &rt2x00debug_fop_dev_flags);
 					      &rt2x00debug_fop_dev_flags);
 	if (IS_ERR(intf->dev_flags))
 	if (IS_ERR(intf->dev_flags))
@@ -532,7 +529,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 ({								\
 ({								\
 	(__intf)->__name##_off_entry =				\
 	(__intf)->__name##_off_entry =				\
 	    debugfs_create_u32(__stringify(__name) "_offset",	\
 	    debugfs_create_u32(__stringify(__name) "_offset",	\
-			       S_IRUGO | S_IWUSR,		\
+			       S_IRUSR | S_IWUSR,		\
 			       (__intf)->register_folder,	\
 			       (__intf)->register_folder,	\
 			       &(__intf)->offset_##__name);	\
 			       &(__intf)->offset_##__name);	\
 	if (IS_ERR((__intf)->__name##_off_entry))		\
 	if (IS_ERR((__intf)->__name##_off_entry))		\
@@ -540,7 +537,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 								\
 								\
 	(__intf)->__name##_val_entry =				\
 	(__intf)->__name##_val_entry =				\
 	    debugfs_create_file(__stringify(__name) "_value",	\
 	    debugfs_create_file(__stringify(__name) "_value",	\
-				S_IRUGO | S_IWUSR,		\
+				S_IRUSR | S_IWUSR,		\
 				(__intf)->register_folder,	\
 				(__intf)->register_folder,	\
 				(__intf), &rt2x00debug_fop_##__name);\
 				(__intf), &rt2x00debug_fop_##__name);\
 	if (IS_ERR((__intf)->__name##_val_entry))		\
 	if (IS_ERR((__intf)->__name##_val_entry))		\
@@ -560,7 +557,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 		goto exit;
 		goto exit;
 
 
 	intf->queue_frame_dump_entry =
 	intf->queue_frame_dump_entry =
-	    debugfs_create_file("dump", S_IRUGO, intf->queue_folder,
+	    debugfs_create_file("dump", S_IRUSR, intf->queue_folder,
 				intf, &rt2x00debug_fop_queue_dump);
 				intf, &rt2x00debug_fop_queue_dump);
 	if (IS_ERR(intf->queue_frame_dump_entry))
 	if (IS_ERR(intf->queue_frame_dump_entry))
 		goto exit;
 		goto exit;
@@ -569,7 +566,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 	init_waitqueue_head(&intf->frame_dump_waitqueue);
 	init_waitqueue_head(&intf->frame_dump_waitqueue);
 
 
 	intf->queue_stats_entry =
 	intf->queue_stats_entry =
-	    debugfs_create_file("queue", S_IRUGO, intf->queue_folder,
+	    debugfs_create_file("queue", S_IRUSR, intf->queue_folder,
 				intf, &rt2x00debug_fop_queue_stats);
 				intf, &rt2x00debug_fop_queue_stats);
 
 
 	return;
 	return;

+ 1 - 0
drivers/net/wireless/rt2x00/rt2x00mac.c

@@ -247,6 +247,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw,
 		rt2x00dev->intf_sta_count++;
 		rt2x00dev->intf_sta_count++;
 
 
 	spin_lock_init(&intf->lock);
 	spin_lock_init(&intf->lock);
+	spin_lock_init(&intf->seqlock);
 	intf->beacon = entry;
 	intf->beacon = entry;
 
 
 	if (conf->type == IEEE80211_IF_TYPE_AP)
 	if (conf->type == IEEE80211_IF_TYPE_AP)

+ 3 - 2
drivers/net/wireless/rt2x00/rt2x00queue.c

@@ -128,6 +128,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 	unsigned int data_length;
 	unsigned int data_length;
 	unsigned int duration;
 	unsigned int duration;
 	unsigned int residual;
 	unsigned int residual;
+	unsigned long irqflags;
 
 
 	memset(txdesc, 0, sizeof(*txdesc));
 	memset(txdesc, 0, sizeof(*txdesc));
 
 
@@ -213,14 +214,14 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry,
 	 * sequence counter given by mac80211.
 	 * sequence counter given by mac80211.
 	 */
 	 */
 	if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
 	if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
-		spin_lock(&intf->lock);
+		spin_lock_irqsave(&intf->seqlock, irqflags);
 
 
 		if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
 		if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
 			intf->seqno += 0x10;
 			intf->seqno += 0x10;
 		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
 		hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
 		hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
 		hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
 
 
-		spin_unlock(&intf->lock);
+		spin_unlock_irqrestore(&intf->seqlock, irqflags);
 
 
 		__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
 		__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
 	}
 	}

+ 5 - 0
drivers/net/wireless/rt2x00/rt61pci.c

@@ -1003,6 +1003,11 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data,
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 
 
+	/*
+	 * Hardware needs another millisecond before it is ready.
+	 */
+	msleep(1);
+
 	/*
 	/*
 	 * Reset MAC and BBP registers.
 	 * Reset MAC and BBP registers.
 	 */
 	 */

+ 4 - 0
drivers/net/wireless/rtl8187.h

@@ -94,6 +94,10 @@ struct rtl8187_priv {
 	const struct rtl818x_rf_ops *rf;
 	const struct rtl818x_rf_ops *rf;
 	struct ieee80211_vif *vif;
 	struct ieee80211_vif *vif;
 	int mode;
 	int mode;
+	/* The mutex protects the TX loopback state.
+	 * Any attempt to set channels concurrently locks the device.
+	 */
+	struct mutex conf_mutex;
 
 
 	/* rtl8187 specific */
 	/* rtl8187 specific */
 	struct ieee80211_channel channels[14];
 	struct ieee80211_channel channels[14];

+ 16 - 1
drivers/net/wireless/rtl8187_dev.c

@@ -31,6 +31,8 @@ MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 
 
 static struct usb_device_id rtl8187_table[] __devinitdata = {
 static struct usb_device_id rtl8187_table[] __devinitdata = {
+	/* Asus */
+	{USB_DEVICE(0x0b05, 0x171d), .driver_info = DEVICE_RTL8187},
 	/* Realtek */
 	/* Realtek */
 	{USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187},
 	{USB_DEVICE(0x0bda, 0x8187), .driver_info = DEVICE_RTL8187},
 	{USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B},
 	{USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B},
@@ -726,6 +728,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
+	mutex_lock(&priv->conf_mutex);
 	if (priv->is_rtl8187b) {
 	if (priv->is_rtl8187b) {
 		reg = RTL818X_RX_CONF_MGMT |
 		reg = RTL818X_RX_CONF_MGMT |
 		      RTL818X_RX_CONF_DATA |
 		      RTL818X_RX_CONF_DATA |
@@ -747,6 +750,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
 				  (7 << 0  /* long retry limit */) |
 				  (7 << 0  /* long retry limit */) |
 				  (7 << 21 /* MAX TX DMA */));
 				  (7 << 21 /* MAX TX DMA */));
 		rtl8187_init_urbs(dev);
 		rtl8187_init_urbs(dev);
+		mutex_unlock(&priv->conf_mutex);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -790,6 +794,7 @@ static int rtl8187_start(struct ieee80211_hw *dev)
 	reg |= RTL818X_CMD_TX_ENABLE;
 	reg |= RTL818X_CMD_TX_ENABLE;
 	reg |= RTL818X_CMD_RX_ENABLE;
 	reg |= RTL818X_CMD_RX_ENABLE;
 	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
 	rtl818x_iowrite8(priv, &priv->map->CMD, reg);
+	mutex_unlock(&priv->conf_mutex);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -801,6 +806,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
 	struct sk_buff *skb;
 	struct sk_buff *skb;
 	u32 reg;
 	u32 reg;
 
 
+	mutex_lock(&priv->conf_mutex);
 	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0);
 
 
 	reg = rtl818x_ioread8(priv, &priv->map->CMD);
 	reg = rtl818x_ioread8(priv, &priv->map->CMD);
@@ -820,7 +826,7 @@ static void rtl8187_stop(struct ieee80211_hw *dev)
 		usb_kill_urb(info->urb);
 		usb_kill_urb(info->urb);
 		kfree_skb(skb);
 		kfree_skb(skb);
 	}
 	}
-	return;
+	mutex_unlock(&priv->conf_mutex);
 }
 }
 
 
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
 static int rtl8187_add_interface(struct ieee80211_hw *dev,
@@ -840,6 +846,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
 		return -EOPNOTSUPP;
 		return -EOPNOTSUPP;
 	}
 	}
 
 
+	mutex_lock(&priv->conf_mutex);
 	priv->vif = conf->vif;
 	priv->vif = conf->vif;
 
 
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
@@ -848,6 +855,7 @@ static int rtl8187_add_interface(struct ieee80211_hw *dev,
 				 ((u8 *)conf->mac_addr)[i]);
 				 ((u8 *)conf->mac_addr)[i]);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL);
 
 
+	mutex_unlock(&priv->conf_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -855,8 +863,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev,
 				     struct ieee80211_if_init_conf *conf)
 				     struct ieee80211_if_init_conf *conf)
 {
 {
 	struct rtl8187_priv *priv = dev->priv;
 	struct rtl8187_priv *priv = dev->priv;
+	mutex_lock(&priv->conf_mutex);
 	priv->mode = IEEE80211_IF_TYPE_MNTR;
 	priv->mode = IEEE80211_IF_TYPE_MNTR;
 	priv->vif = NULL;
 	priv->vif = NULL;
+	mutex_unlock(&priv->conf_mutex);
 }
 }
 
 
 static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
 static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
@@ -864,6 +874,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
 	struct rtl8187_priv *priv = dev->priv;
 	struct rtl8187_priv *priv = dev->priv;
 	u32 reg;
 	u32 reg;
 
 
+	mutex_lock(&priv->conf_mutex);
 	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
 	reg = rtl818x_ioread32(priv, &priv->map->TX_CONF);
 	/* Enable TX loopback on MAC level to avoid TX during channel
 	/* Enable TX loopback on MAC level to avoid TX during channel
 	 * changes, as this has be seen to causes problems and the
 	 * changes, as this has be seen to causes problems and the
@@ -896,6 +907,7 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf)
 	rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
 	rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100);
 	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
 	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100);
 	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
 	rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL_TIME, 100);
+	mutex_unlock(&priv->conf_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -907,6 +919,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
 	int i;
 	int i;
 	u8 reg;
 	u8 reg;
 
 
+	mutex_lock(&priv->conf_mutex);
 	for (i = 0; i < ETH_ALEN; i++)
 	for (i = 0; i < ETH_ALEN; i++)
 		rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
 		rtl818x_iowrite8(priv, &priv->map->BSSID[i], conf->bssid[i]);
 
 
@@ -920,6 +933,7 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev,
 		rtl818x_iowrite8(priv, &priv->map->MSR, reg);
 		rtl818x_iowrite8(priv, &priv->map->MSR, reg);
 	}
 	}
 
 
+	mutex_unlock(&priv->conf_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1187,6 +1201,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf,
 		printk(KERN_ERR "rtl8187: Cannot register device\n");
 		printk(KERN_ERR "rtl8187: Cannot register device\n");
 		goto err_free_dev;
 		goto err_free_dev;
 	}
 	}
+	mutex_init(&priv->conf_mutex);
 
 
 	printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n",
 	printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n",
 	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),
 	       wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr),

+ 1 - 0
net/mac80211/ieee80211_i.h

@@ -586,6 +586,7 @@ struct ieee80211_local {
 	struct timer_list sta_cleanup;
 	struct timer_list sta_cleanup;
 
 
 	unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
 	unsigned long queues_pending[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
+	unsigned long queues_pending_run[BITS_TO_LONGS(IEEE80211_MAX_QUEUES)];
 	struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES];
 	struct ieee80211_tx_stored_packet pending_packet[IEEE80211_MAX_QUEUES];
 	struct tasklet_struct tx_pending_tasklet;
 	struct tasklet_struct tx_pending_tasklet;
 
 

+ 12 - 5
net/mac80211/tx.c

@@ -1060,13 +1060,14 @@ static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
 static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
 static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
 			  struct ieee80211_tx_data *tx)
 			  struct ieee80211_tx_data *tx)
 {
 {
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_tx_info *info;
 	int ret, i;
 	int ret, i;
 
 
-	if (netif_subqueue_stopped(local->mdev, skb))
-		return IEEE80211_TX_AGAIN;
-
 	if (skb) {
 	if (skb) {
+		if (netif_subqueue_stopped(local->mdev, skb))
+			return IEEE80211_TX_AGAIN;
+		info =  IEEE80211_SKB_CB(skb);
+
 		ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
 		ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
 				     "TX to low-level driver", skb);
 				     "TX to low-level driver", skb);
 		ret = local->ops->tx(local_to_hw(local), skb);
 		ret = local->ops->tx(local_to_hw(local), skb);
@@ -1215,6 +1216,7 @@ retry:
 
 
 		if (ret == IEEE80211_TX_FRAG_AGAIN)
 		if (ret == IEEE80211_TX_FRAG_AGAIN)
 			skb = NULL;
 			skb = NULL;
+
 		set_bit(queue, local->queues_pending);
 		set_bit(queue, local->queues_pending);
 		smp_mb();
 		smp_mb();
 		/*
 		/*
@@ -1708,14 +1710,19 @@ void ieee80211_tx_pending(unsigned long data)
 	netif_tx_lock_bh(dev);
 	netif_tx_lock_bh(dev);
 	for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
 	for (i = 0; i < ieee80211_num_regular_queues(&local->hw); i++) {
 		/* Check that this queue is ok */
 		/* Check that this queue is ok */
-		if (__netif_subqueue_stopped(local->mdev, i))
+		if (__netif_subqueue_stopped(local->mdev, i) &&
+		    !test_bit(i, local->queues_pending_run))
 			continue;
 			continue;
 
 
 		if (!test_bit(i, local->queues_pending)) {
 		if (!test_bit(i, local->queues_pending)) {
+			clear_bit(i, local->queues_pending_run);
 			ieee80211_wake_queue(&local->hw, i);
 			ieee80211_wake_queue(&local->hw, i);
 			continue;
 			continue;
 		}
 		}
 
 
+		clear_bit(i, local->queues_pending_run);
+		netif_start_subqueue(local->mdev, i);
+
 		store = &local->pending_packet[i];
 		store = &local->pending_packet[i];
 		tx.extra_frag = store->extra_frag;
 		tx.extra_frag = store->extra_frag;
 		tx.num_extra_frag = store->num_extra_frag;
 		tx.num_extra_frag = store->num_extra_frag;

+ 1 - 0
net/mac80211/util.c

@@ -361,6 +361,7 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue)
 	struct ieee80211_local *local = hw_to_local(hw);
 	struct ieee80211_local *local = hw_to_local(hw);
 
 
 	if (test_bit(queue, local->queues_pending)) {
 	if (test_bit(queue, local->queues_pending)) {
+		set_bit(queue, local->queues_pending_run);
 		tasklet_schedule(&local->tx_pending_tasklet);
 		tasklet_schedule(&local->tx_pending_tasklet);
 	} else {
 	} else {
 		netif_wake_subqueue(local->mdev, queue);
 		netif_wake_subqueue(local->mdev, queue);

+ 39 - 15
net/rfkill/rfkill-input.c

@@ -109,6 +109,25 @@ static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB);
 static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
 static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX);
 static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
 static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN);
 
 
+static void rfkill_schedule_evsw_rfkillall(int state)
+{
+	/* EVERY radio type. state != 0 means radios ON */
+	/* handle EPO (emergency power off) through shortcut */
+	if (state) {
+		rfkill_schedule_set(&rfkill_wwan,
+				    RFKILL_STATE_UNBLOCKED);
+		rfkill_schedule_set(&rfkill_wimax,
+				    RFKILL_STATE_UNBLOCKED);
+		rfkill_schedule_set(&rfkill_uwb,
+				    RFKILL_STATE_UNBLOCKED);
+		rfkill_schedule_set(&rfkill_bt,
+				    RFKILL_STATE_UNBLOCKED);
+		rfkill_schedule_set(&rfkill_wlan,
+				    RFKILL_STATE_UNBLOCKED);
+	} else
+		rfkill_schedule_epo();
+}
+
 static void rfkill_event(struct input_handle *handle, unsigned int type,
 static void rfkill_event(struct input_handle *handle, unsigned int type,
 			unsigned int code, int data)
 			unsigned int code, int data)
 {
 {
@@ -132,21 +151,7 @@ static void rfkill_event(struct input_handle *handle, unsigned int type,
 	} else if (type == EV_SW) {
 	} else if (type == EV_SW) {
 		switch (code) {
 		switch (code) {
 		case SW_RFKILL_ALL:
 		case SW_RFKILL_ALL:
-			/* EVERY radio type. data != 0 means radios ON */
-			/* handle EPO (emergency power off) through shortcut */
-			if (data) {
-				rfkill_schedule_set(&rfkill_wwan,
-						    RFKILL_STATE_UNBLOCKED);
-				rfkill_schedule_set(&rfkill_wimax,
-						    RFKILL_STATE_UNBLOCKED);
-				rfkill_schedule_set(&rfkill_uwb,
-						    RFKILL_STATE_UNBLOCKED);
-				rfkill_schedule_set(&rfkill_bt,
-						    RFKILL_STATE_UNBLOCKED);
-				rfkill_schedule_set(&rfkill_wlan,
-						    RFKILL_STATE_UNBLOCKED);
-			} else
-				rfkill_schedule_epo();
+			rfkill_schedule_evsw_rfkillall(data);
 			break;
 			break;
 		default:
 		default:
 			break;
 			break;
@@ -168,6 +173,7 @@ static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
 	handle->handler = handler;
 	handle->handler = handler;
 	handle->name = "rfkill";
 	handle->name = "rfkill";
 
 
+	/* causes rfkill_start() to be called */
 	error = input_register_handle(handle);
 	error = input_register_handle(handle);
 	if (error)
 	if (error)
 		goto err_free_handle;
 		goto err_free_handle;
@@ -185,6 +191,23 @@ static int rfkill_connect(struct input_handler *handler, struct input_dev *dev,
 	return error;
 	return error;
 }
 }
 
 
+static void rfkill_start(struct input_handle *handle)
+{
+	/* Take event_lock to guard against configuration changes, we
+	 * should be able to deal with concurrency with rfkill_event()
+	 * just fine (which event_lock will also avoid). */
+	spin_lock_irq(&handle->dev->event_lock);
+
+	if (test_bit(EV_SW, handle->dev->evbit)) {
+		if (test_bit(SW_RFKILL_ALL, handle->dev->swbit))
+			rfkill_schedule_evsw_rfkillall(test_bit(SW_RFKILL_ALL,
+							handle->dev->sw));
+		/* add resync for further EV_SW events here */
+	}
+
+	spin_unlock_irq(&handle->dev->event_lock);
+}
+
 static void rfkill_disconnect(struct input_handle *handle)
 static void rfkill_disconnect(struct input_handle *handle)
 {
 {
 	input_close_device(handle);
 	input_close_device(handle);
@@ -225,6 +248,7 @@ static struct input_handler rfkill_handler = {
 	.event =	rfkill_event,
 	.event =	rfkill_event,
 	.connect =	rfkill_connect,
 	.connect =	rfkill_connect,
 	.disconnect =	rfkill_disconnect,
 	.disconnect =	rfkill_disconnect,
+	.start =	rfkill_start,
 	.name =		"rfkill",
 	.name =		"rfkill",
 	.id_table =	rfkill_ids,
 	.id_table =	rfkill_ids,
 };
 };

+ 14 - 1
net/rfkill/rfkill.c

@@ -105,6 +105,16 @@ static void rfkill_led_trigger(struct rfkill *rfkill,
 #endif /* CONFIG_RFKILL_LEDS */
 #endif /* CONFIG_RFKILL_LEDS */
 }
 }
 
 
+#ifdef CONFIG_RFKILL_LEDS
+static void rfkill_led_trigger_activate(struct led_classdev *led)
+{
+	struct rfkill *rfkill = container_of(led->trigger,
+			struct rfkill, led_trigger);
+
+	rfkill_led_trigger(rfkill, rfkill->state);
+}
+#endif /* CONFIG_RFKILL_LEDS */
+
 static void notify_rfkill_state_change(struct rfkill *rfkill)
 static void notify_rfkill_state_change(struct rfkill *rfkill)
 {
 {
 	blocking_notifier_call_chain(&rfkill_notifier_list,
 	blocking_notifier_call_chain(&rfkill_notifier_list,
@@ -589,7 +599,10 @@ static void rfkill_led_trigger_register(struct rfkill *rfkill)
 #ifdef CONFIG_RFKILL_LEDS
 #ifdef CONFIG_RFKILL_LEDS
 	int error;
 	int error;
 
 
-	rfkill->led_trigger.name = rfkill->dev.bus_id;
+	if (!rfkill->led_trigger.name)
+		rfkill->led_trigger.name = rfkill->dev.bus_id;
+	if (!rfkill->led_trigger.activate)
+		rfkill->led_trigger.activate = rfkill_led_trigger_activate;
 	error = led_trigger_register(&rfkill->led_trigger);
 	error = led_trigger_register(&rfkill->led_trigger);
 	if (error)
 	if (error)
 		rfkill->led_trigger.name = NULL;
 		rfkill->led_trigger.name = NULL;

部分文件因文件數量過多而無法顯示