Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
This commit is contained in:
		
						commit
						3a999e6eb5
					
				| @ -88,27 +88,6 @@ Who:	Luis R. Rodriguez <lrodriguez@atheros.com> | ||||
| 
 | ||||
| --------------------------- | ||||
| 
 | ||||
| What:	CONFIG_WIRELESS_OLD_REGULATORY - old static regulatory information | ||||
| When:	March 2010 / desktop catchup | ||||
| 
 | ||||
| Why:	The old regulatory infrastructure has been replaced with a new one | ||||
| 	which does not require statically defined regulatory domains. We do | ||||
| 	not want to keep static regulatory domains in the kernel due to the | ||||
| 	the dynamic nature of regulatory law and localization. We kept around | ||||
| 	the old static definitions for the regulatory domains of: | ||||
| 
 | ||||
| 		* US | ||||
| 		* JP | ||||
| 		* EU | ||||
| 
 | ||||
| 	and used by default the US when CONFIG_WIRELESS_OLD_REGULATORY was | ||||
| 	set. We will remove this option once the standard Linux desktop catches | ||||
| 	up with the new userspace APIs we have implemented. | ||||
| 
 | ||||
| Who:	Luis R. Rodriguez <lrodriguez@atheros.com> | ||||
| 
 | ||||
| --------------------------- | ||||
| 
 | ||||
| What:	dev->power.power_state | ||||
| When:	July 2007 | ||||
| Why:	Broken design for runtime control over driver power states, confusing | ||||
|  | ||||
| @ -1400,15 +1400,15 @@ static void adm8211_configure_filter(struct ieee80211_hw *dev, | ||||
| } | ||||
| 
 | ||||
| static int adm8211_add_interface(struct ieee80211_hw *dev, | ||||
| 				 struct ieee80211_if_init_conf *conf) | ||||
| 				 struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct adm8211_priv *priv = dev->priv; | ||||
| 	if (priv->mode != NL80211_IFTYPE_MONITOR) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 		priv->mode = conf->type; | ||||
| 		priv->mode = vif->type; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EOPNOTSUPP; | ||||
| @ -1416,8 +1416,8 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, | ||||
| 
 | ||||
| 	ADM8211_IDLE(); | ||||
| 
 | ||||
| 	ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)conf->mac_addr)); | ||||
| 	ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); | ||||
| 	ADM8211_CSR_WRITE(PAR0, le32_to_cpu(*(__le32 *)vif->addr)); | ||||
| 	ADM8211_CSR_WRITE(PAR1, le16_to_cpu(*(__le16 *)(vif->addr + 4))); | ||||
| 
 | ||||
| 	adm8211_update_mode(dev); | ||||
| 
 | ||||
| @ -1427,7 +1427,7 @@ static int adm8211_add_interface(struct ieee80211_hw *dev, | ||||
| } | ||||
| 
 | ||||
| static void adm8211_remove_interface(struct ieee80211_hw *dev, | ||||
| 				     struct ieee80211_if_init_conf *conf) | ||||
| 				     struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct adm8211_priv *priv = dev->priv; | ||||
| 	priv->mode = NL80211_IFTYPE_MONITOR; | ||||
|  | ||||
| @ -1789,7 +1789,7 @@ static void at76_mac80211_stop(struct ieee80211_hw *hw) | ||||
| } | ||||
| 
 | ||||
| static int at76_add_interface(struct ieee80211_hw *hw, | ||||
| 			      struct ieee80211_if_init_conf *conf) | ||||
| 			      struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct at76_priv *priv = hw->priv; | ||||
| 	int ret = 0; | ||||
| @ -1798,7 +1798,7 @@ static int at76_add_interface(struct ieee80211_hw *hw, | ||||
| 
 | ||||
| 	mutex_lock(&priv->mtx); | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 		priv->iw_mode = IW_MODE_INFRA; | ||||
| 		break; | ||||
| @ -1814,7 +1814,7 @@ exit: | ||||
| } | ||||
| 
 | ||||
| static void at76_remove_interface(struct ieee80211_hw *hw, | ||||
| 				  struct ieee80211_if_init_conf *conf) | ||||
| 				  struct ieee80211_vif *vif) | ||||
| { | ||||
| 	at76_dbg(DBG_MAC80211, "%s()", __func__); | ||||
| } | ||||
|  | ||||
| @ -1939,7 +1939,7 @@ err_free: | ||||
| } | ||||
| 
 | ||||
| static int ar9170_op_add_interface(struct ieee80211_hw *hw, | ||||
| 				   struct ieee80211_if_init_conf *conf) | ||||
| 				   struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct ar9170 *ar = hw->priv; | ||||
| 	struct ath_common *common = &ar->common; | ||||
| @ -1952,8 +1952,8 @@ static int ar9170_op_add_interface(struct ieee80211_hw *hw, | ||||
| 		goto unlock; | ||||
| 	} | ||||
| 
 | ||||
| 	ar->vif = conf->vif; | ||||
| 	memcpy(common->macaddr, conf->mac_addr, ETH_ALEN); | ||||
| 	ar->vif = vif; | ||||
| 	memcpy(common->macaddr, vif->addr, ETH_ALEN); | ||||
| 
 | ||||
| 	if (modparam_nohwcrypt || (ar->vif->type != NL80211_IFTYPE_STATION)) { | ||||
| 		ar->rx_software_decryption = true; | ||||
| @ -1973,7 +1973,7 @@ unlock: | ||||
| } | ||||
| 
 | ||||
| static void ar9170_op_remove_interface(struct ieee80211_hw *hw, | ||||
| 				       struct ieee80211_if_init_conf *conf) | ||||
| 				       struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct ar9170 *ar = hw->priv; | ||||
| 
 | ||||
|  | ||||
| @ -225,9 +225,9 @@ static int ath5k_reset_wake(struct ath5k_softc *sc); | ||||
| static int ath5k_start(struct ieee80211_hw *hw); | ||||
| static void ath5k_stop(struct ieee80211_hw *hw); | ||||
| static int ath5k_add_interface(struct ieee80211_hw *hw, | ||||
| 		struct ieee80211_if_init_conf *conf); | ||||
| 		struct ieee80211_vif *vif); | ||||
| static void ath5k_remove_interface(struct ieee80211_hw *hw, | ||||
| 		struct ieee80211_if_init_conf *conf); | ||||
| 		struct ieee80211_vif *vif); | ||||
| static int ath5k_config(struct ieee80211_hw *hw, u32 changed); | ||||
| static u64 ath5k_prepare_multicast(struct ieee80211_hw *hw, | ||||
| 				   int mc_count, struct dev_addr_list *mc_list); | ||||
| @ -1903,17 +1903,6 @@ accept: | ||||
| 		rxs->noise = sc->ah->ah_noise_floor; | ||||
| 		rxs->signal = rxs->noise + rs.rs_rssi; | ||||
| 
 | ||||
| 		/* An rssi of 35 indicates you should be able use
 | ||||
| 		 * 54 Mbps reliably. A more elaborate scheme can be used | ||||
| 		 * here but it requires a map of SNR/throughput for each | ||||
| 		 * possible mode used */ | ||||
| 		rxs->qual = rs.rs_rssi * 100 / 35; | ||||
| 
 | ||||
| 		/* rssi can be more than 35 though, anything above that
 | ||||
| 		 * should be considered at 100% */ | ||||
| 		if (rxs->qual > 100) | ||||
| 			rxs->qual = 100; | ||||
| 
 | ||||
| 		rxs->antenna = rs.rs_antenna; | ||||
| 		rxs->rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); | ||||
| 		rxs->flag |= ath5k_rx_decrypted(sc, ds, skb, &rs); | ||||
| @ -2381,6 +2370,9 @@ ath5k_init(struct ath5k_softc *sc) | ||||
| 	 */ | ||||
| 	ath5k_stop_locked(sc); | ||||
| 
 | ||||
| 	/* Set PHY calibration interval */ | ||||
| 	ah->ah_cal_intval = ath5k_calinterval; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The basic interface to setting the hardware in a good | ||||
| 	 * state is ``reset''.  On return the hardware is known to | ||||
| @ -2408,10 +2400,6 @@ ath5k_init(struct ath5k_softc *sc) | ||||
| 
 | ||||
| 	/* Set ack to be sent at low bit-rates */ | ||||
| 	ath5k_hw_set_ack_bitrate_high(ah, false); | ||||
| 
 | ||||
| 	/* Set PHY calibration inteval */ | ||||
| 	ah->ah_cal_intval = ath5k_calinterval; | ||||
| 
 | ||||
| 	ret = 0; | ||||
| done: | ||||
| 	mmiowb(); | ||||
| @ -2785,7 +2773,7 @@ static void ath5k_stop(struct ieee80211_hw *hw) | ||||
| } | ||||
| 
 | ||||
| static int ath5k_add_interface(struct ieee80211_hw *hw, | ||||
| 		struct ieee80211_if_init_conf *conf) | ||||
| 		struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct ath5k_softc *sc = hw->priv; | ||||
| 	int ret; | ||||
| @ -2796,22 +2784,22 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, | ||||
| 		goto end; | ||||
| 	} | ||||
| 
 | ||||
| 	sc->vif = conf->vif; | ||||
| 	sc->vif = vif; | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_AP: | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 	case NL80211_IFTYPE_ADHOC: | ||||
| 	case NL80211_IFTYPE_MESH_POINT: | ||||
| 	case NL80211_IFTYPE_MONITOR: | ||||
| 		sc->opmode = conf->type; | ||||
| 		sc->opmode = vif->type; | ||||
| 		break; | ||||
| 	default: | ||||
| 		ret = -EOPNOTSUPP; | ||||
| 		goto end; | ||||
| 	} | ||||
| 
 | ||||
| 	ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); | ||||
| 	ath5k_hw_set_lladdr(sc->ah, vif->addr); | ||||
| 	ath5k_mode_setup(sc); | ||||
| 
 | ||||
| 	ret = 0; | ||||
| @ -2822,13 +2810,13 @@ end: | ||||
| 
 | ||||
| static void | ||||
| ath5k_remove_interface(struct ieee80211_hw *hw, | ||||
| 			struct ieee80211_if_init_conf *conf) | ||||
| 			struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct ath5k_softc *sc = hw->priv; | ||||
| 	u8 mac[ETH_ALEN] = {}; | ||||
| 
 | ||||
| 	mutex_lock(&sc->lock); | ||||
| 	if (sc->vif != conf->vif) | ||||
| 	if (sc->vif != vif) | ||||
| 		goto end; | ||||
| 
 | ||||
| 	ath5k_hw_set_lladdr(sc->ah, mac); | ||||
|  | ||||
| @ -77,6 +77,9 @@ | ||||
| #define ATH9K_TXERR_XTXOP          0x08 | ||||
| #define ATH9K_TXERR_TIMER_EXPIRED  0x10 | ||||
| #define ATH9K_TX_ACKED		   0x20 | ||||
| #define ATH9K_TXERR_MASK						\ | ||||
| 	(ATH9K_TXERR_XRETRY | ATH9K_TXERR_FILT | ATH9K_TXERR_FIFO |	\ | ||||
| 	 ATH9K_TXERR_XTXOP | ATH9K_TXERR_TIMER_EXPIRED) | ||||
| 
 | ||||
| #define ATH9K_TX_BA                0x01 | ||||
| #define ATH9K_TX_PWRMGMT           0x02 | ||||
|  | ||||
| @ -2504,6 +2504,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) | ||||
| 		return; /* another wiphy still in use */ | ||||
| 	} | ||||
| 
 | ||||
| 	/* Ensure HW is awake when we try to shut it down. */ | ||||
| 	ath9k_ps_wakeup(sc); | ||||
| 
 | ||||
| 	if (ah->btcoex_hw.enabled) { | ||||
| 		ath9k_hw_btcoex_disable(ah); | ||||
| 		if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) | ||||
| @ -2524,6 +2527,9 @@ static void ath9k_stop(struct ieee80211_hw *hw) | ||||
| 	/* disable HAL and put h/w to sleep */ | ||||
| 	ath9k_hw_disable(ah); | ||||
| 	ath9k_hw_configpcipowersave(ah, 1, 1); | ||||
| 	ath9k_ps_restore(sc); | ||||
| 
 | ||||
| 	/* Finally, put the chip in FULL SLEEP mode */ | ||||
| 	ath9k_setpower(sc, ATH9K_PM_FULL_SLEEP); | ||||
| 
 | ||||
| 	sc->sc_flags |= SC_OP_INVALID; | ||||
| @ -2534,12 +2540,12 @@ static void ath9k_stop(struct ieee80211_hw *hw) | ||||
| } | ||||
| 
 | ||||
| static int ath9k_add_interface(struct ieee80211_hw *hw, | ||||
| 			       struct ieee80211_if_init_conf *conf) | ||||
| 			       struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct ath_wiphy *aphy = hw->priv; | ||||
| 	struct ath_softc *sc = aphy->sc; | ||||
| 	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||||
| 	struct ath_vif *avp = (void *)conf->vif->drv_priv; | ||||
| 	struct ath_vif *avp = (void *)vif->drv_priv; | ||||
| 	enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| @ -2551,7 +2557,7 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 		ic_opmode = NL80211_IFTYPE_STATION; | ||||
| 		break; | ||||
| @ -2562,11 +2568,11 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | ||||
| 			ret = -ENOBUFS; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		ic_opmode = conf->type; | ||||
| 		ic_opmode = vif->type; | ||||
| 		break; | ||||
| 	default: | ||||
| 		ath_print(common, ATH_DBG_FATAL, | ||||
| 			"Interface type %d not yet supported\n", conf->type); | ||||
| 			"Interface type %d not yet supported\n", vif->type); | ||||
| 		ret = -EOPNOTSUPP; | ||||
| 		goto out; | ||||
| 	} | ||||
| @ -2598,18 +2604,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | ||||
| 	 * Enable MIB interrupts when there are hardware phy counters. | ||||
| 	 * Note we only do this (at the moment) for station mode. | ||||
| 	 */ | ||||
| 	if ((conf->type == NL80211_IFTYPE_STATION) || | ||||
| 	    (conf->type == NL80211_IFTYPE_ADHOC) || | ||||
| 	    (conf->type == NL80211_IFTYPE_MESH_POINT)) { | ||||
| 	if ((vif->type == NL80211_IFTYPE_STATION) || | ||||
| 	    (vif->type == NL80211_IFTYPE_ADHOC) || | ||||
| 	    (vif->type == NL80211_IFTYPE_MESH_POINT)) { | ||||
| 		sc->imask |= ATH9K_INT_MIB; | ||||
| 		sc->imask |= ATH9K_INT_TSFOOR; | ||||
| 	} | ||||
| 
 | ||||
| 	ath9k_hw_set_interrupts(sc->sc_ah, sc->imask); | ||||
| 
 | ||||
| 	if (conf->type == NL80211_IFTYPE_AP    || | ||||
| 	    conf->type == NL80211_IFTYPE_ADHOC || | ||||
| 	    conf->type == NL80211_IFTYPE_MONITOR) | ||||
| 	if (vif->type == NL80211_IFTYPE_AP    || | ||||
| 	    vif->type == NL80211_IFTYPE_ADHOC || | ||||
| 	    vif->type == NL80211_IFTYPE_MONITOR) | ||||
| 		ath_start_ani(common); | ||||
| 
 | ||||
| out: | ||||
| @ -2618,12 +2624,12 @@ out: | ||||
| } | ||||
| 
 | ||||
| static void ath9k_remove_interface(struct ieee80211_hw *hw, | ||||
| 				   struct ieee80211_if_init_conf *conf) | ||||
| 				   struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct ath_wiphy *aphy = hw->priv; | ||||
| 	struct ath_softc *sc = aphy->sc; | ||||
| 	struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||||
| 	struct ath_vif *avp = (void *)conf->vif->drv_priv; | ||||
| 	struct ath_vif *avp = (void *)vif->drv_priv; | ||||
| 	int i; | ||||
| 
 | ||||
| 	ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n"); | ||||
| @ -2637,14 +2643,16 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | ||||
| 	if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) || | ||||
| 	    (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) || | ||||
| 	    (sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT)) { | ||||
| 		ath9k_ps_wakeup(sc); | ||||
| 		ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); | ||||
| 		ath_beacon_return(sc, avp); | ||||
| 		ath9k_ps_restore(sc); | ||||
| 	} | ||||
| 
 | ||||
| 	sc->sc_flags &= ~SC_OP_BEACONS; | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) { | ||||
| 		if (sc->beacon.bslot[i] == conf->vif) { | ||||
| 		if (sc->beacon.bslot[i] == vif) { | ||||
| 			printk(KERN_DEBUG "%s: vif had allocated beacon " | ||||
| 			       "slot\n", __func__); | ||||
| 			sc->beacon.bslot[i] = NULL; | ||||
| @ -3087,15 +3095,21 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | ||||
| 	case IEEE80211_AMPDU_RX_STOP: | ||||
| 		break; | ||||
| 	case IEEE80211_AMPDU_TX_START: | ||||
| 		ath9k_ps_wakeup(sc); | ||||
| 		ath_tx_aggr_start(sc, sta, tid, ssn); | ||||
| 		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||||
| 		ath9k_ps_restore(sc); | ||||
| 		break; | ||||
| 	case IEEE80211_AMPDU_TX_STOP: | ||||
| 		ath9k_ps_wakeup(sc); | ||||
| 		ath_tx_aggr_stop(sc, sta, tid); | ||||
| 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | ||||
| 		ath9k_ps_restore(sc); | ||||
| 		break; | ||||
| 	case IEEE80211_AMPDU_TX_OPERATIONAL: | ||||
| 		ath9k_ps_wakeup(sc); | ||||
| 		ath_tx_aggr_resume(sc, sta, tid); | ||||
| 		ath9k_ps_restore(sc); | ||||
| 		break; | ||||
| 	default: | ||||
| 		ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL, | ||||
|  | ||||
| @ -96,7 +96,7 @@ static void ath_pci_bt_coex_prep(struct ath_common *common) | ||||
| 	pci_write_config_byte(pdev, ATH_PCIE_CAP_LINK_CTRL, aspm); | ||||
| } | ||||
| 
 | ||||
| const static struct ath_bus_ops ath_pci_bus_ops = { | ||||
| static const struct ath_bus_ops ath_pci_bus_ops = { | ||||
| 	.read_cachesize = ath_pci_read_cachesize, | ||||
| 	.cleanup = ath_pci_cleanup, | ||||
| 	.eeprom_read = ath_pci_eeprom_read, | ||||
|  | ||||
| @ -2072,7 +2072,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) | ||||
| 				&txq->axq_q, lastbf->list.prev); | ||||
| 
 | ||||
| 		txq->axq_depth--; | ||||
| 		txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_FILT); | ||||
| 		txok = !(ds->ds_txstat.ts_status & ATH9K_TXERR_MASK); | ||||
| 		txq->axq_tx_inprogress = false; | ||||
| 		spin_unlock_bh(&txq->axq_lock); | ||||
| 
 | ||||
|  | ||||
| @ -3,6 +3,7 @@ config B43 | ||||
| 	depends on SSB_POSSIBLE && MAC80211 && HAS_DMA | ||||
| 	select SSB | ||||
| 	select FW_LOADER | ||||
| 	select SSB_BLOCKIO | ||||
| 	---help--- | ||||
| 	  b43 is a driver for the Broadcom 43xx series wireless devices. | ||||
| 
 | ||||
| @ -78,14 +79,6 @@ config B43_SDIO | ||||
| 
 | ||||
| 	  If unsure, say N. | ||||
| 
 | ||||
| # Data transfers to the device via PIO | ||||
| # This is only needed on PCMCIA and SDIO devices. All others can do DMA properly. | ||||
| config B43_PIO | ||||
| 	bool | ||||
| 	depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO) | ||||
| 	select SSB_BLOCKIO | ||||
| 	default y | ||||
| 
 | ||||
| config B43_NPHY | ||||
| 	bool "Pre IEEE 802.11n support (BROKEN)" | ||||
| 	depends on B43 && EXPERIMENTAL && BROKEN | ||||
| @ -137,12 +130,4 @@ config B43_DEBUG | ||||
| 	  for production use. | ||||
| 	  Only say Y, if you are debugging a problem in the b43 driver sourcecode. | ||||
| 
 | ||||
| config B43_FORCE_PIO | ||||
| 	bool "Force usage of PIO instead of DMA" | ||||
| 	depends on B43 && B43_DEBUG | ||||
| 	---help--- | ||||
| 	  This will disable DMA and always enable PIO instead. | ||||
| 
 | ||||
| 	  Say N! | ||||
| 	  This is only for debugging the PIO engine code. You do | ||||
| 	  _NOT_ want to enable this. | ||||
|  | ||||
| @ -12,7 +12,7 @@ b43-y				+= xmit.o | ||||
| b43-y				+= lo.o | ||||
| b43-y				+= wa.o | ||||
| b43-y				+= dma.o | ||||
| b43-$(CONFIG_B43_PIO)		+= pio.o | ||||
| b43-y				+= pio.o | ||||
| b43-y				+= rfkill.o | ||||
| b43-$(CONFIG_B43_LEDS)		+= leds.o | ||||
| b43-$(CONFIG_B43_PCMCIA)	+= pcmcia.o | ||||
|  | ||||
| @ -821,11 +821,9 @@ struct b43_wl { | ||||
| 	/* The device LEDs. */ | ||||
| 	struct b43_leds leds; | ||||
| 
 | ||||
| #ifdef CONFIG_B43_PIO | ||||
| 	/* Kmalloc'ed scratch space for PIO TX/RX. Protected by wl->mutex. */ | ||||
| 	u8 pio_scratchspace[110] __attribute__((__aligned__(8))); | ||||
| 	u8 pio_tailspace[4] __attribute__((__aligned__(8))); | ||||
| #endif /* CONFIG_B43_PIO */ | ||||
| }; | ||||
| 
 | ||||
| static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw) | ||||
| @ -876,20 +874,9 @@ static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value) | ||||
| 
 | ||||
| static inline bool b43_using_pio_transfers(struct b43_wldev *dev) | ||||
| { | ||||
| #ifdef CONFIG_B43_PIO | ||||
| 	return dev->__using_pio_transfers; | ||||
| #else | ||||
| 	return 0; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_B43_FORCE_PIO | ||||
| # define B43_FORCE_PIO	1 | ||||
| #else | ||||
| # define B43_FORCE_PIO	0 | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| /* Message printing */ | ||||
| void b43info(struct b43_wl *wl, const char *fmt, ...) | ||||
|     __attribute__ ((format(printf, 2, 3))); | ||||
|  | ||||
| @ -383,160 +383,44 @@ static inline | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* Check if a DMA region fits the device constraints.
 | ||||
|  * Returns true, if the region is OK for usage with this device. */ | ||||
| static inline bool b43_dma_address_ok(struct b43_dmaring *ring, | ||||
| 				      dma_addr_t addr, size_t size) | ||||
| { | ||||
| 	switch (ring->type) { | ||||
| 	case B43_DMA_30BIT: | ||||
| 		if ((u64)addr + size > (1ULL << 30)) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case B43_DMA_32BIT: | ||||
| 		if ((u64)addr + size > (1ULL << 32)) | ||||
| 			return 0; | ||||
| 		break; | ||||
| 	case B43_DMA_64BIT: | ||||
| 		/* Currently we can't have addresses beyond
 | ||||
| 		 * 64bit in the kernel. */ | ||||
| 		break; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| #define is_4k_aligned(addr)	(((u64)(addr) & 0x0FFFull) == 0) | ||||
| #define is_8k_aligned(addr)	(((u64)(addr) & 0x1FFFull) == 0) | ||||
| 
 | ||||
| static void b43_unmap_and_free_ringmem(struct b43_dmaring *ring, void *base, | ||||
| 				       dma_addr_t dmaaddr, size_t size) | ||||
| { | ||||
| 	ssb_dma_unmap_single(ring->dev->dev, dmaaddr, size, DMA_TO_DEVICE); | ||||
| 	free_pages((unsigned long)base, get_order(size)); | ||||
| } | ||||
| 
 | ||||
| static void * __b43_get_and_map_ringmem(struct b43_dmaring *ring, | ||||
| 					dma_addr_t *dmaaddr, size_t size, | ||||
| 					gfp_t gfp_flags) | ||||
| { | ||||
| 	void *base; | ||||
| 
 | ||||
| 	base = (void *)__get_free_pages(gfp_flags, get_order(size)); | ||||
| 	if (!base) | ||||
| 		return NULL; | ||||
| 	memset(base, 0, size); | ||||
| 	*dmaaddr = ssb_dma_map_single(ring->dev->dev, base, size, | ||||
| 				      DMA_TO_DEVICE); | ||||
| 	if (ssb_dma_mapping_error(ring->dev->dev, *dmaaddr)) { | ||||
| 		free_pages((unsigned long)base, get_order(size)); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return base; | ||||
| } | ||||
| 
 | ||||
| static void * b43_get_and_map_ringmem(struct b43_dmaring *ring, | ||||
| 				      dma_addr_t *dmaaddr, size_t size) | ||||
| { | ||||
| 	void *base; | ||||
| 
 | ||||
| 	base = __b43_get_and_map_ringmem(ring, dmaaddr, size, | ||||
| 					 GFP_KERNEL); | ||||
| 	if (!base) { | ||||
| 		b43err(ring->dev->wl, "Failed to allocate or map pages " | ||||
| 		       "for DMA ringmemory\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	if (!b43_dma_address_ok(ring, *dmaaddr, size)) { | ||||
| 		/* The memory does not fit our device constraints.
 | ||||
| 		 * Retry with GFP_DMA set to get lower memory. */ | ||||
| 		b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size); | ||||
| 		base = __b43_get_and_map_ringmem(ring, dmaaddr, size, | ||||
| 						 GFP_KERNEL | GFP_DMA); | ||||
| 		if (!base) { | ||||
| 			b43err(ring->dev->wl, "Failed to allocate or map pages " | ||||
| 			       "in the GFP_DMA region for DMA ringmemory\n"); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 		if (!b43_dma_address_ok(ring, *dmaaddr, size)) { | ||||
| 			b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size); | ||||
| 			b43err(ring->dev->wl, "Failed to allocate DMA " | ||||
| 			       "ringmemory that fits device constraints\n"); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} | ||||
| 	/* We expect the memory to be 4k aligned, at least. */ | ||||
| 	if (B43_WARN_ON(!is_4k_aligned(*dmaaddr))) { | ||||
| 		b43_unmap_and_free_ringmem(ring, base, *dmaaddr, size); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return base; | ||||
| } | ||||
| 
 | ||||
| static int alloc_ringmemory(struct b43_dmaring *ring) | ||||
| { | ||||
| 	unsigned int required; | ||||
| 	void *base; | ||||
| 	dma_addr_t dmaaddr; | ||||
| 	gfp_t flags = GFP_KERNEL; | ||||
| 
 | ||||
| 	/* There are several requirements to the descriptor ring memory:
 | ||||
| 	 * - The memory region needs to fit the address constraints for the | ||||
| 	 *   device (same as for frame buffers). | ||||
| 	 * - For 30/32bit DMA devices, the descriptor ring must be 4k aligned. | ||||
| 	 * - For 64bit DMA devices, the descriptor ring must be 8k aligned. | ||||
| 	/* The specs call for 4K buffers for 30- and 32-bit DMA with 4K
 | ||||
| 	 * alignment and 8K buffers for 64-bit DMA with 8K alignment. Testing | ||||
| 	 * has shown that 4K is sufficient for the latter as long as the buffer | ||||
| 	 * does not cross an 8K boundary. | ||||
| 	 * | ||||
| 	 * For unknown reasons - possibly a hardware error - the BCM4311 rev | ||||
| 	 * 02, which uses 64-bit DMA, needs the ring buffer in very low memory, | ||||
| 	 * which accounts for the GFP_DMA flag below. | ||||
| 	 * | ||||
| 	 * The flags here must match the flags in free_ringmemory below! | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (ring->type == B43_DMA_64BIT) | ||||
| 		required = ring->nr_slots * sizeof(struct b43_dmadesc64); | ||||
| 	else | ||||
| 		required = ring->nr_slots * sizeof(struct b43_dmadesc32); | ||||
| 	if (B43_WARN_ON(required > 0x1000)) | ||||
| 		flags |= GFP_DMA; | ||||
| 	ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev, | ||||
| 						  B43_DMA_RINGMEMSIZE, | ||||
| 						  &(ring->dmabase), flags); | ||||
| 	if (!ring->descbase) { | ||||
| 		b43err(ring->dev->wl, "DMA ringmemory allocation failed\n"); | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	ring->alloc_descsize = 0x1000; | ||||
| 	base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize); | ||||
| 	if (!base) | ||||
| 		return -ENOMEM; | ||||
| 	ring->alloc_descbase = base; | ||||
| 	ring->alloc_dmabase = dmaaddr; | ||||
| 
 | ||||
| 	if ((ring->type != B43_DMA_64BIT) || is_8k_aligned(dmaaddr)) { | ||||
| 		/* We're on <=32bit DMA, or we already got 8k aligned memory.
 | ||||
| 		 * That's all we need, so we're fine. */ | ||||
| 		ring->descbase = base; | ||||
| 		ring->dmabase = dmaaddr; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	b43_unmap_and_free_ringmem(ring, base, dmaaddr, ring->alloc_descsize); | ||||
| 
 | ||||
| 	/* Ok, we failed at the 8k alignment requirement.
 | ||||
| 	 * Try to force-align the memory region now. */ | ||||
| 	ring->alloc_descsize = 0x2000; | ||||
| 	base = b43_get_and_map_ringmem(ring, &dmaaddr, ring->alloc_descsize); | ||||
| 	if (!base) | ||||
| 		return -ENOMEM; | ||||
| 	ring->alloc_descbase = base; | ||||
| 	ring->alloc_dmabase = dmaaddr; | ||||
| 
 | ||||
| 	if (is_8k_aligned(dmaaddr)) { | ||||
| 		/* We're already 8k aligned. That Ok, too. */ | ||||
| 		ring->descbase = base; | ||||
| 		ring->dmabase = dmaaddr; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	/* Force-align it to 8k */ | ||||
| 	ring->descbase = (void *)((u8 *)base + 0x1000); | ||||
| 	ring->dmabase = dmaaddr + 0x1000; | ||||
| 	B43_WARN_ON(!is_8k_aligned(ring->dmabase)); | ||||
| 	memset(ring->descbase, 0, B43_DMA_RINGMEMSIZE); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void free_ringmemory(struct b43_dmaring *ring) | ||||
| { | ||||
| 	b43_unmap_and_free_ringmem(ring, ring->alloc_descbase, | ||||
| 				   ring->alloc_dmabase, ring->alloc_descsize); | ||||
| 	gfp_t flags = GFP_KERNEL; | ||||
| 
 | ||||
| 	if (ring->type == B43_DMA_64BIT) | ||||
| 		flags |= GFP_DMA; | ||||
| 
 | ||||
| 	ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE, | ||||
| 				ring->descbase, ring->dmabase, flags); | ||||
| } | ||||
| 
 | ||||
| /* Reset the RX DMA channel */ | ||||
| @ -646,14 +530,29 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring, | ||||
| 	if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr))) | ||||
| 		return 1; | ||||
| 
 | ||||
| 	if (!b43_dma_address_ok(ring, addr, buffersize)) { | ||||
| 		/* We can't support this address. Unmap it again. */ | ||||
| 		unmap_descbuffer(ring, addr, buffersize, dma_to_device); | ||||
| 		return 1; | ||||
| 	switch (ring->type) { | ||||
| 	case B43_DMA_30BIT: | ||||
| 		if ((u64)addr + buffersize > (1ULL << 30)) | ||||
| 			goto address_error; | ||||
| 		break; | ||||
| 	case B43_DMA_32BIT: | ||||
| 		if ((u64)addr + buffersize > (1ULL << 32)) | ||||
| 			goto address_error; | ||||
| 		break; | ||||
| 	case B43_DMA_64BIT: | ||||
| 		/* Currently we can't have addresses beyond
 | ||||
| 		 * 64bit in the kernel. */ | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
| 	/* The address is OK. */ | ||||
| 	return 0; | ||||
| 
 | ||||
| address_error: | ||||
| 	/* We can't support this address. Unmap it again. */ | ||||
| 	unmap_descbuffer(ring, addr, buffersize, dma_to_device); | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb) | ||||
| @ -715,9 +614,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring, | ||||
| 	meta->dmaaddr = dmaaddr; | ||||
| 	ring->ops->fill_descriptor(ring, desc, dmaaddr, | ||||
| 				   ring->rx_buffersize, 0, 0, 0); | ||||
| 	ssb_dma_sync_single_for_device(ring->dev->dev, | ||||
| 				       ring->alloc_dmabase, | ||||
| 				       ring->alloc_descsize, DMA_TO_DEVICE); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| @ -1354,9 +1250,6 @@ static int dma_tx_fragment(struct b43_dmaring *ring, | ||||
| 	} | ||||
| 	/* Now transfer the whole frame. */ | ||||
| 	wmb(); | ||||
| 	ssb_dma_sync_single_for_device(ring->dev->dev, | ||||
| 				       ring->alloc_dmabase, | ||||
| 				       ring->alloc_descsize, DMA_TO_DEVICE); | ||||
| 	ops->poke_tx(ring, next_slot(ring, slot)); | ||||
| 	return 0; | ||||
| 
 | ||||
| @ -1760,7 +1653,6 @@ void b43_dma_tx_resume(struct b43_wldev *dev) | ||||
| 	b43_power_saving_ctl_bits(dev, 0); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_B43_PIO | ||||
| static void direct_fifo_rx(struct b43_wldev *dev, enum b43_dmatype type, | ||||
| 			   u16 mmio_base, bool enable) | ||||
| { | ||||
| @ -1794,4 +1686,3 @@ void b43_dma_direct_fifo_rx(struct b43_wldev *dev, | ||||
| 	mmio_base = b43_dmacontroller_base(type, engine_index); | ||||
| 	direct_fifo_rx(dev, type, mmio_base, enable); | ||||
| } | ||||
| #endif /* CONFIG_B43_PIO */ | ||||
|  | ||||
| @ -157,6 +157,7 @@ struct b43_dmadesc_generic { | ||||
| } __attribute__ ((__packed__)); | ||||
| 
 | ||||
| /* Misc DMA constants */ | ||||
| #define B43_DMA_RINGMEMSIZE		PAGE_SIZE | ||||
| #define B43_DMA0_RX_FRAMEOFFSET		30 | ||||
| 
 | ||||
| /* DMA engine tuning knobs */ | ||||
| @ -246,12 +247,6 @@ struct b43_dmaring { | ||||
| 	/* The QOS priority assigned to this ring. Only used for TX rings.
 | ||||
| 	 * This is the mac80211 "queue" value. */ | ||||
| 	u8 queue_prio; | ||||
| 	/* Pointers and size of the originally allocated and mapped memory
 | ||||
| 	 * region for the descriptor ring. */ | ||||
| 	void *alloc_descbase; | ||||
| 	dma_addr_t alloc_dmabase; | ||||
| 	unsigned int alloc_descsize; | ||||
| 	/* Pointer to our wireless device. */ | ||||
| 	struct b43_wldev *dev; | ||||
| #ifdef CONFIG_B43_DEBUG | ||||
| 	/* Maximum number of used slots. */ | ||||
|  | ||||
| @ -102,6 +102,9 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT; | ||||
| module_param_named(verbose, b43_modparam_verbose, int, 0644); | ||||
| MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug"); | ||||
| 
 | ||||
| static int modparam_pio; | ||||
| module_param_named(pio, modparam_pio, int, 0444); | ||||
| MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); | ||||
| 
 | ||||
| static const struct ssb_device_id b43_ssb_tbl[] = { | ||||
| 	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5), | ||||
| @ -1786,8 +1789,8 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev) | ||||
| 			       dma_reason[4], dma_reason[5]); | ||||
| 			b43err(dev->wl, "This device does not support DMA " | ||||
| 			       "on your system. Please use PIO instead.\n"); | ||||
| 			b43err(dev->wl, "CONFIG_B43_FORCE_PIO must be set in " | ||||
| 			       "your kernel configuration.\n"); | ||||
| 			b43err(dev->wl, "Unload the b43 module and reload " | ||||
| 			       "with 'pio=1'\n"); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) { | ||||
| @ -4353,7 +4356,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) | ||||
| 
 | ||||
| 	if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || | ||||
| 	    (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) || | ||||
| 	    B43_FORCE_PIO) { | ||||
| 	    modparam_pio) { | ||||
| 		dev->__using_pio_transfers = 1; | ||||
| 		err = b43_pio_init(dev); | ||||
| 	} else { | ||||
| @ -4388,7 +4391,7 @@ err_busdown: | ||||
| } | ||||
| 
 | ||||
| static int b43_op_add_interface(struct ieee80211_hw *hw, | ||||
| 				struct ieee80211_if_init_conf *conf) | ||||
| 				struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct b43_wl *wl = hw_to_b43_wl(hw); | ||||
| 	struct b43_wldev *dev; | ||||
| @ -4396,24 +4399,24 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, | ||||
| 
 | ||||
| 	/* TODO: allow WDS/AP devices to coexist */ | ||||
| 
 | ||||
| 	if (conf->type != NL80211_IFTYPE_AP && | ||||
| 	    conf->type != NL80211_IFTYPE_MESH_POINT && | ||||
| 	    conf->type != NL80211_IFTYPE_STATION && | ||||
| 	    conf->type != NL80211_IFTYPE_WDS && | ||||
| 	    conf->type != NL80211_IFTYPE_ADHOC) | ||||
| 	if (vif->type != NL80211_IFTYPE_AP && | ||||
| 	    vif->type != NL80211_IFTYPE_MESH_POINT && | ||||
| 	    vif->type != NL80211_IFTYPE_STATION && | ||||
| 	    vif->type != NL80211_IFTYPE_WDS && | ||||
| 	    vif->type != NL80211_IFTYPE_ADHOC) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 	if (wl->operating) | ||||
| 		goto out_mutex_unlock; | ||||
| 
 | ||||
| 	b43dbg(wl, "Adding Interface type %d\n", conf->type); | ||||
| 	b43dbg(wl, "Adding Interface type %d\n", vif->type); | ||||
| 
 | ||||
| 	dev = wl->current_dev; | ||||
| 	wl->operating = 1; | ||||
| 	wl->vif = conf->vif; | ||||
| 	wl->if_type = conf->type; | ||||
| 	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); | ||||
| 	wl->vif = vif; | ||||
| 	wl->if_type = vif->type; | ||||
| 	memcpy(wl->mac_addr, vif->addr, ETH_ALEN); | ||||
| 
 | ||||
| 	b43_adjust_opmode(dev); | ||||
| 	b43_set_pretbtt(dev); | ||||
| @ -4428,17 +4431,17 @@ static int b43_op_add_interface(struct ieee80211_hw *hw, | ||||
| } | ||||
| 
 | ||||
| static void b43_op_remove_interface(struct ieee80211_hw *hw, | ||||
| 				    struct ieee80211_if_init_conf *conf) | ||||
| 				    struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct b43_wl *wl = hw_to_b43_wl(hw); | ||||
| 	struct b43_wldev *dev = wl->current_dev; | ||||
| 
 | ||||
| 	b43dbg(wl, "Removing Interface type %d\n", conf->type); | ||||
| 	b43dbg(wl, "Removing Interface type %d\n", vif->type); | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 
 | ||||
| 	B43_WARN_ON(!wl->operating); | ||||
| 	B43_WARN_ON(wl->vif != conf->vif); | ||||
| 	B43_WARN_ON(wl->vif != vif); | ||||
| 	wl->vif = NULL; | ||||
| 
 | ||||
| 	wl->operating = 0; | ||||
|  | ||||
| @ -55,8 +55,6 @@ | ||||
| #define B43_PIO_MAX_NR_TXPACKETS	32 | ||||
| 
 | ||||
| 
 | ||||
| #ifdef CONFIG_B43_PIO | ||||
| 
 | ||||
| struct b43_pio_txpacket { | ||||
| 	/* Pointer to the TX queue we belong to. */ | ||||
| 	struct b43_pio_txqueue *queue; | ||||
| @ -169,42 +167,4 @@ void b43_pio_rx(struct b43_pio_rxqueue *q); | ||||
| void b43_pio_tx_suspend(struct b43_wldev *dev); | ||||
| void b43_pio_tx_resume(struct b43_wldev *dev); | ||||
| 
 | ||||
| 
 | ||||
| #else /* CONFIG_B43_PIO */ | ||||
| 
 | ||||
| 
 | ||||
| static inline int b43_pio_init(struct b43_wldev *dev) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| static inline void b43_pio_free(struct b43_wldev *dev) | ||||
| { | ||||
| } | ||||
| static inline void b43_pio_stop(struct b43_wldev *dev) | ||||
| { | ||||
| } | ||||
| static inline int b43_pio_tx(struct b43_wldev *dev, | ||||
| 			     struct sk_buff *skb) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| static inline void b43_pio_handle_txstatus(struct b43_wldev *dev, | ||||
| 					   const struct b43_txstatus *status) | ||||
| { | ||||
| } | ||||
| static inline void b43_pio_get_tx_stats(struct b43_wldev *dev, | ||||
| 					struct ieee80211_tx_queue_stats *stats) | ||||
| { | ||||
| } | ||||
| static inline void b43_pio_rx(struct b43_pio_rxqueue *q) | ||||
| { | ||||
| } | ||||
| static inline void b43_pio_tx_suspend(struct b43_wldev *dev) | ||||
| { | ||||
| } | ||||
| static inline void b43_pio_tx_resume(struct b43_wldev *dev) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| #endif /* CONFIG_B43_PIO */ | ||||
| #endif /* B43_PIO_H_ */ | ||||
|  | ||||
| @ -3361,7 +3361,7 @@ err_kfree_lo_control: | ||||
| } | ||||
| 
 | ||||
| static int b43legacy_op_add_interface(struct ieee80211_hw *hw, | ||||
| 				      struct ieee80211_if_init_conf *conf) | ||||
| 				      struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); | ||||
| 	struct b43legacy_wldev *dev; | ||||
| @ -3370,23 +3370,23 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw, | ||||
| 
 | ||||
| 	/* TODO: allow WDS/AP devices to coexist */ | ||||
| 
 | ||||
| 	if (conf->type != NL80211_IFTYPE_AP && | ||||
| 	    conf->type != NL80211_IFTYPE_STATION && | ||||
| 	    conf->type != NL80211_IFTYPE_WDS && | ||||
| 	    conf->type != NL80211_IFTYPE_ADHOC) | ||||
| 	if (vif->type != NL80211_IFTYPE_AP && | ||||
| 	    vif->type != NL80211_IFTYPE_STATION && | ||||
| 	    vif->type != NL80211_IFTYPE_WDS && | ||||
| 	    vif->type != NL80211_IFTYPE_ADHOC) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 	if (wl->operating) | ||||
| 		goto out_mutex_unlock; | ||||
| 
 | ||||
| 	b43legacydbg(wl, "Adding Interface type %d\n", conf->type); | ||||
| 	b43legacydbg(wl, "Adding Interface type %d\n", vif->type); | ||||
| 
 | ||||
| 	dev = wl->current_dev; | ||||
| 	wl->operating = 1; | ||||
| 	wl->vif = conf->vif; | ||||
| 	wl->if_type = conf->type; | ||||
| 	memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); | ||||
| 	wl->vif = vif; | ||||
| 	wl->if_type = vif->type; | ||||
| 	memcpy(wl->mac_addr, vif->addr, ETH_ALEN); | ||||
| 
 | ||||
| 	spin_lock_irqsave(&wl->irq_lock, flags); | ||||
| 	b43legacy_adjust_opmode(dev); | ||||
| @ -3403,18 +3403,18 @@ static int b43legacy_op_add_interface(struct ieee80211_hw *hw, | ||||
| } | ||||
| 
 | ||||
| static void b43legacy_op_remove_interface(struct ieee80211_hw *hw, | ||||
| 					  struct ieee80211_if_init_conf *conf) | ||||
| 					  struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); | ||||
| 	struct b43legacy_wldev *dev = wl->current_dev; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	b43legacydbg(wl, "Removing Interface type %d\n", conf->type); | ||||
| 	b43legacydbg(wl, "Removing Interface type %d\n", vif->type); | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 
 | ||||
| 	B43legacy_WARN_ON(!wl->operating); | ||||
| 	B43legacy_WARN_ON(wl->vif != conf->vif); | ||||
| 	B43legacy_WARN_ON(wl->vif != vif); | ||||
| 	wl->vif = NULL; | ||||
| 
 | ||||
| 	wl->operating = 0; | ||||
|  | ||||
| @ -681,19 +681,13 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv, | ||||
| 		snr = rx_stats_sig_avg / rx_stats_noise_diff; | ||||
| 		rx_status.noise = rx_status.signal - | ||||
| 					iwl3945_calc_db_from_ratio(snr); | ||||
| 		rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, | ||||
| 							 rx_status.noise); | ||||
| 
 | ||||
| 	/* If noise info not available, calculate signal quality indicator (%)
 | ||||
| 	 *   using just the dBm signal level. */ | ||||
| 	} else { | ||||
| 		rx_status.noise = priv->last_rx_noise; | ||||
| 		rx_status.qual = iwl3945_calc_sig_qual(rx_status.signal, 0); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	IWL_DEBUG_STATS(priv, "Rssi %d noise %d qual %d sig_avg %d noise_diff %d\n", | ||||
| 			rx_status.signal, rx_status.noise, rx_status.qual, | ||||
| 	IWL_DEBUG_STATS(priv, "Rssi %d noise %d sig_avg %d noise_diff %d\n", | ||||
| 			rx_status.signal, rx_status.noise, | ||||
| 			rx_stats_sig_avg, rx_stats_noise_diff); | ||||
| 
 | ||||
| 	header = (struct ieee80211_hdr *)IWL_RX_DATA(pkt); | ||||
|  | ||||
| @ -222,7 +222,6 @@ struct iwl3945_ibss_seq { | ||||
|  * | ||||
|  *****************************************************************************/ | ||||
| extern int iwl3945_calc_db_from_ratio(int sig_ratio); | ||||
| extern int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm); | ||||
| extern void iwl3945_rx_replenish(void *data); | ||||
| extern void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); | ||||
| extern unsigned int iwl3945_fill_beacon_frame(struct iwl_priv *priv, | ||||
|  | ||||
| @ -150,7 +150,7 @@ static s32 expected_tpt_mimo3_40MHz[4][IWL_RATE_COUNT] = { | ||||
| }; | ||||
| 
 | ||||
| /* mbps, mcs */ | ||||
| const static struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { | ||||
| static const struct iwl_rate_mcs_info iwl_rate_mcs[IWL_RATE_COUNT] = { | ||||
| 	{  "1", "BPSK DSSS"}, | ||||
| 	{  "2", "QPSK DSSS"}, | ||||
| 	{"5.5", "BPSK CCK"}, | ||||
|  | ||||
| @ -2584,12 +2584,12 @@ int iwl_set_mode(struct iwl_priv *priv, int mode) | ||||
| EXPORT_SYMBOL(iwl_set_mode); | ||||
| 
 | ||||
| int iwl_mac_add_interface(struct ieee80211_hw *hw, | ||||
| 				 struct ieee80211_if_init_conf *conf) | ||||
| 				 struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct iwl_priv *priv = hw->priv; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	IWL_DEBUG_MAC80211(priv, "enter: type %d\n", conf->type); | ||||
| 	IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type); | ||||
| 
 | ||||
| 	if (priv->vif) { | ||||
| 		IWL_DEBUG_MAC80211(priv, "leave - vif != NULL\n"); | ||||
| @ -2597,19 +2597,19 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, | ||||
| 	} | ||||
| 
 | ||||
| 	spin_lock_irqsave(&priv->lock, flags); | ||||
| 	priv->vif = conf->vif; | ||||
| 	priv->iw_mode = conf->type; | ||||
| 	priv->vif = vif; | ||||
| 	priv->iw_mode = vif->type; | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&priv->lock, flags); | ||||
| 
 | ||||
| 	mutex_lock(&priv->mutex); | ||||
| 
 | ||||
| 	if (conf->mac_addr) { | ||||
| 		IWL_DEBUG_MAC80211(priv, "Set %pM\n", conf->mac_addr); | ||||
| 		memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); | ||||
| 	if (vif->addr) { | ||||
| 		IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr); | ||||
| 		memcpy(priv->mac_addr, vif->addr, ETH_ALEN); | ||||
| 	} | ||||
| 
 | ||||
| 	if (iwl_set_mode(priv, conf->type) == -EAGAIN) | ||||
| 	if (iwl_set_mode(priv, vif->type) == -EAGAIN) | ||||
| 		/* we are not ready, will run again when ready */ | ||||
| 		set_bit(STATUS_MODE_PENDING, &priv->status); | ||||
| 
 | ||||
| @ -2621,7 +2621,7 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, | ||||
| EXPORT_SYMBOL(iwl_mac_add_interface); | ||||
| 
 | ||||
| void iwl_mac_remove_interface(struct ieee80211_hw *hw, | ||||
| 				     struct ieee80211_if_init_conf *conf) | ||||
| 				     struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct iwl_priv *priv = hw->priv; | ||||
| 
 | ||||
| @ -2634,7 +2634,7 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw, | ||||
| 		priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; | ||||
| 		iwlcore_commit_rxon(priv); | ||||
| 	} | ||||
| 	if (priv->vif == conf->vif) { | ||||
| 	if (priv->vif == vif) { | ||||
| 		priv->vif = NULL; | ||||
| 		memset(priv->bssid, 0, ETH_ALEN); | ||||
| 	} | ||||
|  | ||||
| @ -332,9 +332,9 @@ int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); | ||||
| int iwl_commit_rxon(struct iwl_priv *priv); | ||||
| int iwl_set_mode(struct iwl_priv *priv, int mode); | ||||
| int iwl_mac_add_interface(struct ieee80211_hw *hw, | ||||
| 				 struct ieee80211_if_init_conf *conf); | ||||
| 			  struct ieee80211_vif *vif); | ||||
| void iwl_mac_remove_interface(struct ieee80211_hw *hw, | ||||
| 				 struct ieee80211_if_init_conf *conf); | ||||
| 			      struct ieee80211_vif *vif); | ||||
| int iwl_mac_config(struct ieee80211_hw *hw, u32 changed); | ||||
| void iwl_config_ap(struct iwl_priv *priv); | ||||
| int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, | ||||
|  | ||||
| @ -650,47 +650,6 @@ void iwl_reply_statistics(struct iwl_priv *priv, | ||||
| } | ||||
| EXPORT_SYMBOL(iwl_reply_statistics); | ||||
| 
 | ||||
| #define PERFECT_RSSI (-20) /* dBm */ | ||||
| #define WORST_RSSI (-95)   /* dBm */ | ||||
| #define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) | ||||
| 
 | ||||
| /* Calculate an indication of rx signal quality (a percentage, not dBm!).
 | ||||
|  * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
 | ||||
|  *   about formulas used below. */ | ||||
| static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) | ||||
| { | ||||
| 	int sig_qual; | ||||
| 	int degradation = PERFECT_RSSI - rssi_dbm; | ||||
| 
 | ||||
| 	/* If we get a noise measurement, use signal-to-noise ratio (SNR)
 | ||||
| 	 * as indicator; formula is (signal dbm - noise dbm). | ||||
| 	 * SNR at or above 40 is a great signal (100%). | ||||
| 	 * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. | ||||
| 	 * Weakest usable signal is usually 10 - 15 dB SNR. */ | ||||
| 	if (noise_dbm) { | ||||
| 		if (rssi_dbm - noise_dbm >= 40) | ||||
| 			return 100; | ||||
| 		else if (rssi_dbm < noise_dbm) | ||||
| 			return 0; | ||||
| 		sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; | ||||
| 
 | ||||
| 	/* Else use just the signal level.
 | ||||
| 	 * This formula is a least squares fit of data points collected and | ||||
| 	 *   compared with a reference system that had a percentage (%) display | ||||
| 	 *   for signal quality. */ | ||||
| 	} else | ||||
| 		sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * | ||||
| 			    (15 * RSSI_RANGE + 62 * degradation)) / | ||||
| 			   (RSSI_RANGE * RSSI_RANGE); | ||||
| 
 | ||||
| 	if (sig_qual > 100) | ||||
| 		sig_qual = 100; | ||||
| 	else if (sig_qual < 1) | ||||
| 		sig_qual = 0; | ||||
| 
 | ||||
| 	return sig_qual; | ||||
| } | ||||
| 
 | ||||
| /* Calc max signal level (dBm) among 3 possible receivers */ | ||||
| static inline int iwl_calc_rssi(struct iwl_priv *priv, | ||||
| 				struct iwl_rx_phy_res *rx_resp) | ||||
| @ -1101,11 +1060,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | ||||
| 	if (iwl_is_associated(priv) && | ||||
| 	    !test_bit(STATUS_SCANNING, &priv->status)) { | ||||
| 		rx_status.noise = priv->last_rx_noise; | ||||
| 		rx_status.qual = iwl_calc_sig_qual(rx_status.signal, | ||||
| 							 rx_status.noise); | ||||
| 	} else { | ||||
| 		rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||||
| 		rx_status.qual = iwl_calc_sig_qual(rx_status.signal, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Reset beacon noise level if not associated. */ | ||||
| @ -1118,8 +1074,8 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, | ||||
| 		iwl_dbg_report_frame(priv, phy_res, len, header, 1); | ||||
| #endif | ||||
| 	iwl_dbg_log_rx_data_frame(priv, len, header); | ||||
| 	IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, qual %d, TSF %llu\n", | ||||
| 		rx_status.signal, rx_status.noise, rx_status.qual, | ||||
| 	IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n", | ||||
| 		rx_status.signal, rx_status.noise, | ||||
| 		(unsigned long long)rx_status.mactime); | ||||
| 
 | ||||
| 	/*
 | ||||
|  | ||||
| @ -1299,47 +1299,6 @@ int iwl3945_calc_db_from_ratio(int sig_ratio) | ||||
| 	return (int)ratio2dB[sig_ratio]; | ||||
| } | ||||
| 
 | ||||
| #define PERFECT_RSSI (-20) /* dBm */ | ||||
| #define WORST_RSSI (-95)   /* dBm */ | ||||
| #define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) | ||||
| 
 | ||||
| /* Calculate an indication of rx signal quality (a percentage, not dBm!).
 | ||||
|  * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info
 | ||||
|  *   about formulas used below. */ | ||||
| int iwl3945_calc_sig_qual(int rssi_dbm, int noise_dbm) | ||||
| { | ||||
| 	int sig_qual; | ||||
| 	int degradation = PERFECT_RSSI - rssi_dbm; | ||||
| 
 | ||||
| 	/* If we get a noise measurement, use signal-to-noise ratio (SNR)
 | ||||
| 	 * as indicator; formula is (signal dbm - noise dbm). | ||||
| 	 * SNR at or above 40 is a great signal (100%). | ||||
| 	 * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. | ||||
| 	 * Weakest usable signal is usually 10 - 15 dB SNR. */ | ||||
| 	if (noise_dbm) { | ||||
| 		if (rssi_dbm - noise_dbm >= 40) | ||||
| 			return 100; | ||||
| 		else if (rssi_dbm < noise_dbm) | ||||
| 			return 0; | ||||
| 		sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; | ||||
| 
 | ||||
| 	/* Else use just the signal level.
 | ||||
| 	 * This formula is a least squares fit of data points collected and | ||||
| 	 *   compared with a reference system that had a percentage (%) display | ||||
| 	 *   for signal quality. */ | ||||
| 	} else | ||||
| 		sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * | ||||
| 			    (15 * RSSI_RANGE + 62 * degradation)) / | ||||
| 			   (RSSI_RANGE * RSSI_RANGE); | ||||
| 
 | ||||
| 	if (sig_qual > 100) | ||||
| 		sig_qual = 100; | ||||
| 	else if (sig_qual < 1) | ||||
| 		sig_qual = 0; | ||||
| 
 | ||||
| 	return sig_qual; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * iwl3945_rx_handle - Main entry function for receiving responses from uCode | ||||
|  * | ||||
|  | ||||
| @ -268,7 +268,7 @@ struct iwm_priv { | ||||
| 
 | ||||
| 	struct sk_buff_head rx_list; | ||||
| 	struct list_head rx_tickets; | ||||
| 	struct list_head rx_packets[IWM_RX_ID_HASH]; | ||||
| 	struct list_head rx_packets[IWM_RX_ID_HASH + 1]; | ||||
| 	struct workqueue_struct *rx_wq; | ||||
| 	struct work_struct rx_worker; | ||||
| 
 | ||||
|  | ||||
| @ -567,11 +567,8 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) | ||||
| 	chan_count = lbs_scan_create_channel_list(priv, chan_list); | ||||
| 
 | ||||
| 	netif_stop_queue(priv->dev); | ||||
| 	netif_carrier_off(priv->dev); | ||||
| 	if (priv->mesh_dev) { | ||||
| 	if (priv->mesh_dev) | ||||
| 		netif_stop_queue(priv->mesh_dev); | ||||
| 		netif_carrier_off(priv->mesh_dev); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Prepare to continue an interrupted scan */ | ||||
| 	lbs_deb_scan("chan_count %d, scan_channel %d\n", | ||||
| @ -635,16 +632,13 @@ out2: | ||||
| 	priv->scan_channel = 0; | ||||
| 
 | ||||
| out: | ||||
| 	if (priv->connect_status == LBS_CONNECTED) { | ||||
| 		netif_carrier_on(priv->dev); | ||||
| 		if (!priv->tx_pending_len) | ||||
| 			netif_wake_queue(priv->dev); | ||||
| 	} | ||||
| 	if (priv->mesh_dev && lbs_mesh_connected(priv)) { | ||||
| 		netif_carrier_on(priv->mesh_dev); | ||||
| 		if (!priv->tx_pending_len) | ||||
| 			netif_wake_queue(priv->mesh_dev); | ||||
| 	} | ||||
| 	if (priv->connect_status == LBS_CONNECTED && !priv->tx_pending_len) | ||||
| 		netif_wake_queue(priv->dev); | ||||
| 
 | ||||
| 	if (priv->mesh_dev && lbs_mesh_connected(priv) && | ||||
| 	    !priv->tx_pending_len) | ||||
| 		netif_wake_queue(priv->mesh_dev); | ||||
| 
 | ||||
| 	kfree(chan_list); | ||||
| 
 | ||||
| 	lbs_deb_leave_args(LBS_DEB_SCAN, "ret %d", ret); | ||||
|  | ||||
| @ -318,14 +318,14 @@ static void lbtf_op_stop(struct ieee80211_hw *hw) | ||||
| } | ||||
| 
 | ||||
| static int lbtf_op_add_interface(struct ieee80211_hw *hw, | ||||
| 			struct ieee80211_if_init_conf *conf) | ||||
| 			struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct lbtf_private *priv = hw->priv; | ||||
| 	if (priv->vif != NULL) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	priv->vif = conf->vif; | ||||
| 	switch (conf->type) { | ||||
| 	priv->vif = vif; | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_MESH_POINT: | ||||
| 	case NL80211_IFTYPE_AP: | ||||
| 		lbtf_set_mode(priv, LBTF_AP_MODE); | ||||
| @ -337,12 +337,12 @@ static int lbtf_op_add_interface(struct ieee80211_hw *hw, | ||||
| 		priv->vif = NULL; | ||||
| 		return -EOPNOTSUPP; | ||||
| 	} | ||||
| 	lbtf_set_mac_address(priv, (u8 *) conf->mac_addr); | ||||
| 	lbtf_set_mac_address(priv, (u8 *) vif->addr); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void lbtf_op_remove_interface(struct ieee80211_hw *hw, | ||||
| 			struct ieee80211_if_init_conf *conf) | ||||
| 			struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct lbtf_private *priv = hw->priv; | ||||
| 
 | ||||
| @ -495,7 +495,6 @@ int lbtf_rx(struct lbtf_private *priv, struct sk_buff *skb) | ||||
| 	stats.band = IEEE80211_BAND_2GHZ; | ||||
| 	stats.signal = prxpd->snr; | ||||
| 	stats.noise = prxpd->nf; | ||||
| 	stats.qual = prxpd->snr - prxpd->nf; | ||||
| 	/* Marvell rate index has a hole at value 4 */ | ||||
| 	if (prxpd->rx_rate > 4) | ||||
| 		--prxpd->rx_rate; | ||||
|  | ||||
| @ -584,24 +584,24 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) | ||||
| 
 | ||||
| 
 | ||||
| static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, | ||||
| 					struct ieee80211_if_init_conf *conf) | ||||
| 					struct ieee80211_vif *vif) | ||||
| { | ||||
| 	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", | ||||
| 	       wiphy_name(hw->wiphy), __func__, conf->type, | ||||
| 	       conf->mac_addr); | ||||
| 	hwsim_set_magic(conf->vif); | ||||
| 	       wiphy_name(hw->wiphy), __func__, vif->type, | ||||
| 	       vif->addr); | ||||
| 	hwsim_set_magic(vif); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void mac80211_hwsim_remove_interface( | ||||
| 	struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) | ||||
| 	struct ieee80211_hw *hw, struct ieee80211_vif *vif) | ||||
| { | ||||
| 	printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", | ||||
| 	       wiphy_name(hw->wiphy), __func__, conf->type, | ||||
| 	       conf->mac_addr); | ||||
| 	hwsim_check_magic(conf->vif); | ||||
| 	hwsim_clear_magic(conf->vif); | ||||
| 	       wiphy_name(hw->wiphy), __func__, vif->type, | ||||
| 	       vif->addr); | ||||
| 	hwsim_check_magic(vif); | ||||
| 	hwsim_clear_magic(vif); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -896,6 +896,16 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop) | ||||
| { | ||||
| 	/*
 | ||||
| 	 * In this special case, there's nothing we need to | ||||
| 	 * do because hwsim does transmission synchronously. | ||||
| 	 * In the future, when it does transmissions via | ||||
| 	 * userspace, we may need to do something. | ||||
| 	 */ | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static const struct ieee80211_ops mac80211_hwsim_ops = | ||||
| { | ||||
| @ -912,6 +922,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = | ||||
| 	.conf_tx = mac80211_hwsim_conf_tx, | ||||
| 	CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) | ||||
| 	.ampdu_action = mac80211_hwsim_ampdu_action, | ||||
| 	.flush = mac80211_hwsim_flush, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -23,7 +23,7 @@ | ||||
| #define MAX_RID_LEN 1024 | ||||
| 
 | ||||
| /* Helper routine to record keys
 | ||||
|  * Do not call from interrupt context */ | ||||
|  * It is called under orinoco_lock so it may not sleep */ | ||||
| static int orinoco_set_key(struct orinoco_private *priv, int index, | ||||
| 			   enum orinoco_alg alg, const u8 *key, int key_len, | ||||
| 			   const u8 *seq, int seq_len) | ||||
| @ -32,14 +32,14 @@ static int orinoco_set_key(struct orinoco_private *priv, int index, | ||||
| 	kzfree(priv->keys[index].seq); | ||||
| 
 | ||||
| 	if (key_len) { | ||||
| 		priv->keys[index].key = kzalloc(key_len, GFP_KERNEL); | ||||
| 		priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC); | ||||
| 		if (!priv->keys[index].key) | ||||
| 			goto nomem; | ||||
| 	} else | ||||
| 		priv->keys[index].key = NULL; | ||||
| 
 | ||||
| 	if (seq_len) { | ||||
| 		priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL); | ||||
| 		priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC); | ||||
| 		if (!priv->keys[index].seq) | ||||
| 			goto free_key; | ||||
| 	} else | ||||
|  | ||||
| @ -216,7 +216,7 @@ static void p54_stop(struct ieee80211_hw *dev) | ||||
| } | ||||
| 
 | ||||
| static int p54_add_interface(struct ieee80211_hw *dev, | ||||
| 			     struct ieee80211_if_init_conf *conf) | ||||
| 			     struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct p54_common *priv = dev->priv; | ||||
| 
 | ||||
| @ -226,28 +226,28 @@ static int p54_add_interface(struct ieee80211_hw *dev, | ||||
| 		return -EOPNOTSUPP; | ||||
| 	} | ||||
| 
 | ||||
| 	priv->vif = conf->vif; | ||||
| 	priv->vif = vif; | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 	case NL80211_IFTYPE_ADHOC: | ||||
| 	case NL80211_IFTYPE_AP: | ||||
| 	case NL80211_IFTYPE_MESH_POINT: | ||||
| 		priv->mode = conf->type; | ||||
| 		priv->mode = vif->type; | ||||
| 		break; | ||||
| 	default: | ||||
| 		mutex_unlock(&priv->conf_mutex); | ||||
| 		return -EOPNOTSUPP; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); | ||||
| 	memcpy(priv->mac_addr, vif->addr, ETH_ALEN); | ||||
| 	p54_setup_mac(priv); | ||||
| 	mutex_unlock(&priv->conf_mutex); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void p54_remove_interface(struct ieee80211_hw *dev, | ||||
| 				 struct ieee80211_if_init_conf *conf) | ||||
| 				 struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct p54_common *priv = dev->priv; | ||||
| 
 | ||||
|  | ||||
| @ -54,12 +54,12 @@ config RT61PCI | ||||
| 	  When compiled as a module, this driver will be called rt61pci. | ||||
| 
 | ||||
| config RT2800PCI_PCI | ||||
| 	tristate | ||||
| 	boolean | ||||
| 	depends on PCI | ||||
| 	default y | ||||
| 
 | ||||
| config RT2800PCI_SOC | ||||
| 	tristate | ||||
| 	boolean | ||||
| 	depends on RALINK_RT288X || RALINK_RT305X | ||||
| 	default y | ||||
| 
 | ||||
|  | ||||
| @ -451,7 +451,7 @@ static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, | ||||
| 	/*
 | ||||
| 	 * RF2420 chipset don't need any additional actions. | ||||
| 	 */ | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF2420)) | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2420)) | ||||
| 		return; | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -1343,8 +1343,7 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2x00_set_chip_rf(rt2x00dev, value, reg); | ||||
| 	rt2x00_print_chip(rt2x00dev); | ||||
| 
 | ||||
| 	if (!rt2x00_rf(&rt2x00dev->chip, RF2420) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2421)) { | ||||
| 	if (!rt2x00_rf(rt2x00dev, RF2420) && !rt2x00_rf(rt2x00dev, RF2421)) { | ||||
| 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
|  | ||||
| @ -440,8 +440,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, | ||||
| 	/*
 | ||||
| 	 * RT2525E and RT5222 need to flip TX I/Q | ||||
| 	 */ | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || | ||||
| 	    rt2x00_rf(&rt2x00dev->chip, RF5222)) { | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) { | ||||
| 		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); | ||||
| 		rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); | ||||
| 		rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); | ||||
| @ -449,7 +448,7 @@ static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, | ||||
| 		/*
 | ||||
| 		 * RT2525E does not need RX I/Q Flip. | ||||
| 		 */ | ||||
| 		if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) | ||||
| 		if (rt2x00_rf(rt2x00dev, RF2525E)) | ||||
| 			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); | ||||
| 	} else { | ||||
| 		rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); | ||||
| @ -475,14 +474,14 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, | ||||
| 	 * Switch on tuning bits. | ||||
| 	 * For RT2523 devices we do not need to update the R1 register. | ||||
| 	 */ | ||||
| 	if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) | ||||
| 	if (!rt2x00_rf(rt2x00dev, RF2523)) | ||||
| 		rt2x00_set_field32(&rf->rf1, RF1_TUNER, 1); | ||||
| 	rt2x00_set_field32(&rf->rf3, RF3_TUNER, 1); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * For RT2525 we should first set the channel to half band higher. | ||||
| 	 */ | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2525)) { | ||||
| 		static const u32 vals[] = { | ||||
| 			0x00080cbe, 0x00080d02, 0x00080d06, 0x00080d0a, | ||||
| 			0x00080d0e, 0x00080d12, 0x00080d16, 0x00080d1a, | ||||
| @ -516,7 +515,7 @@ static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, | ||||
| 	 * Switch off tuning bits. | ||||
| 	 * For RT2523 devices we do not need to update the R1 register. | ||||
| 	 */ | ||||
| 	if (!rt2x00_rf(&rt2x00dev->chip, RF2523)) { | ||||
| 	if (!rt2x00_rf(rt2x00dev, RF2523)) { | ||||
| 		rt2x00_set_field32(&rf->rf1, RF1_TUNER, 0); | ||||
| 		rt2500pci_rf_write(rt2x00dev, 1, rf->rf1); | ||||
| 	} | ||||
| @ -640,7 +639,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, | ||||
| 	 * up to version C the link tuning should halt after 20 | ||||
| 	 * seconds while being associated. | ||||
| 	 */ | ||||
| 	if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D && | ||||
| 	if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D && | ||||
| 	    rt2x00dev->intf_associated && count > 20) | ||||
| 		return; | ||||
| 
 | ||||
| @ -650,7 +649,7 @@ static void rt2500pci_link_tuner(struct rt2x00_dev *rt2x00dev, | ||||
| 	 * should go straight to dynamic CCA tuning when they | ||||
| 	 * are not associated. | ||||
| 	 */ | ||||
| 	if (rt2x00_rev(&rt2x00dev->chip) < RT2560_VERSION_D || | ||||
| 	if (rt2x00_rev(rt2x00dev) < RT2560_VERSION_D || | ||||
| 	    !rt2x00dev->intf_associated) | ||||
| 		goto dynamic_cca_tune; | ||||
| 
 | ||||
| @ -1507,12 +1506,12 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2x00_set_chip_rf(rt2x00dev, value, reg); | ||||
| 	rt2x00_print_chip(rt2x00dev); | ||||
| 
 | ||||
| 	if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2523) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2524) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2525) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2525E) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF5222)) { | ||||
| 	if (!rt2x00_rf(rt2x00dev, RF2522) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2523) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2524) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2525) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2525E) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF5222)) { | ||||
| 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| @ -1744,22 +1743,22 @@ static int rt2500pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||||
| 	spec->supported_bands = SUPPORT_BAND_2GHZ; | ||||
| 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; | ||||
| 
 | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2522)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); | ||||
| 		spec->channels = rf_vals_bg_2522; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2523)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); | ||||
| 		spec->channels = rf_vals_bg_2523; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2524)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); | ||||
| 		spec->channels = rf_vals_bg_2524; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2525)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); | ||||
| 		spec->channels = rf_vals_bg_2525; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2525E)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); | ||||
| 		spec->channels = rf_vals_bg_2525e; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF5222)) { | ||||
| 		spec->supported_bands |= SUPPORT_BAND_5GHZ; | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_5222); | ||||
| 		spec->channels = rf_vals_5222; | ||||
|  | ||||
| @ -565,8 +565,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, | ||||
| 	/*
 | ||||
| 	 * RT2525E and RT5222 need to flip TX I/Q | ||||
| 	 */ | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || | ||||
| 	    rt2x00_rf(&rt2x00dev->chip, RF5222)) { | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2525E) || rt2x00_rf(rt2x00dev, RF5222)) { | ||||
| 		rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); | ||||
| 		rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 1); | ||||
| 		rt2x00_set_field16(&csr6, PHY_CSR6_OFDM_FLIP, 1); | ||||
| @ -574,7 +573,7 @@ static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, | ||||
| 		/*
 | ||||
| 		 * RT2525E does not need RX I/Q Flip. | ||||
| 		 */ | ||||
| 		if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) | ||||
| 		if (rt2x00_rf(rt2x00dev, RF2525E)) | ||||
| 			rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); | ||||
| 	} else { | ||||
| 		rt2x00_set_field16(&csr5, PHY_CSR5_CCK_FLIP, 0); | ||||
| @ -598,7 +597,7 @@ static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, | ||||
| 	/*
 | ||||
| 	 * For RT2525E we should first set the channel to half band higher. | ||||
| 	 */ | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2525E)) { | ||||
| 		static const u32 vals[] = { | ||||
| 			0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, | ||||
| 			0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, | ||||
| @ -793,7 +792,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2x00_set_field16(®, MAC_CSR1_HOST_READY, 1); | ||||
| 	rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg); | ||||
| 
 | ||||
| 	if (rt2x00_rev(&rt2x00dev->chip) >= RT2570_VERSION_C) { | ||||
| 	if (rt2x00_rev(rt2x00dev) >= RT2570_VERSION_C) { | ||||
| 		rt2500usb_register_read(rt2x00dev, PHY_CSR2, ®); | ||||
| 		rt2x00_set_field16(®, PHY_CSR2_LNA, 0); | ||||
| 	} else { | ||||
| @ -1411,19 +1410,18 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2x00_set_chip(rt2x00dev, RT2570, value, reg); | ||||
| 	rt2x00_print_chip(rt2x00dev); | ||||
| 
 | ||||
| 	if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0) || | ||||
| 	    rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { | ||||
| 
 | ||||
| 	if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0) || | ||||
| 	    rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) { | ||||
| 		ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!rt2x00_rf(&rt2x00dev->chip, RF2522) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2523) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2524) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2525) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2525E) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF5222)) { | ||||
| 	if (!rt2x00_rf(rt2x00dev, RF2522) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2523) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2524) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2525) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2525E) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF5222)) { | ||||
| 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| @ -1667,22 +1665,22 @@ static int rt2500usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||||
| 	spec->supported_bands = SUPPORT_BAND_2GHZ; | ||||
| 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; | ||||
| 
 | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF2522)) { | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2522)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2522); | ||||
| 		spec->channels = rf_vals_bg_2522; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF2523)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2523)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2523); | ||||
| 		spec->channels = rf_vals_bg_2523; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF2524)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2524)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2524); | ||||
| 		spec->channels = rf_vals_bg_2524; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2525)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525); | ||||
| 		spec->channels = rf_vals_bg_2525; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2525E)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2525e); | ||||
| 		spec->channels = rf_vals_bg_2525e; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF5222)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF5222)) { | ||||
| 		spec->supported_bands |= SUPPORT_BAND_5GHZ; | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_5222); | ||||
| 		spec->channels = rf_vals_5222; | ||||
|  | ||||
| @ -37,7 +37,7 @@ | ||||
| #include <linux/module.h> | ||||
| 
 | ||||
| #include "rt2x00.h" | ||||
| #if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE) | ||||
| #if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE) | ||||
| #include "rt2x00usb.h" | ||||
| #endif | ||||
| #include "rt2800lib.h" | ||||
| @ -220,8 +220,7 @@ void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, | ||||
| 	/*
 | ||||
| 	 * RT2880 and RT3052 don't support MCU requests. | ||||
| 	 */ | ||||
| 	if (rt2x00_rt(&rt2x00dev->chip, RT2880) || | ||||
| 	    rt2x00_rt(&rt2x00dev->chip, RT3052)) | ||||
| 	if (rt2x00_rt(rt2x00dev, RT2880) || rt2x00_rt(rt2x00dev, RT3052)) | ||||
| 		return; | ||||
| 
 | ||||
| 	mutex_lock(&rt2x00dev->csr_mutex); | ||||
| @ -806,12 +805,12 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, | ||||
| 	unsigned int tx_pin; | ||||
| 	u8 bbp; | ||||
| 
 | ||||
| 	if ((rt2x00_rt(&rt2x00dev->chip, RT3070) || | ||||
| 	     rt2x00_rt(&rt2x00dev->chip, RT3090)) && | ||||
| 	    (rt2x00_rf(&rt2x00dev->chip, RF2020) || | ||||
| 	     rt2x00_rf(&rt2x00dev->chip, RF3020) || | ||||
| 	     rt2x00_rf(&rt2x00dev->chip, RF3021) || | ||||
| 	     rt2x00_rf(&rt2x00dev->chip, RF3022))) | ||||
| 	if ((rt2x00_rt(rt2x00dev, RT3070) || | ||||
| 	     rt2x00_rt(rt2x00dev, RT3090)) && | ||||
| 	    (rt2x00_rf(rt2x00dev, RF2020) || | ||||
| 	     rt2x00_rf(rt2x00dev, RF3020) || | ||||
| 	     rt2x00_rf(rt2x00dev, RF3021) || | ||||
| 	     rt2x00_rf(rt2x00dev, RF3022))) | ||||
| 		rt2800_config_channel_rt3x(rt2x00dev, conf, rf, info); | ||||
| 	else | ||||
| 		rt2800_config_channel_rt2x(rt2x00dev, conf, rf, info); | ||||
| @ -878,7 +877,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, | ||||
| 	rt2x00_set_field8(&bbp, BBP3_HT40_PLUS, conf_is_ht40_plus(conf)); | ||||
| 	rt2800_bbp_write(rt2x00dev, 3, bbp); | ||||
| 
 | ||||
| 	if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { | ||||
| 	if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) { | ||||
| 		if (conf_is_ht40(conf)) { | ||||
| 			rt2800_bbp_write(rt2x00dev, 69, 0x1a); | ||||
| 			rt2800_bbp_write(rt2x00dev, 70, 0x0a); | ||||
| @ -1041,7 +1040,7 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) | ||||
| { | ||||
| 	if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ) { | ||||
| 		if (rt2x00_intf_is_usb(rt2x00dev) && | ||||
| 		    rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) | ||||
| 		    rt2x00_rev(rt2x00dev) == RT3070_VERSION) | ||||
| 			return 0x1c + (2 * rt2x00dev->lna_gain); | ||||
| 		else | ||||
| 			return 0x2e + rt2x00dev->lna_gain; | ||||
| @ -1072,7 +1071,7 @@ EXPORT_SYMBOL_GPL(rt2800_reset_tuner); | ||||
| void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual, | ||||
| 		       const u32 count) | ||||
| { | ||||
| 	if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) | ||||
| 	if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) | ||||
| 		return; | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -1121,7 +1120,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) | ||||
| 
 | ||||
| 	if (rt2x00_intf_is_usb(rt2x00dev)) { | ||||
| 		rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000); | ||||
| #if defined(CONFIG_RT2800USB) || defined(CONFIG_RT2800USB_MODULE) | ||||
| #if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE) | ||||
| 		rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0, | ||||
| 					    USB_MODE_RESET, REGISTER_TIMEOUT); | ||||
| #endif | ||||
| @ -1158,7 +1157,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg); | ||||
| 
 | ||||
| 	if (rt2x00_intf_is_usb(rt2x00dev) && | ||||
| 	    rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { | ||||
| 	    rt2x00_rev(rt2x00dev) == RT3070_VERSION) { | ||||
| 		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); | ||||
| 		rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); | ||||
| 		rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); | ||||
| @ -1185,8 +1184,8 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) | ||||
| 
 | ||||
| 	rt2800_register_read(rt2x00dev, MAX_LEN_CFG, ®); | ||||
| 	rt2x00_set_field32(®, MAX_LEN_CFG_MAX_MPDU, AGGREGATION_SIZE); | ||||
| 	if (rt2x00_rev(&rt2x00dev->chip) >= RT2880E_VERSION && | ||||
| 	    rt2x00_rev(&rt2x00dev->chip) < RT3070_VERSION) | ||||
| 	if (rt2x00_rev(rt2x00dev) >= RT2880E_VERSION && | ||||
| 	    rt2x00_rev(rt2x00dev) < RT3070_VERSION) | ||||
| 		rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 2); | ||||
| 	else | ||||
| 		rt2x00_set_field32(®, MAX_LEN_CFG_MAX_PSDU, 1); | ||||
| @ -1465,22 +1464,22 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2800_bbp_write(rt2x00dev, 103, 0x00); | ||||
| 	rt2800_bbp_write(rt2x00dev, 105, 0x05); | ||||
| 
 | ||||
| 	if (rt2x00_rev(&rt2x00dev->chip) == RT2860C_VERSION) { | ||||
| 	if (rt2x00_rev(rt2x00dev) == RT2860C_VERSION) { | ||||
| 		rt2800_bbp_write(rt2x00dev, 69, 0x16); | ||||
| 		rt2800_bbp_write(rt2x00dev, 73, 0x12); | ||||
| 	} | ||||
| 
 | ||||
| 	if (rt2x00_rev(&rt2x00dev->chip) > RT2860D_VERSION) | ||||
| 	if (rt2x00_rev(rt2x00dev) > RT2860D_VERSION) | ||||
| 		rt2800_bbp_write(rt2x00dev, 84, 0x19); | ||||
| 
 | ||||
| 	if (rt2x00_intf_is_usb(rt2x00dev) && | ||||
| 	    rt2x00_rev(&rt2x00dev->chip) == RT3070_VERSION) { | ||||
| 	    rt2x00_rev(rt2x00dev) == RT3070_VERSION) { | ||||
| 		rt2800_bbp_write(rt2x00dev, 70, 0x0a); | ||||
| 		rt2800_bbp_write(rt2x00dev, 84, 0x99); | ||||
| 		rt2800_bbp_write(rt2x00dev, 105, 0x05); | ||||
| 	} | ||||
| 
 | ||||
| 	if (rt2x00_rt(&rt2x00dev->chip, RT3052)) { | ||||
| 	if (rt2x00_rt(rt2x00dev, RT3052)) { | ||||
| 		rt2800_bbp_write(rt2x00dev, 31, 0x08); | ||||
| 		rt2800_bbp_write(rt2x00dev, 78, 0x0e); | ||||
| 		rt2800_bbp_write(rt2x00dev, 80, 0x08); | ||||
| @ -1566,13 +1565,13 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) | ||||
| 	u8 bbp; | ||||
| 
 | ||||
| 	if (rt2x00_intf_is_usb(rt2x00dev) && | ||||
| 	    rt2x00_rev(&rt2x00dev->chip) != RT3070_VERSION) | ||||
| 	    rt2x00_rev(rt2x00dev) != RT3070_VERSION) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (rt2x00_intf_is_pci(rt2x00dev)) { | ||||
| 		if (!rt2x00_rf(&rt2x00dev->chip, RF3020) && | ||||
| 		    !rt2x00_rf(&rt2x00dev->chip, RF3021) && | ||||
| 		    !rt2x00_rf(&rt2x00dev->chip, RF3022)) | ||||
| 		if (!rt2x00_rf(rt2x00dev, RF3020) && | ||||
| 		    !rt2x00_rf(rt2x00dev, RF3021) && | ||||
| 		    !rt2x00_rf(rt2x00dev, RF3022)) | ||||
| 			return 0; | ||||
| 	} | ||||
| 
 | ||||
| @ -1737,7 +1736,7 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev) | ||||
| 		rt2x00_set_field16(&word, EEPROM_ANTENNA_RF_TYPE, RF2820); | ||||
| 		rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word); | ||||
| 		EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word); | ||||
| 	} else if (rt2x00_rev(&rt2x00dev->chip) < RT2883_VERSION) { | ||||
| 	} else if (rt2x00_rev(rt2x00dev) < RT2883_VERSION) { | ||||
| 		/*
 | ||||
| 		 * There is a max of 2 RX streams for RT28x0 series | ||||
| 		 */ | ||||
| @ -1839,17 +1838,15 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2x00_set_chip_rf(rt2x00dev, value, reg); | ||||
| 
 | ||||
| 	if (rt2x00_intf_is_usb(rt2x00dev)) { | ||||
| 		struct rt2x00_chip *chip = &rt2x00dev->chip; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * The check for rt2860 is not a typo, some rt2870 hardware | ||||
| 		 * identifies itself as rt2860 in the CSR register. | ||||
| 		 */ | ||||
| 		if (rt2x00_check_rev(chip, 0xfff00000, 0x28600000) || | ||||
| 		    rt2x00_check_rev(chip, 0xfff00000, 0x28700000) || | ||||
| 		    rt2x00_check_rev(chip, 0xfff00000, 0x28800000)) { | ||||
| 		if (rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28600000) || | ||||
| 		    rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28700000) || | ||||
| 		    rt2x00_check_rev(rt2x00dev, 0xfff00000, 0x28800000)) { | ||||
| 			rt2x00_set_chip_rt(rt2x00dev, RT2870); | ||||
| 		} else if (rt2x00_check_rev(chip, 0xffff0000, 0x30700000)) { | ||||
| 		} else if (rt2x00_check_rev(rt2x00dev, 0xffff0000, 0x30700000)) { | ||||
| 			rt2x00_set_chip_rt(rt2x00dev, RT3070); | ||||
| 		} else { | ||||
| 			ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); | ||||
| @ -1858,14 +1855,14 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||||
| 	} | ||||
| 	rt2x00_print_chip(rt2x00dev); | ||||
| 
 | ||||
| 	if (!rt2x00_rf(&rt2x00dev->chip, RF2820) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2850) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2720) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2750) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF3020) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2020) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF3021) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF3022)) { | ||||
| 	if (!rt2x00_rf(rt2x00dev, RF2820) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2850) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2720) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2750) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF3020) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2020) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF3021) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF3022)) { | ||||
| 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| @ -2013,7 +2010,6 @@ static const struct rf_channel rf_vals_302x[] = { | ||||
| 
 | ||||
| int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||||
| { | ||||
| 	struct rt2x00_chip *chip = &rt2x00dev->chip; | ||||
| 	struct hw_mode_spec *spec = &rt2x00dev->spec; | ||||
| 	struct channel_info *info; | ||||
| 	char *tx_power1; | ||||
| @ -2049,19 +2045,19 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||||
| 	spec->supported_bands = SUPPORT_BAND_2GHZ; | ||||
| 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; | ||||
| 
 | ||||
| 	if (rt2x00_rf(chip, RF2820) || | ||||
| 	    rt2x00_rf(chip, RF2720) || | ||||
| 	    (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(chip, RF3052))) { | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2820) || | ||||
| 	    rt2x00_rf(rt2x00dev, RF2720) || | ||||
| 	    (rt2x00_intf_is_pci(rt2x00dev) && rt2x00_rf(rt2x00dev, RF3052))) { | ||||
| 		spec->num_channels = 14; | ||||
| 		spec->channels = rf_vals; | ||||
| 	} else if (rt2x00_rf(chip, RF2850) || rt2x00_rf(chip, RF2750)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2850) || rt2x00_rf(rt2x00dev, RF2750)) { | ||||
| 		spec->supported_bands |= SUPPORT_BAND_5GHZ; | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals); | ||||
| 		spec->channels = rf_vals; | ||||
| 	} else if (rt2x00_rf(chip, RF3020) || | ||||
| 		   rt2x00_rf(chip, RF2020) || | ||||
| 		   rt2x00_rf(chip, RF3021) || | ||||
| 		   rt2x00_rf(chip, RF3022)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF3020) || | ||||
| 		   rt2x00_rf(rt2x00dev, RF2020) || | ||||
| 		   rt2x00_rf(rt2x00dev, RF3021) || | ||||
| 		   rt2x00_rf(rt2x00dev, RF3022)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_302x); | ||||
| 		spec->channels = rf_vals_302x; | ||||
| 	} | ||||
| @ -2069,7 +2065,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||||
| 	/*
 | ||||
| 	 * Initialize HT information. | ||||
| 	 */ | ||||
| 	if (!rt2x00_rf(chip, RF2020)) | ||||
| 	if (!rt2x00_rf(rt2x00dev, RF2020)) | ||||
| 		spec->ht.ht_supported = true; | ||||
| 	else | ||||
| 		spec->ht.ht_supported = false; | ||||
|  | ||||
| @ -48,14 +48,6 @@ | ||||
| #include "rt2800.h" | ||||
| #include "rt2800pci.h" | ||||
| 
 | ||||
| #ifdef CONFIG_RT2800PCI_PCI_MODULE | ||||
| #define CONFIG_RT2800PCI_PCI | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_RT2800PCI_WISOC_MODULE | ||||
| #define CONFIG_RT2800PCI_WISOC | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
|  * Allow hardware encryption to be disabled. | ||||
|  */ | ||||
| @ -87,7 +79,7 @@ static void rt2800pci_mcu_status(struct rt2x00_dev *rt2x00dev, const u8 token) | ||||
| 	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0); | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_RT2800PCI_WISOC | ||||
| #ifdef CONFIG_RT2800PCI_SOC | ||||
| static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) | ||||
| { | ||||
| 	u32 *base_addr = (u32 *) KSEG1ADDR(0x1F040000); /* XXX for RT3052 */ | ||||
| @ -98,7 +90,7 @@ static void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) | ||||
| static inline void rt2800pci_read_eeprom_soc(struct rt2x00_dev *rt2x00dev) | ||||
| { | ||||
| } | ||||
| #endif /* CONFIG_RT2800PCI_WISOC */ | ||||
| #endif /* CONFIG_RT2800PCI_SOC */ | ||||
| 
 | ||||
| #ifdef CONFIG_RT2800PCI_PCI | ||||
| static void rt2800pci_eepromregister_read(struct eeprom_93cx6 *eeprom) | ||||
| @ -1129,8 +1121,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) | ||||
| 	/*
 | ||||
| 	 * This device requires firmware. | ||||
| 	 */ | ||||
| 	if (!rt2x00_rt(&rt2x00dev->chip, RT2880) && | ||||
| 	    !rt2x00_rt(&rt2x00dev->chip, RT3052)) | ||||
| 	if (!rt2x00_rt(rt2x00dev, RT2880) && !rt2x00_rt(rt2x00dev, RT3052)) | ||||
| 		__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags); | ||||
| 	__set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags); | ||||
| 	__set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags); | ||||
| @ -1251,7 +1242,7 @@ MODULE_DEVICE_TABLE(pci, rt2800pci_device_table); | ||||
| #endif /* CONFIG_RT2800PCI_PCI */ | ||||
| MODULE_LICENSE("GPL"); | ||||
| 
 | ||||
| #ifdef CONFIG_RT2800PCI_WISOC | ||||
| #ifdef CONFIG_RT2800PCI_SOC | ||||
| #if defined(CONFIG_RALINK_RT288X) | ||||
| __rt2x00soc_probe(RT2880, &rt2800pci_ops); | ||||
| #elif defined(CONFIG_RALINK_RT305X) | ||||
| @ -1269,7 +1260,7 @@ static struct platform_driver rt2800soc_driver = { | ||||
| 	.suspend	= rt2x00soc_suspend, | ||||
| 	.resume		= rt2x00soc_resume, | ||||
| }; | ||||
| #endif /* CONFIG_RT2800PCI_WISOC */ | ||||
| #endif /* CONFIG_RT2800PCI_SOC */ | ||||
| 
 | ||||
| #ifdef CONFIG_RT2800PCI_PCI | ||||
| static struct pci_driver rt2800pci_driver = { | ||||
| @ -1286,7 +1277,7 @@ static int __init rt2800pci_init(void) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| #ifdef CONFIG_RT2800PCI_WISOC | ||||
| #ifdef CONFIG_RT2800PCI_SOC | ||||
| 	ret = platform_driver_register(&rt2800soc_driver); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| @ -1294,7 +1285,7 @@ static int __init rt2800pci_init(void) | ||||
| #ifdef CONFIG_RT2800PCI_PCI | ||||
| 	ret = pci_register_driver(&rt2800pci_driver); | ||||
| 	if (ret) { | ||||
| #ifdef CONFIG_RT2800PCI_WISOC | ||||
| #ifdef CONFIG_RT2800PCI_SOC | ||||
| 		platform_driver_unregister(&rt2800soc_driver); | ||||
| #endif | ||||
| 		return ret; | ||||
| @ -1309,7 +1300,7 @@ static void __exit rt2800pci_exit(void) | ||||
| #ifdef CONFIG_RT2800PCI_PCI | ||||
| 	pci_unregister_driver(&rt2800pci_driver); | ||||
| #endif | ||||
| #ifdef CONFIG_RT2800PCI_WISOC | ||||
| #ifdef CONFIG_RT2800PCI_SOC | ||||
| 	platform_driver_unregister(&rt2800soc_driver); | ||||
| #endif | ||||
| } | ||||
|  | ||||
| @ -92,7 +92,7 @@ static bool rt2800usb_check_crc(const u8 *data, const size_t len) | ||||
| static int rt2800usb_check_firmware(struct rt2x00_dev *rt2x00dev, | ||||
| 				    const u8 *data, const size_t len) | ||||
| { | ||||
| 	u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; | ||||
| 	u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff; | ||||
| 	size_t offset = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -138,7 +138,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev, | ||||
| 	u32 reg; | ||||
| 	u32 offset; | ||||
| 	u32 length; | ||||
| 	u16 chipset = (rt2x00_rev(&rt2x00dev->chip) >> 16) & 0xffff; | ||||
| 	u16 chipset = (rt2x00_rev(rt2x00dev) >> 16) & 0xffff; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Check which section of the firmware we need. | ||||
| @ -933,6 +933,7 @@ static struct usb_device_id rt2800usb_device_table[] = { | ||||
| 	{ USB_DEVICE(0x1737, 0x0070), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||||
| 	{ USB_DEVICE(0x1737, 0x0071), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||||
| 	{ USB_DEVICE(0x1737, 0x0077), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||||
| 	{ USB_DEVICE(0x1737, 0x0079), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||||
| 	/* Logitec */ | ||||
| 	{ USB_DEVICE(0x0789, 0x0162), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||||
| 	{ USB_DEVICE(0x0789, 0x0163), USB_DEVICE_DATA(&rt2800usb_ops) }, | ||||
|  | ||||
| @ -937,25 +937,25 @@ static inline void rt2x00_print_chip(struct rt2x00_dev *rt2x00dev) | ||||
| 	     rt2x00dev->chip.rt, rt2x00dev->chip.rf, rt2x00dev->chip.rev); | ||||
| } | ||||
| 
 | ||||
| static inline char rt2x00_rt(const struct rt2x00_chip *chipset, const u16 chip) | ||||
| static inline char rt2x00_rt(struct rt2x00_dev *rt2x00dev, const u16 rt) | ||||
| { | ||||
| 	return (chipset->rt == chip); | ||||
| 	return (rt2x00dev->chip.rt == rt); | ||||
| } | ||||
| 
 | ||||
| static inline char rt2x00_rf(const struct rt2x00_chip *chipset, const u16 chip) | ||||
| static inline char rt2x00_rf(struct rt2x00_dev *rt2x00dev, const u16 rf) | ||||
| { | ||||
| 	return (chipset->rf == chip); | ||||
| 	return (rt2x00dev->chip.rf == rf); | ||||
| } | ||||
| 
 | ||||
| static inline u32 rt2x00_rev(const struct rt2x00_chip *chipset) | ||||
| static inline u32 rt2x00_rev(struct rt2x00_dev *rt2x00dev) | ||||
| { | ||||
| 	return chipset->rev; | ||||
| 	return rt2x00dev->chip.rev; | ||||
| } | ||||
| 
 | ||||
| static inline bool rt2x00_check_rev(const struct rt2x00_chip *chipset, | ||||
| static inline bool rt2x00_check_rev(struct rt2x00_dev *rt2x00dev, | ||||
| 				    const u32 mask, const u32 rev) | ||||
| { | ||||
| 	return ((chipset->rev & mask) == rev); | ||||
| 	return ((rt2x00dev->chip.rev & mask) == rev); | ||||
| } | ||||
| 
 | ||||
| static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev, | ||||
| @ -964,20 +964,20 @@ static inline void rt2x00_set_chip_intf(struct rt2x00_dev *rt2x00dev, | ||||
| 	rt2x00dev->chip.intf = intf; | ||||
| } | ||||
| 
 | ||||
| static inline bool rt2x00_intf(const struct rt2x00_chip *chipset, | ||||
| static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev, | ||||
| 			       enum rt2x00_chip_intf intf) | ||||
| { | ||||
| 	return (chipset->intf == intf); | ||||
| 	return (rt2x00dev->chip.intf == intf); | ||||
| } | ||||
| 
 | ||||
| static inline bool rt2x00_intf_is_pci(struct rt2x00_dev *rt2x00dev) | ||||
| { | ||||
| 	return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_PCI); | ||||
| 	return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI); | ||||
| } | ||||
| 
 | ||||
| static inline bool rt2x00_intf_is_usb(struct rt2x00_dev *rt2x00dev) | ||||
| { | ||||
| 	return rt2x00_intf(&rt2x00dev->chip, RT2X00_CHIP_INTF_USB); | ||||
| 	return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_USB); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| @ -1019,9 +1019,9 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); | ||||
| int rt2x00mac_start(struct ieee80211_hw *hw); | ||||
| void rt2x00mac_stop(struct ieee80211_hw *hw); | ||||
| int rt2x00mac_add_interface(struct ieee80211_hw *hw, | ||||
| 			    struct ieee80211_if_init_conf *conf); | ||||
| 			    struct ieee80211_vif *vif); | ||||
| void rt2x00mac_remove_interface(struct ieee80211_hw *hw, | ||||
| 				struct ieee80211_if_init_conf *conf); | ||||
| 				struct ieee80211_vif *vif); | ||||
| int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); | ||||
| void rt2x00mac_configure_filter(struct ieee80211_hw *hw, | ||||
| 				unsigned int changed_flags, | ||||
|  | ||||
| @ -187,10 +187,10 @@ void rt2x00mac_stop(struct ieee80211_hw *hw) | ||||
| EXPORT_SYMBOL_GPL(rt2x00mac_stop); | ||||
| 
 | ||||
| int rt2x00mac_add_interface(struct ieee80211_hw *hw, | ||||
| 			    struct ieee80211_if_init_conf *conf) | ||||
| 			    struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct rt2x00_dev *rt2x00dev = hw->priv; | ||||
| 	struct rt2x00_intf *intf = vif_to_intf(conf->vif); | ||||
| 	struct rt2x00_intf *intf = vif_to_intf(vif); | ||||
| 	struct data_queue *queue = rt2x00queue_get_queue(rt2x00dev, QID_BEACON); | ||||
| 	struct queue_entry *entry = NULL; | ||||
| 	unsigned int i; | ||||
| @ -203,7 +203,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, | ||||
| 	    !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_AP: | ||||
| 		/*
 | ||||
| 		 * We don't support mixed combinations of | ||||
| @ -263,7 +263,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, | ||||
| 	 * increase interface count and start initialization. | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (conf->type == NL80211_IFTYPE_AP) | ||||
| 	if (vif->type == NL80211_IFTYPE_AP) | ||||
| 		rt2x00dev->intf_ap_count++; | ||||
| 	else | ||||
| 		rt2x00dev->intf_sta_count++; | ||||
| @ -273,16 +273,16 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, | ||||
| 	mutex_init(&intf->beacon_skb_mutex); | ||||
| 	intf->beacon = entry; | ||||
| 
 | ||||
| 	if (conf->type == NL80211_IFTYPE_AP) | ||||
| 		memcpy(&intf->bssid, conf->mac_addr, ETH_ALEN); | ||||
| 	memcpy(&intf->mac, conf->mac_addr, ETH_ALEN); | ||||
| 	if (vif->type == NL80211_IFTYPE_AP) | ||||
| 		memcpy(&intf->bssid, vif->addr, ETH_ALEN); | ||||
| 	memcpy(&intf->mac, vif->addr, ETH_ALEN); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The MAC adddress must be configured after the device | ||||
| 	 * has been initialized. Otherwise the device can reset | ||||
| 	 * the MAC registers. | ||||
| 	 */ | ||||
| 	rt2x00lib_config_intf(rt2x00dev, intf, conf->type, intf->mac, NULL); | ||||
| 	rt2x00lib_config_intf(rt2x00dev, intf, vif->type, intf->mac, NULL); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Some filters depend on the current working mode. We can force | ||||
| @ -296,10 +296,10 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, | ||||
| EXPORT_SYMBOL_GPL(rt2x00mac_add_interface); | ||||
| 
 | ||||
| void rt2x00mac_remove_interface(struct ieee80211_hw *hw, | ||||
| 				struct ieee80211_if_init_conf *conf) | ||||
| 				struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct rt2x00_dev *rt2x00dev = hw->priv; | ||||
| 	struct rt2x00_intf *intf = vif_to_intf(conf->vif); | ||||
| 	struct rt2x00_intf *intf = vif_to_intf(vif); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Don't allow interfaces to be remove while | ||||
| @ -307,11 +307,11 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, | ||||
| 	 * no interface is present. | ||||
| 	 */ | ||||
| 	if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || | ||||
| 	    (conf->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || | ||||
| 	    (conf->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) | ||||
| 	    (vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || | ||||
| 	    (vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (conf->type == NL80211_IFTYPE_AP) | ||||
| 	if (vif->type == NL80211_IFTYPE_AP) | ||||
| 		rt2x00dev->intf_ap_count--; | ||||
| 	else | ||||
| 		rt2x00dev->intf_sta_count--; | ||||
|  | ||||
| @ -637,8 +637,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, | ||||
| 	rt61pci_bbp_read(rt2x00dev, 4, &r4); | ||||
| 	rt61pci_bbp_read(rt2x00dev, 77, &r77); | ||||
| 
 | ||||
| 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, | ||||
| 			  rt2x00_rf(&rt2x00dev->chip, RF5325)); | ||||
| 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF5325)); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Configure the RX antenna. | ||||
| @ -684,8 +683,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev, | ||||
| 	rt61pci_bbp_read(rt2x00dev, 4, &r4); | ||||
| 	rt61pci_bbp_read(rt2x00dev, 77, &r77); | ||||
| 
 | ||||
| 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, | ||||
| 			  rt2x00_rf(&rt2x00dev->chip, RF2529)); | ||||
| 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529)); | ||||
| 	rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, | ||||
| 			  !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags)); | ||||
| 
 | ||||
| @ -833,12 +831,11 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, | ||||
| 
 | ||||
| 	rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg); | ||||
| 
 | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF5225) || | ||||
| 	    rt2x00_rf(&rt2x00dev->chip, RF5325)) | ||||
| 	if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) | ||||
| 		rt61pci_config_antenna_5x(rt2x00dev, ant); | ||||
| 	else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) | ||||
| 	else if (rt2x00_rf(rt2x00dev, RF2527)) | ||||
| 		rt61pci_config_antenna_2x(rt2x00dev, ant); | ||||
| 	else if (rt2x00_rf(&rt2x00dev->chip, RF2529)) { | ||||
| 	else if (rt2x00_rf(rt2x00dev, RF2529)) { | ||||
| 		if (test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) | ||||
| 			rt61pci_config_antenna_2x(rt2x00dev, ant); | ||||
| 		else | ||||
| @ -879,8 +876,7 @@ static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, | ||||
| 	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); | ||||
| 	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); | ||||
| 
 | ||||
| 	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || | ||||
| 		  rt2x00_rf(&rt2x00dev->chip, RF2527)); | ||||
| 	smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); | ||||
| 
 | ||||
| 	rt61pci_bbp_read(rt2x00dev, 3, &r3); | ||||
| 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); | ||||
| @ -2302,10 +2298,10 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2x00_set_chip_rf(rt2x00dev, value, reg); | ||||
| 	rt2x00_print_chip(rt2x00dev); | ||||
| 
 | ||||
| 	if (!rt2x00_rf(&rt2x00dev->chip, RF5225) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF5325) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2527) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2529)) { | ||||
| 	if (!rt2x00_rf(rt2x00dev, RF5225) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF5325) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2527) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2529)) { | ||||
| 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| @ -2360,7 +2356,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||||
| 	 * the antenna settings should be gathered from the NIC | ||||
| 	 * eeprom word. | ||||
| 	 */ | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF2529) && | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2529) && | ||||
| 	    !test_bit(CONFIG_DOUBLE_ANTENNA, &rt2x00dev->flags)) { | ||||
| 		rt2x00dev->default_ant.rx = | ||||
| 		    ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED); | ||||
| @ -2571,8 +2567,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||||
| 		spec->channels = rf_vals_seq; | ||||
| 	} | ||||
| 
 | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF5225) || | ||||
| 	    rt2x00_rf(&rt2x00dev->chip, RF5325)) { | ||||
| 	if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF5325)) { | ||||
| 		spec->supported_bands |= SUPPORT_BAND_5GHZ; | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_seq); | ||||
| 	} | ||||
|  | ||||
| @ -136,8 +136,8 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, | ||||
| 		 * all others contain 20 bits. | ||||
| 		 */ | ||||
| 		rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, | ||||
| 				   20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || | ||||
| 					 rt2x00_rf(&rt2x00dev->chip, RF2527))); | ||||
| 				   20 + (rt2x00_rf(rt2x00dev, RF5225) || | ||||
| 					 rt2x00_rf(rt2x00dev, RF2527))); | ||||
| 		rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); | ||||
| 		rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); | ||||
| 
 | ||||
| @ -741,11 +741,9 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, | ||||
| 
 | ||||
| 	rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg); | ||||
| 
 | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF5226) || | ||||
| 	    rt2x00_rf(&rt2x00dev->chip, RF5225)) | ||||
| 	if (rt2x00_rf(rt2x00dev, RF5226) || rt2x00_rf(rt2x00dev, RF5225)) | ||||
| 		rt73usb_config_antenna_5x(rt2x00dev, ant); | ||||
| 	else if (rt2x00_rf(&rt2x00dev->chip, RF2528) || | ||||
| 		 rt2x00_rf(&rt2x00dev->chip, RF2527)) | ||||
| 	else if (rt2x00_rf(rt2x00dev, RF2528) || rt2x00_rf(rt2x00dev, RF2527)) | ||||
| 		rt73usb_config_antenna_2x(rt2x00dev, ant); | ||||
| } | ||||
| 
 | ||||
| @ -779,8 +777,7 @@ static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, | ||||
| 	rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); | ||||
| 	rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); | ||||
| 
 | ||||
| 	smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || | ||||
| 		  rt2x00_rf(&rt2x00dev->chip, RF2527)); | ||||
| 	smart = !(rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)); | ||||
| 
 | ||||
| 	rt73usb_bbp_read(rt2x00dev, 3, &r3); | ||||
| 	rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); | ||||
| @ -1210,8 +1207,7 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); | ||||
| 
 | ||||
| 	reg = 0x000023b0; | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF5225) || | ||||
| 	    rt2x00_rf(&rt2x00dev->chip, RF2527)) | ||||
| 	if (rt2x00_rf(rt2x00dev, RF5225) || rt2x00_rf(rt2x00dev, RF2527)) | ||||
| 		rt2x00_set_field32(®, PHY_CSR1_RF_RPI, 1); | ||||
| 	rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg); | ||||
| 
 | ||||
| @ -1827,16 +1823,16 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) | ||||
| 	rt2x00_set_chip(rt2x00dev, RT2571, value, reg); | ||||
| 	rt2x00_print_chip(rt2x00dev); | ||||
| 
 | ||||
| 	if (!rt2x00_check_rev(&rt2x00dev->chip, 0x000ffff0, 0x25730) || | ||||
| 	    rt2x00_check_rev(&rt2x00dev->chip, 0x0000000f, 0)) { | ||||
| 	if (!rt2x00_check_rev(rt2x00dev, 0x000ffff0, 0x25730) || | ||||
| 	    rt2x00_check_rev(rt2x00dev, 0x0000000f, 0)) { | ||||
| 		ERROR(rt2x00dev, "Invalid RT chipset detected.\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!rt2x00_rf(&rt2x00dev->chip, RF5226) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2528) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF5225) && | ||||
| 	    !rt2x00_rf(&rt2x00dev->chip, RF2527)) { | ||||
| 	if (!rt2x00_rf(rt2x00dev, RF5226) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2528) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF5225) && | ||||
| 	    !rt2x00_rf(rt2x00dev, RF2527)) { | ||||
| 		ERROR(rt2x00dev, "Invalid RF chipset detected.\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| @ -2081,17 +2077,17 @@ static int rt73usb_probe_hw_mode(struct rt2x00_dev *rt2x00dev) | ||||
| 	spec->supported_bands = SUPPORT_BAND_2GHZ; | ||||
| 	spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM; | ||||
| 
 | ||||
| 	if (rt2x00_rf(&rt2x00dev->chip, RF2528)) { | ||||
| 	if (rt2x00_rf(rt2x00dev, RF2528)) { | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_bg_2528); | ||||
| 		spec->channels = rf_vals_bg_2528; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF5226)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF5226)) { | ||||
| 		spec->supported_bands |= SUPPORT_BAND_5GHZ; | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_5226); | ||||
| 		spec->channels = rf_vals_5226; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF2527)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF2527)) { | ||||
| 		spec->num_channels = 14; | ||||
| 		spec->channels = rf_vals_5225_2527; | ||||
| 	} else if (rt2x00_rf(&rt2x00dev->chip, RF5225)) { | ||||
| 	} else if (rt2x00_rf(rt2x00dev, RF5225)) { | ||||
| 		spec->supported_bands |= SUPPORT_BAND_5GHZ; | ||||
| 		spec->num_channels = ARRAY_SIZE(rf_vals_5225_2527); | ||||
| 		spec->channels = rf_vals_5225_2527; | ||||
|  | ||||
| @ -60,7 +60,6 @@ struct rtl8180_priv { | ||||
| 	struct rtl818x_csr __iomem *map; | ||||
| 	const struct rtl818x_rf_ops *rf; | ||||
| 	struct ieee80211_vif *vif; | ||||
| 	int mode; | ||||
| 
 | ||||
| 	/* rtl8180 driver specific */ | ||||
| 	spinlock_t lock; | ||||
|  | ||||
| @ -82,8 +82,6 @@ static const struct ieee80211_channel rtl818x_channels[] = { | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) | ||||
| { | ||||
| 	struct rtl8180_priv *priv = dev->priv; | ||||
| @ -615,7 +613,6 @@ static int rtl8180_start(struct ieee80211_hw *dev) | ||||
| 	reg |= RTL818X_CMD_TX_ENABLE; | ||||
| 	rtl818x_iowrite8(priv, &priv->map->CMD, reg); | ||||
| 
 | ||||
| 	priv->mode = NL80211_IFTYPE_MONITOR; | ||||
| 	return 0; | ||||
| 
 | ||||
|  err_free_rings: | ||||
| @ -633,8 +630,6 @@ static void rtl8180_stop(struct ieee80211_hw *dev) | ||||
| 	u8 reg; | ||||
| 	int i; | ||||
| 
 | ||||
| 	priv->mode = NL80211_IFTYPE_UNSPECIFIED; | ||||
| 
 | ||||
| 	rtl818x_iowrite16(priv, &priv->map->INT_MASK, 0); | ||||
| 
 | ||||
| 	reg = rtl818x_ioread8(priv, &priv->map->CMD); | ||||
| @ -657,38 +652,39 @@ static void rtl8180_stop(struct ieee80211_hw *dev) | ||||
| } | ||||
| 
 | ||||
| static int rtl8180_add_interface(struct ieee80211_hw *dev, | ||||
| 				 struct ieee80211_if_init_conf *conf) | ||||
| 				 struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct rtl8180_priv *priv = dev->priv; | ||||
| 
 | ||||
| 	if (priv->mode != NL80211_IFTYPE_MONITOR) | ||||
| 		return -EOPNOTSUPP; | ||||
| 	/*
 | ||||
| 	 * We only support one active interface at a time. | ||||
| 	 */ | ||||
| 	if (priv->vif) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 		priv->mode = conf->type; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EOPNOTSUPP; | ||||
| 	} | ||||
| 
 | ||||
| 	priv->vif = conf->vif; | ||||
| 	priv->vif = vif; | ||||
| 
 | ||||
| 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); | ||||
| 	rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0], | ||||
| 			  le32_to_cpu(*(__le32 *)conf->mac_addr)); | ||||
| 			  le32_to_cpu(*(__le32 *)vif->addr)); | ||||
| 	rtl818x_iowrite16(priv, (__le16 __iomem *)&priv->map->MAC[4], | ||||
| 			  le16_to_cpu(*(__le16 *)(conf->mac_addr + 4))); | ||||
| 			  le16_to_cpu(*(__le16 *)(vif->addr + 4))); | ||||
| 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void rtl8180_remove_interface(struct ieee80211_hw *dev, | ||||
| 				     struct ieee80211_if_init_conf *conf) | ||||
| 				     struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct rtl8180_priv *priv = dev->priv; | ||||
| 	priv->mode = NL80211_IFTYPE_MONITOR; | ||||
| 	priv->vif = NULL; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -92,7 +92,7 @@ struct rtl8187_priv { | ||||
| 	struct rtl818x_csr *map; | ||||
| 	const struct rtl818x_rf_ops *rf; | ||||
| 	struct ieee80211_vif *vif; | ||||
| 	int mode; | ||||
| 
 | ||||
| 	/* The mutex protects the TX loopback state.
 | ||||
| 	 * Any attempt to set channels concurrently locks the device. | ||||
| 	 */ | ||||
|  | ||||
| @ -1018,31 +1018,30 @@ static void rtl8187_stop(struct ieee80211_hw *dev) | ||||
| } | ||||
| 
 | ||||
| static int rtl8187_add_interface(struct ieee80211_hw *dev, | ||||
| 				 struct ieee80211_if_init_conf *conf) | ||||
| 				 struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct rtl8187_priv *priv = dev->priv; | ||||
| 	int i; | ||||
| 	int ret = -EOPNOTSUPP; | ||||
| 
 | ||||
| 	mutex_lock(&priv->conf_mutex); | ||||
| 	if (priv->mode != NL80211_IFTYPE_MONITOR) | ||||
| 	if (priv->vif) | ||||
| 		goto exit; | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 		priv->mode = conf->type; | ||||
| 		break; | ||||
| 	default: | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = 0; | ||||
| 	priv->vif = conf->vif; | ||||
| 	priv->vif = vif; | ||||
| 
 | ||||
| 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); | ||||
| 	for (i = 0; i < ETH_ALEN; i++) | ||||
| 		rtl818x_iowrite8(priv, &priv->map->MAC[i], | ||||
| 				 ((u8 *)conf->mac_addr)[i]); | ||||
| 				 ((u8 *)vif->addr)[i]); | ||||
| 	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); | ||||
| 
 | ||||
| exit: | ||||
| @ -1051,11 +1050,10 @@ exit: | ||||
| } | ||||
| 
 | ||||
| static void rtl8187_remove_interface(struct ieee80211_hw *dev, | ||||
| 				     struct ieee80211_if_init_conf *conf) | ||||
| 				     struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct rtl8187_priv *priv = dev->priv; | ||||
| 	mutex_lock(&priv->conf_mutex); | ||||
| 	priv->mode = NL80211_IFTYPE_MONITOR; | ||||
| 	priv->vif = NULL; | ||||
| 	mutex_unlock(&priv->conf_mutex); | ||||
| } | ||||
| @ -1365,7 +1363,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, | ||||
| 	dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; | ||||
| 
 | ||||
| 
 | ||||
| 	priv->mode = NL80211_IFTYPE_MONITOR; | ||||
| 	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | | ||||
| 		     IEEE80211_HW_SIGNAL_DBM | | ||||
| 		     IEEE80211_HW_RX_INCLUDES_FCS; | ||||
|  | ||||
| @ -33,7 +33,7 @@ static void led_turn_on(struct work_struct *work) | ||||
| 	struct rtl8187_led *led = &priv->led_tx; | ||||
| 
 | ||||
| 	/* Don't change the LED, when the device is down. */ | ||||
| 	if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) | ||||
| 	if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED) | ||||
| 		return ; | ||||
| 
 | ||||
| 	/* Skip if the LED is not registered. */ | ||||
| @ -71,7 +71,7 @@ static void led_turn_off(struct work_struct *work) | ||||
| 	struct rtl8187_led *led = &priv->led_tx; | ||||
| 
 | ||||
| 	/* Don't change the LED, when the device is down. */ | ||||
| 	if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) | ||||
| 	if (!priv->vif || priv->vif->type == NL80211_IFTYPE_UNSPECIFIED) | ||||
| 		return ; | ||||
| 
 | ||||
| 	/* Skip if the LED is not registered. */ | ||||
|  | ||||
| @ -256,7 +256,7 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (loop >= INIT_LOOP) { | ||||
| 	if (loop > INIT_LOOP) { | ||||
| 		wl1251_error("timeout waiting for the hardware to " | ||||
| 			     "complete initialization"); | ||||
| 		return -EIO; | ||||
|  | ||||
| @ -511,13 +511,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) | ||||
| } | ||||
| 
 | ||||
| static int wl1251_op_add_interface(struct ieee80211_hw *hw, | ||||
| 				   struct ieee80211_if_init_conf *conf) | ||||
| 				   struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct wl1251 *wl = hw->priv; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | ||||
| 		     conf->type, conf->mac_addr); | ||||
| 		     vif->type, vif->addr); | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 	if (wl->vif) { | ||||
| @ -525,9 +525,9 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	wl->vif = conf->vif; | ||||
| 	wl->vif = vif; | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 		wl->bss_type = BSS_TYPE_STA_BSS; | ||||
| 		break; | ||||
| @ -539,8 +539,8 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw, | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (memcmp(wl->mac_addr, conf->mac_addr, ETH_ALEN)) { | ||||
| 		memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN); | ||||
| 	if (memcmp(wl->mac_addr, vif->addr, ETH_ALEN)) { | ||||
| 		memcpy(wl->mac_addr, vif->addr, ETH_ALEN); | ||||
| 		SET_IEEE80211_PERM_ADDR(wl->hw, wl->mac_addr); | ||||
| 		ret = wl1251_acx_station_id(wl); | ||||
| 		if (ret < 0) | ||||
| @ -553,7 +553,7 @@ out: | ||||
| } | ||||
| 
 | ||||
| static void wl1251_op_remove_interface(struct ieee80211_hw *hw, | ||||
| 					 struct ieee80211_if_init_conf *conf) | ||||
| 					 struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct wl1251 *wl = hw->priv; | ||||
| 
 | ||||
|  | ||||
| @ -107,10 +107,9 @@ enum { | ||||
| 				  CFG_RX_CTL_EN | CFG_RX_BCN_EN |     \ | ||||
| 				  CFG_RX_AUTH_EN | CFG_RX_ASSOC_EN) | ||||
| 
 | ||||
| #define WL1271_DEFAULT_BASIC_RATE_SET (CONF_TX_RATE_MASK_ALL) | ||||
| 
 | ||||
| #define WL1271_FW_NAME "wl1271-fw.bin" | ||||
| #define WL1271_NVS_NAME "wl1271-nvs.bin" | ||||
| #define WL1271_NVS_LEN  468 | ||||
| 
 | ||||
| /*
 | ||||
|  * Enable/disable 802.11a support for WL1273 | ||||
| @ -276,6 +275,7 @@ struct wl1271_debugfs { | ||||
| 
 | ||||
| 	struct dentry *retry_count; | ||||
| 	struct dentry *excessive_retries; | ||||
| 	struct dentry *gpio_power; | ||||
| }; | ||||
| 
 | ||||
| #define NUM_TX_QUEUES              4 | ||||
| @ -322,6 +322,17 @@ struct wl1271 { | ||||
| 	enum wl1271_state state; | ||||
| 	struct mutex mutex; | ||||
| 
 | ||||
| #define WL1271_FLAG_STA_RATES_CHANGED  (0) | ||||
| #define WL1271_FLAG_STA_ASSOCIATED     (1) | ||||
| #define WL1271_FLAG_JOINED             (2) | ||||
| #define WL1271_FLAG_GPIO_POWER         (3) | ||||
| #define WL1271_FLAG_TX_QUEUE_STOPPED   (4) | ||||
| #define WL1271_FLAG_SCANNING           (5) | ||||
| #define WL1271_FLAG_IN_ELP             (6) | ||||
| #define WL1271_FLAG_PSM                (7) | ||||
| #define WL1271_FLAG_PSM_REQUESTED      (8) | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	struct wl1271_partition_set part; | ||||
| 
 | ||||
| 	struct wl1271_chip chip; | ||||
| @ -359,7 +370,6 @@ struct wl1271 { | ||||
| 
 | ||||
| 	/* Frames scheduled for transmission, not handled yet */ | ||||
| 	struct sk_buff_head tx_queue; | ||||
| 	bool tx_queue_stopped; | ||||
| 
 | ||||
| 	struct work_struct tx_work; | ||||
| 
 | ||||
| @ -387,14 +397,15 @@ struct wl1271 { | ||||
| 	u32 mbox_ptr[2]; | ||||
| 
 | ||||
| 	/* Are we currently scanning */ | ||||
| 	bool scanning; | ||||
| 	struct wl1271_scan scan; | ||||
| 
 | ||||
| 	/* Our association ID */ | ||||
| 	u16 aid; | ||||
| 
 | ||||
| 	/* currently configured rate set */ | ||||
| 	u32 sta_rate_set; | ||||
| 	u32 basic_rate_set; | ||||
| 	u32 rate_set; | ||||
| 
 | ||||
| 	/* The current band */ | ||||
| 	enum ieee80211_band band; | ||||
| @ -405,18 +416,9 @@ struct wl1271 { | ||||
| 	unsigned int rx_config; | ||||
| 	unsigned int rx_filter; | ||||
| 
 | ||||
| 	/* is firmware in elp mode */ | ||||
| 	bool elp; | ||||
| 
 | ||||
| 	struct completion *elp_compl; | ||||
| 	struct delayed_work elp_work; | ||||
| 
 | ||||
| 	/* we can be in psm, but not in elp, we have to differentiate */ | ||||
| 	bool psm; | ||||
| 
 | ||||
| 	/* PSM mode requested */ | ||||
| 	bool psm_requested; | ||||
| 
 | ||||
| 	/* retry counter for PSM entries */ | ||||
| 	u8 psm_entry_retry; | ||||
| 
 | ||||
| @ -435,9 +437,6 @@ struct wl1271 { | ||||
| 
 | ||||
| 	struct ieee80211_vif *vif; | ||||
| 
 | ||||
| 	/* Used for a workaround to send disconnect before rejoining */ | ||||
| 	bool joined; | ||||
| 
 | ||||
| 	/* Current chipset configuration */ | ||||
| 	struct conf_drv_settings conf; | ||||
| 
 | ||||
| @ -455,7 +454,9 @@ int wl1271_plt_stop(struct wl1271 *wl); | ||||
| 
 | ||||
| #define WL1271_TX_QUEUE_MAX_LENGTH 20 | ||||
| 
 | ||||
| /* WL1271 needs a 200ms sleep after power on */ | ||||
| /* WL1271 needs a 200ms sleep after power on, and a 20ms sleep before power
 | ||||
|    on in case is has been shut down shortly before */ | ||||
| #define WL1271_PRE_POWER_ON_SLEEP 20 /* in miliseconds */ | ||||
| #define WL1271_POWER_ON_SLEEP 200 /* in miliseconds */ | ||||
| 
 | ||||
| static inline bool wl1271_11a_enabled(void) | ||||
|  | ||||
| @ -390,6 +390,35 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int wl1271_acx_dco_itrim_params(struct wl1271 *wl) | ||||
| { | ||||
| 	struct acx_dco_itrim_params *dco; | ||||
| 	struct conf_itrim_settings *c = &wl->conf.itrim; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_ACX, "acx dco itrim parameters"); | ||||
| 
 | ||||
| 	dco = kzalloc(sizeof(*dco), GFP_KERNEL); | ||||
| 	if (!dco) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	dco->enable = c->enable; | ||||
| 	dco->timeout = cpu_to_le32(c->timeout); | ||||
| 
 | ||||
| 	ret = wl1271_cmd_configure(wl, ACX_SET_DCO_ITRIM_PARAMS, | ||||
| 				   dco, sizeof(*dco)); | ||||
| 	if (ret < 0) { | ||||
| 		wl1271_warning("failed to set dco itrim parameters: %d", ret); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	kfree(dco); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter) | ||||
| { | ||||
| 	struct acx_beacon_filter_option *beacon_filter = NULL; | ||||
| @ -758,10 +787,11 @@ int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) | ||||
| int wl1271_acx_rate_policies(struct wl1271 *wl) | ||||
| { | ||||
| 	struct acx_rate_policy *acx; | ||||
| 	struct conf_tx_rate_class *c = &wl->conf.tx.rc_conf; | ||||
| 	int idx = 0; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_ACX, "acx rate policies"); | ||||
| @ -773,12 +803,21 @@ int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates) | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/* configure one default (one-size-fits-all) rate class */ | ||||
| 	acx->rate_class_cnt = cpu_to_le32(1); | ||||
| 	acx->rate_class[0].enabled_rates = cpu_to_le32(enabled_rates); | ||||
| 	acx->rate_class[0].short_retry_limit = c->short_retry_limit; | ||||
| 	acx->rate_class[0].long_retry_limit = c->long_retry_limit; | ||||
| 	acx->rate_class[0].aflags = c->aflags; | ||||
| 	/* configure one basic rate class */ | ||||
| 	idx = ACX_TX_BASIC_RATE; | ||||
| 	acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->basic_rate_set); | ||||
| 	acx->rate_class[idx].short_retry_limit = c->short_retry_limit; | ||||
| 	acx->rate_class[idx].long_retry_limit = c->long_retry_limit; | ||||
| 	acx->rate_class[idx].aflags = c->aflags; | ||||
| 
 | ||||
| 	/* configure one AP supported rate class */ | ||||
| 	idx = ACX_TX_AP_FULL_RATE; | ||||
| 	acx->rate_class[idx].enabled_rates = cpu_to_le32(wl->rate_set); | ||||
| 	acx->rate_class[idx].short_retry_limit = c->short_retry_limit; | ||||
| 	acx->rate_class[idx].long_retry_limit = c->long_retry_limit; | ||||
| 	acx->rate_class[idx].aflags = c->aflags; | ||||
| 
 | ||||
| 	acx->rate_class_cnt = cpu_to_le32(ACX_TX_RATE_POLICY_CNT); | ||||
| 
 | ||||
| 	ret = wl1271_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); | ||||
| 	if (ret < 0) { | ||||
| @ -1012,59 +1051,6 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int wl1271_acx_smart_reflex(struct wl1271 *wl) | ||||
| { | ||||
| 	struct acx_smart_reflex_state *sr_state = NULL; | ||||
| 	struct acx_smart_reflex_config_params *sr_param = NULL; | ||||
| 	int i, ret; | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_ACX, "acx smart reflex"); | ||||
| 
 | ||||
| 	sr_param = kzalloc(sizeof(*sr_param), GFP_KERNEL); | ||||
| 	if (!sr_param) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < CONF_SR_ERR_TBL_COUNT; i++) { | ||||
| 		struct conf_mart_reflex_err_table *e = | ||||
| 			&(wl->conf.init.sr_err_tbl[i]); | ||||
| 
 | ||||
| 		sr_param->error_table[i].len = e->len; | ||||
| 		sr_param->error_table[i].upper_limit = e->upper_limit; | ||||
| 		memcpy(sr_param->error_table[i].values, e->values, e->len); | ||||
| 	} | ||||
| 
 | ||||
| 	ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_PARAMS, | ||||
| 				   sr_param, sizeof(*sr_param)); | ||||
| 	if (ret < 0) { | ||||
| 		wl1271_warning("failed to set smart reflex params: %d", ret); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	sr_state = kzalloc(sizeof(*sr_state), GFP_KERNEL); | ||||
| 	if (!sr_state) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/* enable smart reflex */ | ||||
| 	sr_state->enable = wl->conf.init.sr_enable; | ||||
| 
 | ||||
| 	ret = wl1271_cmd_configure(wl, ACX_SET_SMART_REFLEX_STATE, | ||||
| 				   sr_state, sizeof(*sr_state)); | ||||
| 	if (ret < 0) { | ||||
| 		wl1271_warning("failed to set smart reflex params: %d", ret); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	kfree(sr_state); | ||||
| 	kfree(sr_param); | ||||
| 	return ret; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable) | ||||
| { | ||||
| 	struct wl1271_acx_bet_enable *acx = NULL; | ||||
| @ -1132,3 +1118,31 @@ out: | ||||
| 	kfree(acx); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int wl1271_acx_pm_config(struct wl1271 *wl) | ||||
| { | ||||
| 	struct wl1271_acx_pm_config *acx = NULL; | ||||
| 	struct  conf_pm_config_settings *c = &wl->conf.pm_config; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_ACX, "acx pm config"); | ||||
| 
 | ||||
| 	acx = kzalloc(sizeof(*acx), GFP_KERNEL); | ||||
| 	if (!acx) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	acx->host_clk_settling_time = cpu_to_le32(c->host_clk_settling_time); | ||||
| 	acx->host_fast_wakeup_support = c->host_fast_wakeup_support; | ||||
| 
 | ||||
| 	ret = wl1271_cmd_configure(wl, ACX_PM_CONFIG, acx, sizeof(*acx)); | ||||
| 	if (ret < 0) { | ||||
| 		wl1271_warning("acx pm config failed: %d", ret); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	kfree(acx); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| @ -415,23 +415,12 @@ struct acx_bt_wlan_coex { | ||||
| 	u8 pad[3]; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| struct acx_smart_reflex_state { | ||||
| struct acx_dco_itrim_params { | ||||
| 	struct acx_header header; | ||||
| 
 | ||||
| 	u8 enable; | ||||
| 	u8 padding[3]; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| struct smart_reflex_err_table { | ||||
| 	u8 len; | ||||
| 	s8 upper_limit; | ||||
| 	s8 values[14]; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| struct acx_smart_reflex_config_params { | ||||
| 	struct acx_header header; | ||||
| 
 | ||||
| 	struct smart_reflex_err_table error_table[3]; | ||||
| 	__le32 timeout; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| #define PTA_ANTENNA_TYPE_DEF		  (0) | ||||
| @ -837,6 +826,9 @@ struct acx_rate_class { | ||||
| 	u8 reserved; | ||||
| }; | ||||
| 
 | ||||
| #define ACX_TX_BASIC_RATE      0 | ||||
| #define ACX_TX_AP_FULL_RATE    1 | ||||
| #define ACX_TX_RATE_POLICY_CNT 2 | ||||
| struct acx_rate_policy { | ||||
| 	struct acx_header header; | ||||
| 
 | ||||
| @ -877,8 +869,8 @@ struct acx_tx_config_options { | ||||
| 	__le16 tx_compl_threshold;   /* number of packets */ | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| #define ACX_RX_MEM_BLOCKS     64 | ||||
| #define ACX_TX_MIN_MEM_BLOCKS 64 | ||||
| #define ACX_RX_MEM_BLOCKS     70 | ||||
| #define ACX_TX_MIN_MEM_BLOCKS 40 | ||||
| #define ACX_TX_DESCRIPTORS    32 | ||||
| #define ACX_NUM_SSID_PROFILES 1 | ||||
| 
 | ||||
| @ -969,6 +961,13 @@ struct wl1271_acx_arp_filter { | ||||
| 			       used. */ | ||||
| } __attribute__((packed)); | ||||
| 
 | ||||
| struct wl1271_acx_pm_config { | ||||
| 	struct acx_header header; | ||||
| 
 | ||||
| 	__le32 host_clk_settling_time; | ||||
| 	u8 host_fast_wakeup_support; | ||||
| 	u8 padding[3]; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| enum { | ||||
| 	ACX_WAKE_UP_CONDITIONS      = 0x0002, | ||||
| @ -1027,13 +1026,13 @@ enum { | ||||
| 	ACX_HT_BSS_OPERATION        = 0x0058, | ||||
| 	ACX_COEX_ACTIVITY           = 0x0059, | ||||
| 	ACX_SET_SMART_REFLEX_DEBUG  = 0x005A, | ||||
| 	ACX_SET_SMART_REFLEX_STATE  = 0x005B, | ||||
| 	ACX_SET_SMART_REFLEX_PARAMS = 0x005F, | ||||
| 	ACX_SET_DCO_ITRIM_PARAMS    = 0x0061, | ||||
| 	DOT11_RX_MSDU_LIFE_TIME     = 0x1004, | ||||
| 	DOT11_CUR_TX_PWR            = 0x100D, | ||||
| 	DOT11_RX_DOT11_MODE         = 0x1012, | ||||
| 	DOT11_RTS_THRESHOLD         = 0x1013, | ||||
| 	DOT11_GROUP_ADDRESS_TBL     = 0x1014, | ||||
| 	ACX_PM_CONFIG               = 0x1016, | ||||
| 
 | ||||
| 	MAX_DOT11_IE = DOT11_GROUP_ADDRESS_TBL, | ||||
| 
 | ||||
| @ -1056,6 +1055,7 @@ int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable, | ||||
| 				 void *mc_list, u32 mc_list_len); | ||||
| int wl1271_acx_service_period_timeout(struct wl1271 *wl); | ||||
| int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold); | ||||
| int wl1271_acx_dco_itrim_params(struct wl1271 *wl); | ||||
| int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter); | ||||
| int wl1271_acx_beacon_filter_table(struct wl1271 *wl); | ||||
| int wl1271_acx_conn_monit_params(struct wl1271 *wl); | ||||
| @ -1069,7 +1069,7 @@ int wl1271_acx_set_preamble(struct wl1271 *wl, enum acx_preamble_type preamble); | ||||
| int wl1271_acx_cts_protect(struct wl1271 *wl, | ||||
| 			   enum acx_ctsprotect_type ctsprotect); | ||||
| int wl1271_acx_statistics(struct wl1271 *wl, struct acx_statistics *stats); | ||||
| int wl1271_acx_rate_policies(struct wl1271 *wl, u32 enabled_rates); | ||||
| int wl1271_acx_rate_policies(struct wl1271 *wl); | ||||
| int wl1271_acx_ac_cfg(struct wl1271 *wl); | ||||
| int wl1271_acx_tid_cfg(struct wl1271 *wl); | ||||
| int wl1271_acx_frag_threshold(struct wl1271 *wl); | ||||
| @ -1081,5 +1081,6 @@ int wl1271_acx_smart_reflex(struct wl1271 *wl); | ||||
| int wl1271_acx_bet_enable(struct wl1271 *wl, bool enable); | ||||
| int wl1271_acx_arp_ip_filter(struct wl1271 *wl, bool enable, u8 *address, | ||||
| 			     u8 version); | ||||
| int wl1271_acx_pm_config(struct wl1271 *wl); | ||||
| 
 | ||||
| #endif /* __WL1271_ACX_H__ */ | ||||
|  | ||||
| @ -225,9 +225,15 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) | ||||
| 	if (nvs == NULL) | ||||
| 		return -ENODEV; | ||||
| 
 | ||||
| 	if (wl->nvs_len < WL1271_NVS_LEN) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	nvs_ptr = nvs; | ||||
| 
 | ||||
| 	nvs_len = wl->nvs_len; | ||||
| 	/* only the first part of the NVS needs to be uploaded */ | ||||
| 	nvs_len = WL1271_NVS_LEN; | ||||
| 
 | ||||
| 	/* FIXME: read init settings from the remaining part of the NVS */ | ||||
| 
 | ||||
| 	/* Update the device MAC address into the nvs */ | ||||
| 	nvs[11] = wl->mac_addr[0]; | ||||
|  | ||||
| @ -209,6 +209,26 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) | ||||
| 	gen_parms->tx_bip_fem_manufacturer = g->tx_bip_fem_manufacturer; | ||||
| 	gen_parms->settings = g->settings; | ||||
| 
 | ||||
| 	gen_parms->sr_state = g->sr_state; | ||||
| 
 | ||||
| 	memcpy(gen_parms->srf1, | ||||
| 	       g->srf1, | ||||
| 	       CONF_MAX_SMART_REFLEX_PARAMS); | ||||
| 	memcpy(gen_parms->srf2, | ||||
| 	       g->srf2, | ||||
| 	       CONF_MAX_SMART_REFLEX_PARAMS); | ||||
| 	memcpy(gen_parms->srf3, | ||||
| 	       g->srf3, | ||||
| 	       CONF_MAX_SMART_REFLEX_PARAMS); | ||||
| 	memcpy(gen_parms->sr_debug_table, | ||||
| 	       g->sr_debug_table, | ||||
| 	       CONF_MAX_SMART_REFLEX_PARAMS); | ||||
| 
 | ||||
| 	gen_parms->sr_sen_n_p = g->sr_sen_n_p; | ||||
| 	gen_parms->sr_sen_n_p_gain = g->sr_sen_n_p_gain; | ||||
| 	gen_parms->sr_sen_nrn = g->sr_sen_nrn; | ||||
| 	gen_parms->sr_sen_prn = g->sr_sen_prn; | ||||
| 
 | ||||
| 	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0); | ||||
| 	if (ret < 0) | ||||
| 		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed"); | ||||
| @ -253,6 +273,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) | ||||
| 	       CONF_NUMBER_OF_RATE_GROUPS); | ||||
| 	memcpy(radio_parms->tx_rate_limits_degraded, r->tx_rate_limits_degraded, | ||||
| 	       CONF_NUMBER_OF_RATE_GROUPS); | ||||
| 	memcpy(radio_parms->tx_rate_limits_extreme, r->tx_rate_limits_extreme, | ||||
| 	       CONF_NUMBER_OF_RATE_GROUPS); | ||||
| 
 | ||||
| 	memcpy(radio_parms->tx_channel_limits_11b, r->tx_channel_limits_11b, | ||||
| 	       CONF_NUMBER_OF_CHANNELS_2_4); | ||||
| @ -263,6 +285,11 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) | ||||
| 	memcpy(radio_parms->tx_ibias, r->tx_ibias, CONF_NUMBER_OF_RATE_GROUPS); | ||||
| 
 | ||||
| 	radio_parms->rx_fem_insertion_loss = r->rx_fem_insertion_loss; | ||||
| 	radio_parms->degraded_low_to_normal_threshold = | ||||
| 		r->degraded_low_to_normal_threshold; | ||||
| 	radio_parms->degraded_normal_to_high_threshold = | ||||
| 		r->degraded_normal_to_high_threshold; | ||||
| 
 | ||||
| 
 | ||||
| 	for (i = 0; i < CONF_NUMBER_OF_SUB_BANDS_5; i++) | ||||
| 		radio_parms->tx_ref_pd_voltage_5[i] = | ||||
| @ -275,6 +302,8 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) | ||||
| 	       r->tx_rate_limits_normal_5, CONF_NUMBER_OF_RATE_GROUPS); | ||||
| 	memcpy(radio_parms->tx_rate_limits_degraded_5, | ||||
| 	       r->tx_rate_limits_degraded_5, CONF_NUMBER_OF_RATE_GROUPS); | ||||
| 	memcpy(radio_parms->tx_rate_limits_extreme_5, | ||||
| 	       r->tx_rate_limits_extreme_5, CONF_NUMBER_OF_RATE_GROUPS); | ||||
| 	memcpy(radio_parms->tx_channel_limits_ofdm_5, | ||||
| 	       r->tx_channel_limits_ofdm_5, CONF_NUMBER_OF_CHANNELS_5); | ||||
| 	memcpy(radio_parms->tx_pdv_rate_offsets_5, r->tx_pdv_rate_offsets_5, | ||||
| @ -283,6 +312,10 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) | ||||
| 	       CONF_NUMBER_OF_RATE_GROUPS); | ||||
| 	memcpy(radio_parms->rx_fem_insertion_loss_5, | ||||
| 	       r->rx_fem_insertion_loss_5, CONF_NUMBER_OF_SUB_BANDS_5); | ||||
| 	radio_parms->degraded_low_to_normal_threshold_5 = | ||||
| 		r->degraded_low_to_normal_threshold_5; | ||||
| 	radio_parms->degraded_normal_to_high_threshold_5 = | ||||
| 		r->degraded_normal_to_high_threshold_5; | ||||
| 
 | ||||
| 	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", | ||||
| 		    radio_parms, sizeof(*radio_parms)); | ||||
| @ -311,19 +344,6 @@ int wl1271_cmd_join(struct wl1271 *wl) | ||||
| 			do_cal = false; | ||||
| 	} | ||||
| 
 | ||||
| 	/* FIXME: This is a workaround, because with the current stack, we
 | ||||
| 	 * cannot know when we have disassociated.  So, if we have already | ||||
| 	 * joined, we disconnect before joining again. */ | ||||
| 	if (wl->joined) { | ||||
| 		ret = wl1271_cmd_disconnect(wl); | ||||
| 		if (ret < 0) { | ||||
| 			wl1271_error("failed to disconnect before rejoining"); | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		wl->joined = false; | ||||
| 	} | ||||
| 
 | ||||
| 	join = kzalloc(sizeof(*join), GFP_KERNEL); | ||||
| 	if (!join) { | ||||
| 		ret = -ENOMEM; | ||||
| @ -388,8 +408,6 @@ int wl1271_cmd_join(struct wl1271 *wl) | ||||
| 		goto out_free; | ||||
| 	} | ||||
| 
 | ||||
| 	wl->joined = true; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to | ||||
| 	 * simplify locking we just sleep instead, for now | ||||
| @ -487,7 +505,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) | ||||
| int wl1271_cmd_data_path(struct wl1271 *wl, bool enable) | ||||
| { | ||||
| 	struct cmd_enabledisable_path *cmd; | ||||
| 	int ret; | ||||
| @ -501,7 +519,8 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	cmd->channel = channel; | ||||
| 	/* the channel here is only used for calibration, so hardcoded to 1 */ | ||||
| 	cmd->channel = 1; | ||||
| 
 | ||||
| 	if (enable) { | ||||
| 		cmd_rx = CMD_ENABLE_RX; | ||||
| @ -514,22 +533,22 @@ int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) | ||||
| 	ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0); | ||||
| 	if (ret < 0) { | ||||
| 		wl1271_error("rx %s cmd for channel %d failed", | ||||
| 			     enable ? "start" : "stop", channel); | ||||
| 			     enable ? "start" : "stop", cmd->channel); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", | ||||
| 		     enable ? "start" : "stop", channel); | ||||
| 		     enable ? "start" : "stop", cmd->channel); | ||||
| 
 | ||||
| 	ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0); | ||||
| 	if (ret < 0) { | ||||
| 		wl1271_error("tx %s cmd for channel %d failed", | ||||
| 			     enable ? "start" : "stop", channel); | ||||
| 			     enable ? "start" : "stop", cmd->channel); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", | ||||
| 		     enable ? "start" : "stop", channel); | ||||
| 		     enable ? "start" : "stop", cmd->channel); | ||||
| 
 | ||||
| out: | ||||
| 	kfree(cmd); | ||||
| @ -636,7 +655,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | ||||
| 	channels = wl->hw->wiphy->bands[ieee_band]->channels; | ||||
| 	n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; | ||||
| 
 | ||||
| 	if (wl->scanning) | ||||
| 	if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	params = kzalloc(sizeof(*params), GFP_KERNEL); | ||||
| @ -711,7 +730,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | ||||
| 
 | ||||
| 	wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); | ||||
| 
 | ||||
| 	wl->scanning = true; | ||||
| 	set_bit(WL1271_FLAG_SCANNING, &wl->flags); | ||||
| 	if (wl1271_11a_enabled()) { | ||||
| 		wl->scan.state = band; | ||||
| 		if (band == WL1271_SCAN_BAND_DUAL) { | ||||
| @ -729,7 +748,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, | ||||
| 	ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0); | ||||
| 	if (ret < 0) { | ||||
| 		wl1271_error("SCAN failed"); | ||||
| 		wl->scanning = false; | ||||
| 		clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| @ -777,7 +796,7 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int wl1271_build_basic_rates(char *rates, u8 band) | ||||
| static int wl1271_build_basic_rates(u8 *rates, u8 band) | ||||
| { | ||||
| 	u8 index = 0; | ||||
| 
 | ||||
| @ -804,7 +823,7 @@ static int wl1271_build_basic_rates(char *rates, u8 band) | ||||
| 	return index; | ||||
| } | ||||
| 
 | ||||
| static int wl1271_build_extended_rates(char *rates, u8 band) | ||||
| static int wl1271_build_extended_rates(u8 *rates, u8 band) | ||||
| { | ||||
| 	u8 index = 0; | ||||
| 
 | ||||
|  | ||||
| @ -37,7 +37,7 @@ int wl1271_cmd_join(struct wl1271 *wl); | ||||
| int wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer); | ||||
| int wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len); | ||||
| int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len); | ||||
| int wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable); | ||||
| int wl1271_cmd_data_path(struct wl1271 *wl, bool enable); | ||||
| int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode); | ||||
| int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, | ||||
| 			   size_t len); | ||||
| @ -437,6 +437,21 @@ struct wl1271_general_parms_cmd { | ||||
| 	u8 tx_bip_fem_autodetect; | ||||
| 	u8 tx_bip_fem_manufacturer; | ||||
| 	u8 settings; | ||||
| 
 | ||||
| 	u8 sr_state; | ||||
| 
 | ||||
| 	s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS]; | ||||
| 	s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS]; | ||||
| 	s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS]; | ||||
| 
 | ||||
| 	s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS]; | ||||
| 
 | ||||
| 	u8 sr_sen_n_p; | ||||
| 	u8 sr_sen_n_p_gain; | ||||
| 	u8 sr_sen_nrn; | ||||
| 	u8 sr_sen_prn; | ||||
| 
 | ||||
| 	u8 padding[3]; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| struct wl1271_radio_parms_cmd { | ||||
| @ -458,11 +473,12 @@ struct wl1271_radio_parms_cmd { | ||||
| 	/* Dynamic radio parameters */ | ||||
| 	/* 2.4GHz */ | ||||
| 	__le16 tx_ref_pd_voltage; | ||||
| 	s8  tx_ref_power; | ||||
| 	u8  tx_ref_power; | ||||
| 	s8  tx_offset_db; | ||||
| 
 | ||||
| 	s8  tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 
 | ||||
| 	s8  tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; | ||||
| 	s8  tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; | ||||
| @ -471,15 +487,19 @@ struct wl1271_radio_parms_cmd { | ||||
| 	u8  tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	u8  rx_fem_insertion_loss; | ||||
| 
 | ||||
| 	u8 padding2; | ||||
| 	u8  degraded_low_to_normal_threshold; | ||||
| 	u8  degraded_normal_to_high_threshold; | ||||
| 
 | ||||
| 	u8  padding1; /* our own padding, not in ref driver */ | ||||
| 
 | ||||
| 	/* 5GHz */ | ||||
| 	__le16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 	s8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 	u8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 	s8  tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 
 | ||||
| 	s8  tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 
 | ||||
| 	s8  tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; | ||||
| 	s8  tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| @ -488,7 +508,10 @@ struct wl1271_radio_parms_cmd { | ||||
| 	s8  tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 
 | ||||
| 	u8 padding3[2]; | ||||
| 	u8  degraded_low_to_normal_threshold_5; | ||||
| 	u8  degraded_normal_to_high_threshold_5; | ||||
| 
 | ||||
| 	u8 padding2[2]; | ||||
| } __attribute__ ((packed)); | ||||
| 
 | ||||
| struct wl1271_cmd_cal_channel_tune { | ||||
|  | ||||
| @ -258,7 +258,8 @@ struct conf_rx_settings { | ||||
| #define CONF_TX_MAX_RATE_CLASSES       8 | ||||
| 
 | ||||
| #define CONF_TX_RATE_MASK_UNSPECIFIED  0 | ||||
| #define CONF_TX_RATE_MASK_ALL          0x1eff | ||||
| #define CONF_TX_RATE_MASK_BASIC        (CONF_HW_BIT_RATE_1MBPS | \ | ||||
| 					CONF_HW_BIT_RATE_2MBPS) | ||||
| #define CONF_TX_RATE_RETRY_LIMIT       10 | ||||
| 
 | ||||
| struct conf_tx_rate_class { | ||||
| @ -722,31 +723,6 @@ struct conf_conn_settings { | ||||
| 	u8 psm_entry_retries; | ||||
| }; | ||||
| 
 | ||||
| #define CONF_SR_ERR_TBL_MAX_VALUES   14 | ||||
| 
 | ||||
| struct conf_mart_reflex_err_table { | ||||
| 	/*
 | ||||
| 	 * Length of the error table values table. | ||||
| 	 * | ||||
| 	 * Range: 0 - CONF_SR_ERR_TBL_MAX_VALUES | ||||
| 	 */ | ||||
| 	u8 len; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Smart Reflex error table upper limit. | ||||
| 	 * | ||||
| 	 * Range: s8 | ||||
| 	 */ | ||||
| 	s8 upper_limit; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Smart Reflex error table values. | ||||
| 	 * | ||||
| 	 * Range: s8 | ||||
| 	 */ | ||||
| 	s8 values[CONF_SR_ERR_TBL_MAX_VALUES]; | ||||
| }; | ||||
| 
 | ||||
| enum { | ||||
| 	CONF_REF_CLK_19_2_E, | ||||
| 	CONF_REF_CLK_26_E, | ||||
| @ -759,6 +735,9 @@ enum single_dual_band_enum { | ||||
| 	CONF_DUAL_BAND | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| #define CONF_MAX_SMART_REFLEX_PARAMS 16 | ||||
| 
 | ||||
| struct conf_general_parms { | ||||
| 	/*
 | ||||
| 	 * RF Reference Clock type / speed | ||||
| @ -815,6 +794,20 @@ struct conf_general_parms { | ||||
| 	 * Range: Unknown | ||||
| 	 */ | ||||
| 	u8 settings; | ||||
| 
 | ||||
| 	/* Smart reflex settings */ | ||||
| 	u8 sr_state; | ||||
| 
 | ||||
| 	s8 srf1[CONF_MAX_SMART_REFLEX_PARAMS]; | ||||
| 	s8 srf2[CONF_MAX_SMART_REFLEX_PARAMS]; | ||||
| 	s8 srf3[CONF_MAX_SMART_REFLEX_PARAMS]; | ||||
| 
 | ||||
| 	s8 sr_debug_table[CONF_MAX_SMART_REFLEX_PARAMS]; | ||||
| 
 | ||||
| 	u8 sr_sen_n_p; | ||||
| 	u8 sr_sen_n_p_gain; | ||||
| 	u8 sr_sen_nrn; | ||||
| 	u8 sr_sen_prn; | ||||
| }; | ||||
| 
 | ||||
| #define CONF_RSSI_AND_PROCESS_COMPENSATION_SIZE 15 | ||||
| @ -847,12 +840,13 @@ struct conf_radio_parms { | ||||
| 	 * | ||||
| 	 * Range: unknown | ||||
| 	 */ | ||||
| 	s16 tx_ref_pd_voltage; | ||||
| 	s8  tx_ref_power; | ||||
| 	u16 tx_ref_pd_voltage; | ||||
| 	u8  tx_ref_power; | ||||
| 	s8  tx_offset_db; | ||||
| 
 | ||||
| 	s8  tx_rate_limits_normal[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  tx_rate_limits_degraded[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  tx_rate_limits_extreme[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 
 | ||||
| 	s8  tx_channel_limits_11b[CONF_NUMBER_OF_CHANNELS_2_4]; | ||||
| 	s8  tx_channel_limits_ofdm[CONF_NUMBER_OF_CHANNELS_2_4]; | ||||
| @ -861,17 +855,22 @@ struct conf_radio_parms { | ||||
| 	u8  tx_ibias[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	u8  rx_fem_insertion_loss; | ||||
| 
 | ||||
| 	u8  degraded_low_to_normal_threshold; | ||||
| 	u8  degraded_normal_to_high_threshold; | ||||
| 
 | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Dynamic radio parameters for 5GHz | ||||
| 	 * | ||||
| 	 * Range: unknown | ||||
| 	 */ | ||||
| 	s16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 	s8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 	u16 tx_ref_pd_voltage_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 	u8  tx_ref_power_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 	s8  tx_offset_db_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 
 | ||||
| 	s8  tx_rate_limits_normal_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  tx_rate_limits_degraded_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  tx_rate_limits_extreme_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 
 | ||||
| 	s8  tx_channel_limits_ofdm_5[CONF_NUMBER_OF_CHANNELS_5]; | ||||
| 	s8  tx_pdv_rate_offsets_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| @ -879,23 +878,12 @@ struct conf_radio_parms { | ||||
| 	/* FIXME: this is inconsistent with the types for 2.4GHz */ | ||||
| 	s8  tx_ibias_5[CONF_NUMBER_OF_RATE_GROUPS]; | ||||
| 	s8  rx_fem_insertion_loss_5[CONF_NUMBER_OF_SUB_BANDS_5]; | ||||
| 
 | ||||
| 	u8  degraded_low_to_normal_threshold_5; | ||||
| 	u8  degraded_normal_to_high_threshold_5; | ||||
| }; | ||||
| 
 | ||||
| #define CONF_SR_ERR_TBL_COUNT        3 | ||||
| 
 | ||||
| struct conf_init_settings { | ||||
| 	/*
 | ||||
| 	 * Configure Smart Reflex error table values. | ||||
| 	 */ | ||||
| 	struct conf_mart_reflex_err_table sr_err_tbl[CONF_SR_ERR_TBL_COUNT]; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Smart Reflex enable flag. | ||||
| 	 * | ||||
| 	 * Range: 1 - Smart Reflex enabled, 0 - Smart Reflex disabled | ||||
| 	 */ | ||||
| 	u8 sr_enable; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Configure general parameters. | ||||
| 	 */ | ||||
| @ -908,12 +896,38 @@ struct conf_init_settings { | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| struct conf_itrim_settings { | ||||
| 	/* enable dco itrim */ | ||||
| 	u8 enable; | ||||
| 
 | ||||
| 	/* moderation timeout in microsecs from the last TX */ | ||||
| 	u32 timeout; | ||||
| }; | ||||
| 
 | ||||
| struct conf_pm_config_settings { | ||||
| 	/*
 | ||||
| 	 * Host clock settling time | ||||
| 	 * | ||||
| 	 * Range: 0 - 30000 us | ||||
| 	 */ | ||||
| 	u32 host_clk_settling_time; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Host fast wakeup support | ||||
| 	 * | ||||
| 	 * Range: true, false | ||||
| 	 */ | ||||
| 	bool host_fast_wakeup_support; | ||||
| }; | ||||
| 
 | ||||
| struct conf_drv_settings { | ||||
| 	struct conf_sg_settings sg; | ||||
| 	struct conf_rx_settings rx; | ||||
| 	struct conf_tx_settings tx; | ||||
| 	struct conf_conn_settings conn; | ||||
| 	struct conf_init_settings init; | ||||
| 	struct conf_itrim_settings itrim; | ||||
| 	struct conf_pm_config_settings pm_config; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -237,6 +237,64 @@ static const struct file_operations tx_queue_len_ops = { | ||||
| 	.open = wl1271_open_file_generic, | ||||
| }; | ||||
| 
 | ||||
| static ssize_t gpio_power_read(struct file *file, char __user *user_buf, | ||||
| 			  size_t count, loff_t *ppos) | ||||
| { | ||||
| 	struct wl1271 *wl = file->private_data; | ||||
| 	bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||||
| 
 | ||||
| 	int res; | ||||
| 	char buf[10]; | ||||
| 
 | ||||
| 	res = scnprintf(buf, sizeof(buf), "%d\n", state); | ||||
| 
 | ||||
| 	return simple_read_from_buffer(user_buf, count, ppos, buf, res); | ||||
| } | ||||
| 
 | ||||
| static ssize_t gpio_power_write(struct file *file, | ||||
| 			   const char __user *user_buf, | ||||
| 			   size_t count, loff_t *ppos) | ||||
| { | ||||
| 	struct wl1271 *wl = file->private_data; | ||||
| 	char buf[10]; | ||||
| 	size_t len; | ||||
| 	unsigned long value; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 
 | ||||
| 	len = min(count, sizeof(buf) - 1); | ||||
| 	if (copy_from_user(buf, user_buf, len)) { | ||||
| 		ret = -EFAULT; | ||||
| 		goto out; | ||||
| 	} | ||||
| 	buf[len] = '\0'; | ||||
| 
 | ||||
| 	ret = strict_strtoul(buf, 0, &value); | ||||
| 	if (ret < 0) { | ||||
| 		wl1271_warning("illegal value in gpio_power"); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (value) { | ||||
| 		wl->set_power(true); | ||||
| 		set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||||
| 	} else { | ||||
| 		wl->set_power(false); | ||||
| 		clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	mutex_unlock(&wl->mutex); | ||||
| 	return count; | ||||
| } | ||||
| 
 | ||||
| static const struct file_operations gpio_power_ops = { | ||||
| 	.read = gpio_power_read, | ||||
| 	.write = gpio_power_write, | ||||
| 	.open = wl1271_open_file_generic | ||||
| }; | ||||
| 
 | ||||
| static void wl1271_debugfs_delete_files(struct wl1271 *wl) | ||||
| { | ||||
| 	DEBUGFS_FWSTATS_DEL(tx, internal_desc_overflow); | ||||
| @ -333,6 +391,8 @@ static void wl1271_debugfs_delete_files(struct wl1271 *wl) | ||||
| 	DEBUGFS_DEL(tx_queue_len); | ||||
| 	DEBUGFS_DEL(retry_count); | ||||
| 	DEBUGFS_DEL(excessive_retries); | ||||
| 
 | ||||
| 	DEBUGFS_DEL(gpio_power); | ||||
| } | ||||
| 
 | ||||
| static int wl1271_debugfs_add_files(struct wl1271 *wl) | ||||
| @ -434,6 +494,8 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl) | ||||
| 	DEBUGFS_ADD(retry_count, wl->debugfs.rootdir); | ||||
| 	DEBUGFS_ADD(excessive_retries, wl->debugfs.rootdir); | ||||
| 
 | ||||
| 	DEBUGFS_ADD(gpio_power, wl->debugfs.rootdir); | ||||
| 
 | ||||
| out: | ||||
| 	if (ret < 0) | ||||
| 		wl1271_debugfs_delete_files(wl); | ||||
|  | ||||
| @ -35,7 +35,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, | ||||
| 	wl1271_debug(DEBUG_EVENT, "status: 0x%x", | ||||
| 		     mbox->scheduled_scan_status); | ||||
| 
 | ||||
| 	if (wl->scanning) { | ||||
| 	if (test_bit(WL1271_FLAG_SCANNING, &wl->flags)) { | ||||
| 		if (wl->scan.state == WL1271_SCAN_BAND_DUAL) { | ||||
| 			wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, | ||||
| 						NULL, size); | ||||
| @ -43,7 +43,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, | ||||
| 			 * to the wl1271_cmd_scan function that we are not | ||||
| 			 * scanning as it checks that. | ||||
| 			 */ | ||||
| 			wl->scanning = false; | ||||
| 			clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | ||||
| 			wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len, | ||||
| 						wl->scan.active, | ||||
| 						wl->scan.high_prio, | ||||
| @ -62,7 +62,7 @@ static int wl1271_event_scan_complete(struct wl1271 *wl, | ||||
| 			mutex_unlock(&wl->mutex); | ||||
| 			ieee80211_scan_completed(wl->hw, false); | ||||
| 			mutex_lock(&wl->mutex); | ||||
| 			wl->scanning = false; | ||||
| 			clear_bit(WL1271_FLAG_SCANNING, &wl->flags); | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| @ -78,7 +78,7 @@ static int wl1271_event_ps_report(struct wl1271 *wl, | ||||
| 
 | ||||
| 	switch (mbox->ps_status) { | ||||
| 	case EVENT_ENTER_POWER_SAVE_FAIL: | ||||
| 		if (!wl->psm) { | ||||
| 		if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) { | ||||
| 			wl->psm_entry_retry = 0; | ||||
| 			break; | ||||
| 		} | ||||
| @ -89,7 +89,6 @@ static int wl1271_event_ps_report(struct wl1271 *wl, | ||||
| 		} else { | ||||
| 			wl1271_error("PSM entry failed, giving up.\n"); | ||||
| 			wl->psm_entry_retry = 0; | ||||
| 			*beacon_loss = true; | ||||
| 		} | ||||
| 		break; | ||||
| 	case EVENT_ENTER_POWER_SAVE_SUCCESS: | ||||
| @ -136,7 +135,8 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | ||||
| 	 * filtering) is enabled. Without PSM, the stack will receive all | ||||
| 	 * beacons and can detect beacon loss by itself. | ||||
| 	 */ | ||||
| 	if (vector & BSS_LOSE_EVENT_ID && wl->psm) { | ||||
| 	if (vector & BSS_LOSE_EVENT_ID && | ||||
| 	    test_bit(WL1271_FLAG_PSM, &wl->flags)) { | ||||
| 		wl1271_debug(DEBUG_EVENT, "BSS_LOSE_EVENT"); | ||||
| 
 | ||||
| 		/* indicate to the stack, that beacons have been lost */ | ||||
| @ -150,7 +150,7 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	if (beacon_loss) { | ||||
| 	if (wl->vif && beacon_loss) { | ||||
| 		/* Obviously, it's dangerous to release the mutex while
 | ||||
| 		   we are holding many of the variables in the wl struct. | ||||
| 		   That's why it's done last in the function, and care must | ||||
| @ -184,7 +184,7 @@ void wl1271_event_mbox_config(struct wl1271 *wl) | ||||
| 		     wl->mbox_ptr[0], wl->mbox_ptr[1]); | ||||
| } | ||||
| 
 | ||||
| int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack) | ||||
| int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) | ||||
| { | ||||
| 	struct event_mailbox mbox; | ||||
| 	int ret; | ||||
| @ -204,9 +204,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num, bool do_ack) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	/* then we let the firmware know it can go on...*/ | ||||
| 	if (do_ack) | ||||
| 		wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, | ||||
| 				   INTR_TRIG_EVENT_ACK); | ||||
| 	wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_EVENT_ACK); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -112,6 +112,6 @@ struct event_mailbox { | ||||
| 
 | ||||
| int wl1271_event_unmask(struct wl1271 *wl); | ||||
| void wl1271_event_mbox_config(struct wl1271 *wl); | ||||
| int wl1271_event_handle(struct wl1271 *wl, u8 mbox, bool do_ack); | ||||
| int wl1271_event_handle(struct wl1271 *wl, u8 mbox); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -229,6 +229,10 @@ int wl1271_hw_init(struct wl1271 *wl) | ||||
| 	if (ret < 0) | ||||
| 		goto out_free_memmap; | ||||
| 
 | ||||
| 	ret = wl1271_acx_dco_itrim_params(wl); | ||||
| 	if (ret < 0) | ||||
| 		goto out_free_memmap; | ||||
| 
 | ||||
| 	/* Initialize connection monitoring thresholds */ | ||||
| 	ret = wl1271_acx_conn_monit_params(wl); | ||||
| 	if (ret < 0) | ||||
| @ -280,12 +284,12 @@ int wl1271_hw_init(struct wl1271 *wl) | ||||
| 		goto out_free_memmap; | ||||
| 
 | ||||
| 	/* Configure TX rate classes */ | ||||
| 	ret = wl1271_acx_rate_policies(wl, CONF_TX_RATE_MASK_ALL); | ||||
| 	ret = wl1271_acx_rate_policies(wl); | ||||
| 	if (ret < 0) | ||||
| 		goto out_free_memmap; | ||||
| 
 | ||||
| 	/* Enable data path */ | ||||
| 	ret = wl1271_cmd_data_path(wl, wl->channel, 1); | ||||
| 	ret = wl1271_cmd_data_path(wl, 1); | ||||
| 	if (ret < 0) | ||||
| 		goto out_free_memmap; | ||||
| 
 | ||||
| @ -299,8 +303,8 @@ int wl1271_hw_init(struct wl1271 *wl) | ||||
| 	if (ret < 0) | ||||
| 		goto out_free_memmap; | ||||
| 
 | ||||
| 	/* Configure smart reflex */ | ||||
| 	ret = wl1271_acx_smart_reflex(wl); | ||||
| 	/* configure PM */ | ||||
| 	ret = wl1271_acx_pm_config(wl); | ||||
| 	if (ret < 0) | ||||
| 		goto out_free_memmap; | ||||
| 
 | ||||
|  | ||||
| @ -47,6 +47,8 @@ | ||||
| #include "wl1271_cmd.h" | ||||
| #include "wl1271_boot.h" | ||||
| 
 | ||||
| #define WL1271_BOOT_RETRIES 3 | ||||
| 
 | ||||
| static struct conf_drv_settings default_conf = { | ||||
| 	.sg = { | ||||
| 		.per_threshold               = 7500, | ||||
| @ -67,16 +69,17 @@ static struct conf_drv_settings default_conf = { | ||||
| 		.ps_poll_timeout             = 15, | ||||
| 		.upsd_timeout                = 15, | ||||
| 		.rts_threshold               = 2347, | ||||
| 		.rx_cca_threshold            = 0xFFEF, | ||||
| 		.irq_blk_threshold           = 0, | ||||
| 		.irq_pkt_threshold           = USHORT_MAX, | ||||
| 		.irq_timeout                 = 5, | ||||
| 		.rx_cca_threshold            = 0, | ||||
| 		.irq_blk_threshold           = 0xFFFF, | ||||
| 		.irq_pkt_threshold           = 0, | ||||
| 		.irq_timeout                 = 600, | ||||
| 		.queue_type                  = CONF_RX_QUEUE_TYPE_LOW_PRIORITY, | ||||
| 	}, | ||||
| 	.tx = { | ||||
| 		.tx_energy_detection         = 0, | ||||
| 		.rc_conf                     = { | ||||
| 			.enabled_rates       = CONF_TX_RATE_MASK_UNSPECIFIED, | ||||
| 			.enabled_rates       = CONF_HW_BIT_RATE_1MBPS | | ||||
| 					       CONF_HW_BIT_RATE_2MBPS, | ||||
| 			.short_retry_limit   = 10, | ||||
| 			.long_retry_limit    = 10, | ||||
| 			.aflags              = 0 | ||||
| @ -172,8 +175,8 @@ static struct conf_drv_settings default_conf = { | ||||
| 			} | ||||
| 		}, | ||||
| 		.frag_threshold              = IEEE80211_MAX_FRAG_THRESHOLD, | ||||
| 		.tx_compl_timeout            = 5, | ||||
| 		.tx_compl_threshold          = 5 | ||||
| 		.tx_compl_timeout            = 700, | ||||
| 		.tx_compl_threshold          = 4 | ||||
| 	}, | ||||
| 	.conn = { | ||||
| 		.wake_up_event               = CONF_WAKE_UP_EVENT_DTIM, | ||||
| @ -186,12 +189,12 @@ static struct conf_drv_settings default_conf = { | ||||
| 				.rule        = CONF_BCN_RULE_PASS_ON_APPEARANCE, | ||||
| 			} | ||||
| 		}, | ||||
| 		.synch_fail_thold            = 5, | ||||
| 		.synch_fail_thold            = 10, | ||||
| 		.bss_lose_timeout            = 100, | ||||
| 		.beacon_rx_timeout           = 10000, | ||||
| 		.broadcast_timeout           = 20000, | ||||
| 		.rx_broadcast_in_ps          = 1, | ||||
| 		.ps_poll_threshold           = 4, | ||||
| 		.ps_poll_threshold           = 20, | ||||
| 		.sig_trigger_count           = 2, | ||||
| 		.sig_trigger = { | ||||
| 			[0] = { | ||||
| @ -226,46 +229,35 @@ static struct conf_drv_settings default_conf = { | ||||
| 		.psm_entry_retries           = 3 | ||||
| 	}, | ||||
| 	.init = { | ||||
| 		.sr_err_tbl = { | ||||
| 			[0] = { | ||||
| 				.len         = 7, | ||||
| 				.upper_limit = 0x03, | ||||
| 				.values      = { | ||||
| 					0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8, | ||||
| 					0x00 } | ||||
| 			}, | ||||
| 			[1] = { | ||||
| 				.len         = 7, | ||||
| 				.upper_limit = 0x03, | ||||
| 				.values      = { | ||||
| 					0x18, 0x10, 0x05, 0xf6, 0xf0, 0xe8, | ||||
| 					0x00 } | ||||
| 			}, | ||||
| 			[2] = { | ||||
| 				.len         = 7, | ||||
| 				.upper_limit = 0x03, | ||||
| 				.values      = { | ||||
| 					0x18, 0x10, 0x05, 0xfb, 0xf0, 0xe8, | ||||
| 					0x00 } | ||||
| 			} | ||||
| 		}, | ||||
| 		.sr_enable                   = 1, | ||||
| 		.genparam                    = { | ||||
| 			.ref_clk             = CONF_REF_CLK_38_4_E, | ||||
| 			.settling_time       = 5, | ||||
| 			.clk_valid_on_wakeup = 0, | ||||
| 			.dc2dcmode           = 0, | ||||
| 			.single_dual_band    = CONF_SINGLE_BAND, | ||||
| 			.tx_bip_fem_autodetect = 0, | ||||
| 			.tx_bip_fem_autodetect = 1, | ||||
| 			.tx_bip_fem_manufacturer = 1, | ||||
| 			.settings = 1, | ||||
| 			.sr_state = 1, | ||||
| 			.srf1 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, | ||||
| 				  0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||||
| 			.srf2 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, | ||||
| 				  0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||||
| 			.srf3 = { 0x07, 0x03, 0x18, 0x10, 0x05, 0xfb, 0xf0, | ||||
| 				  0xe8, 0, 0, 0, 0, 0, 0, 0, 0 }, | ||||
| 			.sr_debug_table = { 0, 0, 0, 0, 0, 0, 0, 0, | ||||
| 					    0, 0, 0, 0, 0, 0, 0, 0 }, | ||||
| 			.sr_sen_n_p = 0, | ||||
| 			.sr_sen_n_p_gain = 0, | ||||
| 			.sr_sen_nrn = 0, | ||||
| 			.sr_sen_prn = 0, | ||||
| 		}, | ||||
| 		.radioparam = { | ||||
| 			.rx_trace_loss       = 10, | ||||
| 			.tx_trace_loss       = 10, | ||||
| 			.rx_trace_loss       = 0x24, | ||||
| 			.tx_trace_loss       = 0x0, | ||||
| 			.rx_rssi_and_proc_compens = { | ||||
| 				0xec, 0xf6, 0x00, 0x0c, 0x18, 0xf8, | ||||
| 				0xfc, 0x00, 0x08, 0x10, 0xf0, 0xf8, | ||||
| 				0xfc, 0x00, 0x80, 0x10, 0xf0, 0xf8, | ||||
| 				0x00, 0x0a, 0x14 }, | ||||
| 			.rx_trace_loss_5     = { 0, 0, 0, 0, 0, 0, 0 }, | ||||
| 			.tx_trace_loss_5     = { 0, 0, 0, 0, 0, 0, 0 }, | ||||
| @ -273,13 +265,15 @@ static struct conf_drv_settings default_conf = { | ||||
| 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
| 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | ||||
| 				0x00, 0x00, 0x00 }, | ||||
| 			.tx_ref_pd_voltage   = 0x24e, | ||||
| 			.tx_ref_power        = 0x78, | ||||
| 			.tx_ref_pd_voltage   = 0x1a9, | ||||
| 			.tx_ref_power        = 0x80, | ||||
| 			.tx_offset_db        = 0x0, | ||||
| 			.tx_rate_limits_normal = { | ||||
| 				0x1e, 0x1f, 0x22, 0x24, 0x28, 0x29 }, | ||||
| 				0x1d, 0x1f, 0x24, 0x28, 0x28, 0x29 }, | ||||
| 			.tx_rate_limits_degraded = { | ||||
| 				0x1b, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, | ||||
| 				0x19, 0x1f, 0x22, 0x23, 0x27, 0x28 }, | ||||
| 			.tx_rate_limits_extreme = { | ||||
| 				0x19, 0x1c, 0x1e, 0x20, 0x24, 0x25 }, | ||||
| 			.tx_channel_limits_11b = { | ||||
| 				0x22, 0x50, 0x50, 0x50, 0x50, 0x50, | ||||
| 				0x50, 0x50, 0x50, 0x50, 0x22, 0x50, | ||||
| @ -289,10 +283,12 @@ static struct conf_drv_settings default_conf = { | ||||
| 				0x50, 0x50, 0x50, 0x50, 0x20, 0x50, | ||||
| 				0x20, 0x50 }, | ||||
| 			.tx_pdv_rate_offsets = { | ||||
| 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, | ||||
| 				0x07, 0x08, 0x04, 0x02, 0x02, 0x00 }, | ||||
| 			.tx_ibias            = { | ||||
| 				0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x27 }, | ||||
| 			.rx_fem_insertion_loss = 0x14, | ||||
| 				0x11, 0x11, 0x15, 0x11, 0x15, 0x0f }, | ||||
| 			.rx_fem_insertion_loss = 0x0e, | ||||
| 			.degraded_low_to_normal_threshold = 0x1e, | ||||
| 			.degraded_normal_to_high_threshold = 0x2d, | ||||
| 			.tx_ref_pd_voltage_5 = { | ||||
| 				0x0190, 0x01a4, 0x01c3, 0x01d8, | ||||
| 				0x020a, 0x021c }, | ||||
| @ -304,6 +300,8 @@ static struct conf_drv_settings default_conf = { | ||||
| 				0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, | ||||
| 			.tx_rate_limits_degraded_5 = { | ||||
| 				0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, | ||||
| 			.tx_rate_limits_extreme_5 = { | ||||
| 				0x1b, 0x1e, 0x21, 0x23, 0x27, 0x00 }, | ||||
| 			.tx_channel_limits_ofdm_5 = { | ||||
| 				0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, | ||||
| 				0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, | ||||
| @ -315,8 +313,18 @@ static struct conf_drv_settings default_conf = { | ||||
| 			.tx_ibias_5          = { | ||||
| 				0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, | ||||
| 			.rx_fem_insertion_loss_5 = { | ||||
| 				0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 } | ||||
| 				0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, | ||||
| 			.degraded_low_to_normal_threshold_5 = 0x00, | ||||
| 			.degraded_normal_to_high_threshold_5 = 0x00 | ||||
| 		} | ||||
| 	}, | ||||
| 	.itrim = { | ||||
| 		.enable = false, | ||||
| 		.timeout = 50000, | ||||
| 	}, | ||||
| 	.pm_config = { | ||||
| 		.host_clk_settling_time = 5000, | ||||
| 		.host_fast_wakeup_support = false | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| @ -359,7 +367,7 @@ static int wl1271_plt_init(struct wl1271 *wl) | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| 	ret = wl1271_cmd_data_path(wl, wl->channel, 1); | ||||
| 	ret = wl1271_cmd_data_path(wl, 1); | ||||
| 	if (ret < 0) | ||||
| 		return ret; | ||||
| 
 | ||||
| @ -374,11 +382,13 @@ static void wl1271_disable_interrupts(struct wl1271 *wl) | ||||
| static void wl1271_power_off(struct wl1271 *wl) | ||||
| { | ||||
| 	wl->set_power(false); | ||||
| 	clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||||
| } | ||||
| 
 | ||||
| static void wl1271_power_on(struct wl1271 *wl) | ||||
| { | ||||
| 	wl->set_power(true); | ||||
| 	set_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); | ||||
| } | ||||
| 
 | ||||
| static void wl1271_fw_status(struct wl1271 *wl, | ||||
| @ -447,14 +457,13 @@ static void wl1271_irq_work(struct work_struct *work) | ||||
| 	intr &= WL1271_INTR_MASK; | ||||
| 
 | ||||
| 	if (intr & WL1271_ACX_INTR_EVENT_A) { | ||||
| 		bool do_ack = (intr & WL1271_ACX_INTR_EVENT_B) ? false : true; | ||||
| 		wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); | ||||
| 		wl1271_event_handle(wl, 0, do_ack); | ||||
| 		wl1271_event_handle(wl, 0); | ||||
| 	} | ||||
| 
 | ||||
| 	if (intr & WL1271_ACX_INTR_EVENT_B) { | ||||
| 		wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); | ||||
| 		wl1271_event_handle(wl, 1, true); | ||||
| 		wl1271_event_handle(wl, 1); | ||||
| 	} | ||||
| 
 | ||||
| 	if (intr & WL1271_ACX_INTR_INIT_COMPLETE) | ||||
| @ -614,6 +623,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) | ||||
| 	struct wl1271_partition_set partition; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	msleep(WL1271_PRE_POWER_ON_SLEEP); | ||||
| 	wl1271_power_on(wl); | ||||
| 	msleep(WL1271_POWER_ON_SLEEP); | ||||
| 	wl1271_spi_reset(wl); | ||||
| @ -643,7 +653,7 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) | ||||
| 
 | ||||
| 		ret = wl1271_setup(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto out_power_off; | ||||
| 			goto out; | ||||
| 		break; | ||||
| 	case CHIP_ID_1271_PG20: | ||||
| 		wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)", | ||||
| @ -651,38 +661,34 @@ static int wl1271_chip_wakeup(struct wl1271 *wl) | ||||
| 
 | ||||
| 		ret = wl1271_setup(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto out_power_off; | ||||
| 			goto out; | ||||
| 		break; | ||||
| 	default: | ||||
| 		wl1271_error("unsupported chip id: 0x%x", wl->chip.id); | ||||
| 		wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); | ||||
| 		ret = -ENODEV; | ||||
| 		goto out_power_off; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (wl->fw == NULL) { | ||||
| 		ret = wl1271_fetch_firmware(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto out_power_off; | ||||
| 			goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	/* No NVS from netlink, try to get it from the filesystem */ | ||||
| 	if (wl->nvs == NULL) { | ||||
| 		ret = wl1271_fetch_nvs(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto out_power_off; | ||||
| 			goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	goto out; | ||||
| 
 | ||||
| out_power_off: | ||||
| 	wl1271_power_off(wl); | ||||
| 
 | ||||
| out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| int wl1271_plt_start(struct wl1271 *wl) | ||||
| { | ||||
| 	int retries = WL1271_BOOT_RETRIES; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| @ -696,35 +702,48 @@ int wl1271_plt_start(struct wl1271 *wl) | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	wl->state = WL1271_STATE_PLT; | ||||
| 	while (retries) { | ||||
| 		retries--; | ||||
| 		ret = wl1271_chip_wakeup(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto power_off; | ||||
| 
 | ||||
| 	ret = wl1271_chip_wakeup(wl); | ||||
| 	if (ret < 0) | ||||
| 		ret = wl1271_boot(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto power_off; | ||||
| 
 | ||||
| 		ret = wl1271_plt_init(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto irq_disable; | ||||
| 
 | ||||
| 		/* Make sure power saving is disabled */ | ||||
| 		ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||||
| 		if (ret < 0) | ||||
| 			goto irq_disable; | ||||
| 
 | ||||
| 		wl->state = WL1271_STATE_PLT; | ||||
| 		wl1271_notice("firmware booted in PLT mode (%s)", | ||||
| 			      wl->chip.fw_ver); | ||||
| 		goto out; | ||||
| 
 | ||||
| 	ret = wl1271_boot(wl); | ||||
| 	if (ret < 0) | ||||
| 		goto out_power_off; | ||||
| 
 | ||||
| 	wl1271_notice("firmware booted in PLT mode (%s)", wl->chip.fw_ver); | ||||
| 
 | ||||
| 	ret = wl1271_plt_init(wl); | ||||
| 	if (ret < 0) | ||||
| 		goto out_irq_disable; | ||||
| 
 | ||||
| 	/* Make sure power saving is disabled */ | ||||
| 	ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||||
| 	if (ret < 0) | ||||
| 		goto out_irq_disable; | ||||
| 
 | ||||
| 	goto out; | ||||
| 
 | ||||
| out_irq_disable: | ||||
| 	wl1271_disable_interrupts(wl); | ||||
| 
 | ||||
| out_power_off: | ||||
| 	wl1271_power_off(wl); | ||||
| irq_disable: | ||||
| 		wl1271_disable_interrupts(wl); | ||||
| 		mutex_unlock(&wl->mutex); | ||||
| 		/* Unlocking the mutex in the middle of handling is
 | ||||
| 		   inherently unsafe. In this case we deem it safe to do, | ||||
| 		   because we need to let any possibly pending IRQ out of | ||||
| 		   the system (and while we are WL1271_STATE_OFF the IRQ | ||||
| 		   work function will not do anything.) Also, any other | ||||
| 		   possible concurrent operations will fail due to the | ||||
| 		   current state, hence the wl1271 struct should be safe. */ | ||||
| 		cancel_work_sync(&wl->irq_work); | ||||
| 		mutex_lock(&wl->mutex); | ||||
| power_off: | ||||
| 		wl1271_power_off(wl); | ||||
| 	} | ||||
| 
 | ||||
| 	wl1271_error("firmware boot in PLT mode failed despite %d retries", | ||||
| 		     WL1271_BOOT_RETRIES); | ||||
| out: | ||||
| 	mutex_unlock(&wl->mutex); | ||||
| 
 | ||||
| @ -762,7 +781,20 @@ out: | ||||
| static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||
| { | ||||
| 	struct wl1271 *wl = hw->priv; | ||||
| 	struct ieee80211_conf *conf = &hw->conf; | ||||
| 	struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); | ||||
| 	struct ieee80211_sta *sta = txinfo->control.sta; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	/* peek into the rates configured in the STA entry */ | ||||
| 	spin_lock_irqsave(&wl->wl_lock, flags); | ||||
| 	if (sta && sta->supp_rates[conf->channel->band] != wl->sta_rate_set) { | ||||
| 		wl->sta_rate_set = sta->supp_rates[conf->channel->band]; | ||||
| 		set_bit(WL1271_FLAG_STA_RATES_CHANGED, &wl->flags); | ||||
| 	} | ||||
| 	spin_unlock_irqrestore(&wl->wl_lock, flags); | ||||
| 
 | ||||
| 	/* queue the packet */ | ||||
| 	skb_queue_tail(&wl->tx_queue, skb); | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -784,7 +816,7 @@ static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||
| 		 * protected. Maybe fix this by removing the stupid | ||||
| 		 * variable altogether and checking the real queue state? | ||||
| 		 */ | ||||
| 		wl->tx_queue_stopped = true; | ||||
| 		set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); | ||||
| 	} | ||||
| 
 | ||||
| 	return NETDEV_TX_OK; | ||||
| @ -880,6 +912,7 @@ static struct notifier_block wl1271_dev_notifier = { | ||||
| static int wl1271_op_start(struct ieee80211_hw *hw) | ||||
| { | ||||
| 	struct wl1271 *wl = hw->priv; | ||||
| 	int retries = WL1271_BOOT_RETRIES; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_MAC80211, "mac80211 start"); | ||||
| @ -893,30 +926,42 @@ static int wl1271_op_start(struct ieee80211_hw *hw) | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = wl1271_chip_wakeup(wl); | ||||
| 	if (ret < 0) | ||||
| 	while (retries) { | ||||
| 		retries--; | ||||
| 		ret = wl1271_chip_wakeup(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto power_off; | ||||
| 
 | ||||
| 		ret = wl1271_boot(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto power_off; | ||||
| 
 | ||||
| 		ret = wl1271_hw_init(wl); | ||||
| 		if (ret < 0) | ||||
| 			goto irq_disable; | ||||
| 
 | ||||
| 		wl->state = WL1271_STATE_ON; | ||||
| 		wl1271_info("firmware booted (%s)", wl->chip.fw_ver); | ||||
| 		goto out; | ||||
| 
 | ||||
| 	ret = wl1271_boot(wl); | ||||
| 	if (ret < 0) | ||||
| 		goto out_power_off; | ||||
| 
 | ||||
| 	ret = wl1271_hw_init(wl); | ||||
| 	if (ret < 0) | ||||
| 		goto out_irq_disable; | ||||
| 
 | ||||
| 	wl->state = WL1271_STATE_ON; | ||||
| 
 | ||||
| 	wl1271_info("firmware booted (%s)", wl->chip.fw_ver); | ||||
| 
 | ||||
| 	goto out; | ||||
| 
 | ||||
| out_irq_disable: | ||||
| 	wl1271_disable_interrupts(wl); | ||||
| 
 | ||||
| out_power_off: | ||||
| 	wl1271_power_off(wl); | ||||
| irq_disable: | ||||
| 		wl1271_disable_interrupts(wl); | ||||
| 		mutex_unlock(&wl->mutex); | ||||
| 		/* Unlocking the mutex in the middle of handling is
 | ||||
| 		   inherently unsafe. In this case we deem it safe to do, | ||||
| 		   because we need to let any possibly pending IRQ out of | ||||
| 		   the system (and while we are WL1271_STATE_OFF the IRQ | ||||
| 		   work function will not do anything.) Also, any other | ||||
| 		   possible concurrent operations will fail due to the | ||||
| 		   current state, hence the wl1271 struct should be safe. */ | ||||
| 		cancel_work_sync(&wl->irq_work); | ||||
| 		mutex_lock(&wl->mutex); | ||||
| power_off: | ||||
| 		wl1271_power_off(wl); | ||||
| 	} | ||||
| 
 | ||||
| 	wl1271_error("firmware boot failed despite %d retries", | ||||
| 		     WL1271_BOOT_RETRIES); | ||||
| out: | ||||
| 	mutex_unlock(&wl->mutex); | ||||
| 
 | ||||
| @ -944,11 +989,10 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | ||||
| 
 | ||||
| 	WARN_ON(wl->state != WL1271_STATE_ON); | ||||
| 
 | ||||
| 	if (wl->scanning) { | ||||
| 	if (test_and_clear_bit(WL1271_FLAG_SCANNING, &wl->flags)) { | ||||
| 		mutex_unlock(&wl->mutex); | ||||
| 		ieee80211_scan_completed(wl->hw, true); | ||||
| 		mutex_lock(&wl->mutex); | ||||
| 		wl->scanning = false; | ||||
| 	} | ||||
| 
 | ||||
| 	wl->state = WL1271_STATE_OFF; | ||||
| @ -973,10 +1017,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | ||||
| 	wl->band = IEEE80211_BAND_2GHZ; | ||||
| 
 | ||||
| 	wl->rx_counter = 0; | ||||
| 	wl->elp = false; | ||||
| 	wl->psm = 0; | ||||
| 	wl->psm_entry_retry = 0; | ||||
| 	wl->tx_queue_stopped = false; | ||||
| 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL; | ||||
| 	wl->tx_blocks_available = 0; | ||||
| 	wl->tx_results_count = 0; | ||||
| @ -986,7 +1027,9 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | ||||
| 	wl->tx_security_seq_32 = 0; | ||||
| 	wl->time_offset = 0; | ||||
| 	wl->session_counter = 0; | ||||
| 	wl->joined = false; | ||||
| 	wl->rate_set = CONF_TX_RATE_MASK_BASIC; | ||||
| 	wl->sta_rate_set = 0; | ||||
| 	wl->flags = 0; | ||||
| 
 | ||||
| 	for (i = 0; i < NUM_TX_QUEUES; i++) | ||||
| 		wl->tx_blocks_freed[i] = 0; | ||||
| @ -996,13 +1039,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) | ||||
| } | ||||
| 
 | ||||
| static int wl1271_op_add_interface(struct ieee80211_hw *hw, | ||||
| 				   struct ieee80211_if_init_conf *conf) | ||||
| 				   struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct wl1271 *wl = hw->priv; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM", | ||||
| 		     conf->type, conf->mac_addr); | ||||
| 		     vif->type, vif->addr); | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 	if (wl->vif) { | ||||
| @ -1010,9 +1053,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw, | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	wl->vif = conf->vif; | ||||
| 	wl->vif = vif; | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 		wl->bss_type = BSS_TYPE_STA_BSS; | ||||
| 		break; | ||||
| @ -1032,7 +1075,7 @@ out: | ||||
| } | ||||
| 
 | ||||
| static void wl1271_op_remove_interface(struct ieee80211_hw *hw, | ||||
| 					 struct ieee80211_if_init_conf *conf) | ||||
| 					 struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct wl1271 *wl = hw->priv; | ||||
| 
 | ||||
| @ -1109,6 +1152,51 @@ out: | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static int wl1271_join_channel(struct wl1271 *wl, int channel) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	/* we need to use a dummy BSSID for now */ | ||||
| 	static const u8 dummy_bssid[ETH_ALEN] = { 0x0b, 0xad, 0xde, | ||||
| 						  0xad, 0xbe, 0xef }; | ||||
| 
 | ||||
| 	/* the dummy join is not required for ad-hoc */ | ||||
| 	if (wl->bss_type == BSS_TYPE_IBSS) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	/* disable mac filter, so we hear everything */ | ||||
| 	wl->rx_config &= ~CFG_BSSID_FILTER_EN; | ||||
| 
 | ||||
| 	wl->channel = channel; | ||||
| 	memcpy(wl->bssid, dummy_bssid, ETH_ALEN); | ||||
| 
 | ||||
| 	ret = wl1271_cmd_join(wl); | ||||
| 	if (ret < 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	set_bit(WL1271_FLAG_JOINED, &wl->flags); | ||||
| 
 | ||||
| out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int wl1271_unjoin_channel(struct wl1271 *wl) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* to stop listening to a channel, we disconnect */ | ||||
| 	ret = wl1271_cmd_disconnect(wl); | ||||
| 	if (ret < 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	clear_bit(WL1271_FLAG_JOINED, &wl->flags); | ||||
| 	wl->channel = 0; | ||||
| 	memset(wl->bssid, 0, ETH_ALEN); | ||||
| 	wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | ||||
| 
 | ||||
| out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | ||||
| { | ||||
| 	struct wl1271 *wl = hw->priv; | ||||
| @ -1117,10 +1205,11 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | ||||
| 
 | ||||
| 	channel = ieee80211_frequency_to_channel(conf->channel->center_freq); | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", | ||||
| 	wl1271_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d %s", | ||||
| 		     channel, | ||||
| 		     conf->flags & IEEE80211_CONF_PS ? "on" : "off", | ||||
| 		     conf->power_level); | ||||
| 		     conf->power_level, | ||||
| 		     conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use"); | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 
 | ||||
| @ -1130,34 +1219,44 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) | ||||
| 	if (ret < 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (channel != wl->channel) { | ||||
| 		/*
 | ||||
| 		 * We assume that the stack will configure the right channel | ||||
| 		 * before associating, so we don't need to send a join | ||||
| 		 * command here.  We will join the right channel when the | ||||
| 		 * BSSID changes | ||||
| 		 */ | ||||
| 		wl->channel = channel; | ||||
| 	if (changed & IEEE80211_CONF_CHANGE_IDLE) { | ||||
| 		if (conf->flags & IEEE80211_CONF_IDLE && | ||||
| 		    test_bit(WL1271_FLAG_JOINED, &wl->flags)) | ||||
| 			wl1271_unjoin_channel(wl); | ||||
| 		else if (!(conf->flags & IEEE80211_CONF_IDLE)) | ||||
| 			wl1271_join_channel(wl, channel); | ||||
| 
 | ||||
| 		if (conf->flags & IEEE80211_CONF_IDLE) { | ||||
| 			wl->rate_set = CONF_TX_RATE_MASK_BASIC; | ||||
| 			wl->sta_rate_set = 0; | ||||
| 			wl1271_acx_rate_policies(wl); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { | ||||
| 		wl1271_info("psm enabled"); | ||||
| 	/* if the channel changes while joined, join again */ | ||||
| 	if (channel != wl->channel && test_bit(WL1271_FLAG_JOINED, &wl->flags)) | ||||
| 		wl1271_join_channel(wl, channel); | ||||
| 
 | ||||
| 		wl->psm_requested = true; | ||||
| 	if (conf->flags & IEEE80211_CONF_PS && | ||||
| 	    !test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { | ||||
| 		set_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * We enter PSM only if we're already associated. | ||||
| 		 * If we're not, we'll enter it when joining an SSID, | ||||
| 		 * through the bss_info_changed() hook. | ||||
| 		 */ | ||||
| 		ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||||
| 		if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) { | ||||
| 			wl1271_info("psm enabled"); | ||||
| 			ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE); | ||||
| 		} | ||||
| 	} else if (!(conf->flags & IEEE80211_CONF_PS) && | ||||
| 		   wl->psm_requested) { | ||||
| 		   test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags)) { | ||||
| 		wl1271_info("psm disabled"); | ||||
| 
 | ||||
| 		wl->psm_requested = false; | ||||
| 		clear_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags); | ||||
| 
 | ||||
| 		if (wl->psm) | ||||
| 		if (test_bit(WL1271_FLAG_PSM, &wl->flags)) | ||||
| 			ret = wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE); | ||||
| 	} | ||||
| 
 | ||||
| @ -1440,22 +1539,6 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static u32 wl1271_enabled_rates_get(struct wl1271 *wl, u64 basic_rate_set) | ||||
| { | ||||
| 	struct ieee80211_supported_band *band; | ||||
| 	u32 enabled_rates = 0; | ||||
| 	int bit; | ||||
| 
 | ||||
| 	band = wl->hw->wiphy->bands[wl->band]; | ||||
| 	for (bit = 0; bit < band->n_bitrates; bit++) { | ||||
| 		if (basic_rate_set & 0x1) | ||||
| 			enabled_rates |= band->bitrates[bit].hw_value; | ||||
| 		basic_rate_set >>= 1; | ||||
| 	} | ||||
| 
 | ||||
| 	return enabled_rates; | ||||
| } | ||||
| 
 | ||||
| static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 				       struct ieee80211_vif *vif, | ||||
| 				       struct ieee80211_bss_conf *bss_conf, | ||||
| @ -1473,9 +1556,68 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 	if (ret < 0) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if ((changed & BSS_CHANGED_BSSID) && | ||||
| 	    /*
 | ||||
| 	     * Now we know the correct bssid, so we send a new join command | ||||
| 	     * and enable the BSSID filter | ||||
| 	     */ | ||||
| 	    memcmp(wl->bssid, bss_conf->bssid, ETH_ALEN)) { | ||||
| 			wl->rx_config |= CFG_BSSID_FILTER_EN; | ||||
| 			memcpy(wl->bssid, bss_conf->bssid, ETH_ALEN); | ||||
| 			ret = wl1271_cmd_build_null_data(wl); | ||||
| 			if (ret < 0) { | ||||
| 				wl1271_warning("cmd buld null data failed %d", | ||||
| 					       ret); | ||||
| 				goto out_sleep; | ||||
| 			} | ||||
| 			ret = wl1271_cmd_join(wl); | ||||
| 			if (ret < 0) { | ||||
| 				wl1271_warning("cmd join failed %d", ret); | ||||
| 				goto out_sleep; | ||||
| 			} | ||||
| 			set_bit(WL1271_FLAG_JOINED, &wl->flags); | ||||
| 	} | ||||
| 
 | ||||
| 	if (wl->bss_type == BSS_TYPE_IBSS) { | ||||
| 		/* FIXME: This implements rudimentary ad-hoc support -
 | ||||
| 		   proper templates are on the wish list and notification | ||||
| 		   on when they change. This patch will update the templates | ||||
| 		   on every call to this function. Also, the firmware will not | ||||
| 		   answer to probe-requests as it does not have the proper | ||||
| 		   SSID set in the JOIN command. The probe-response template | ||||
| 		   is set nevertheless, as the FW will ASSERT without it */ | ||||
| 		struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); | ||||
| 
 | ||||
| 		if (beacon) { | ||||
| 			struct ieee80211_hdr *hdr; | ||||
| 			ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, | ||||
| 						      beacon->data, | ||||
| 						      beacon->len); | ||||
| 
 | ||||
| 			if (ret < 0) { | ||||
| 				dev_kfree_skb(beacon); | ||||
| 				goto out_sleep; | ||||
| 			} | ||||
| 
 | ||||
| 			hdr = (struct ieee80211_hdr *) beacon->data; | ||||
| 			hdr->frame_control = cpu_to_le16( | ||||
| 				IEEE80211_FTYPE_MGMT | | ||||
| 				IEEE80211_STYPE_PROBE_RESP); | ||||
| 
 | ||||
| 			ret = wl1271_cmd_template_set(wl, | ||||
| 						      CMD_TEMPL_PROBE_RESPONSE, | ||||
| 						      beacon->data, | ||||
| 						      beacon->len); | ||||
| 			dev_kfree_skb(beacon); | ||||
| 			if (ret < 0) | ||||
| 				goto out_sleep; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (changed & BSS_CHANGED_ASSOC) { | ||||
| 		if (bss_conf->assoc) { | ||||
| 			wl->aid = bss_conf->aid; | ||||
| 			set_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * with wl1271, we don't need to update the | ||||
| @ -1492,7 +1634,8 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 				goto out_sleep; | ||||
| 
 | ||||
| 			/* If we want to go in PSM but we're not there yet */ | ||||
| 			if (wl->psm_requested && !wl->psm) { | ||||
| 			if (test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags) && | ||||
| 			    !test_bit(WL1271_FLAG_PSM, &wl->flags)) { | ||||
| 				mode = STATION_POWER_SAVE_MODE; | ||||
| 				ret = wl1271_ps_set_mode(wl, mode); | ||||
| 				if (ret < 0) | ||||
| @ -1500,7 +1643,7 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 			} | ||||
| 		} else { | ||||
| 			/* use defaults when not associated */ | ||||
| 			wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; | ||||
| 			clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags); | ||||
| 			wl->aid = 0; | ||||
| 		} | ||||
| 
 | ||||
| @ -1535,17 +1678,6 @@ static void wl1271_op_bss_info_changed(struct ieee80211_hw *hw, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (changed & BSS_CHANGED_BASIC_RATES) { | ||||
| 		wl->basic_rate_set = wl1271_enabled_rates_get( | ||||
| 			wl, bss_conf->basic_rates); | ||||
| 
 | ||||
| 		ret = wl1271_acx_rate_policies(wl, wl->basic_rate_set); | ||||
| 		if (ret < 0) { | ||||
| 			wl1271_warning("Set rate policies failed %d", ret); | ||||
| 			goto out_sleep; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| out_sleep: | ||||
| 	wl1271_ps_elp_sleep(wl); | ||||
| 
 | ||||
| @ -1599,19 +1731,19 @@ static struct ieee80211_rate wl1271_rates[] = { | ||||
| 
 | ||||
| /* can't be const, mac80211 writes to this */ | ||||
| static struct ieee80211_channel wl1271_channels[] = { | ||||
| 	{ .hw_value = 1, .center_freq = 2412}, | ||||
| 	{ .hw_value = 2, .center_freq = 2417}, | ||||
| 	{ .hw_value = 3, .center_freq = 2422}, | ||||
| 	{ .hw_value = 4, .center_freq = 2427}, | ||||
| 	{ .hw_value = 5, .center_freq = 2432}, | ||||
| 	{ .hw_value = 6, .center_freq = 2437}, | ||||
| 	{ .hw_value = 7, .center_freq = 2442}, | ||||
| 	{ .hw_value = 8, .center_freq = 2447}, | ||||
| 	{ .hw_value = 9, .center_freq = 2452}, | ||||
| 	{ .hw_value = 10, .center_freq = 2457}, | ||||
| 	{ .hw_value = 11, .center_freq = 2462}, | ||||
| 	{ .hw_value = 12, .center_freq = 2467}, | ||||
| 	{ .hw_value = 13, .center_freq = 2472}, | ||||
| 	{ .hw_value = 1, .center_freq = 2412, .max_power = 25 }, | ||||
| 	{ .hw_value = 2, .center_freq = 2417, .max_power = 25 }, | ||||
| 	{ .hw_value = 3, .center_freq = 2422, .max_power = 25 }, | ||||
| 	{ .hw_value = 4, .center_freq = 2427, .max_power = 25 }, | ||||
| 	{ .hw_value = 5, .center_freq = 2432, .max_power = 25 }, | ||||
| 	{ .hw_value = 6, .center_freq = 2437, .max_power = 25 }, | ||||
| 	{ .hw_value = 7, .center_freq = 2442, .max_power = 25 }, | ||||
| 	{ .hw_value = 8, .center_freq = 2447, .max_power = 25 }, | ||||
| 	{ .hw_value = 9, .center_freq = 2452, .max_power = 25 }, | ||||
| 	{ .hw_value = 10, .center_freq = 2457, .max_power = 25 }, | ||||
| 	{ .hw_value = 11, .center_freq = 2462, .max_power = 25 }, | ||||
| 	{ .hw_value = 12, .center_freq = 2467, .max_power = 25 }, | ||||
| 	{ .hw_value = 13, .center_freq = 2472, .max_power = 25 }, | ||||
| }; | ||||
| 
 | ||||
| /* can't be const, mac80211 writes to this */ | ||||
| @ -1757,7 +1889,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) | ||||
| 		IEEE80211_HW_BEACON_FILTER | | ||||
| 		IEEE80211_HW_SUPPORTS_PS; | ||||
| 
 | ||||
| 	wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); | ||||
| 	wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | | ||||
| 		BIT(NL80211_IFTYPE_ADHOC); | ||||
| 	wl->hw->wiphy->max_scan_ssids = 1; | ||||
| 	wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wl1271_band_2ghz; | ||||
| 
 | ||||
| @ -1818,21 +1951,18 @@ static int __devinit wl1271_probe(struct spi_device *spi) | ||||
| 
 | ||||
| 	INIT_DELAYED_WORK(&wl->elp_work, wl1271_elp_work); | ||||
| 	wl->channel = WL1271_DEFAULT_CHANNEL; | ||||
| 	wl->scanning = false; | ||||
| 	wl->default_key = 0; | ||||
| 	wl->rx_counter = 0; | ||||
| 	wl->rx_config = WL1271_DEFAULT_RX_CONFIG; | ||||
| 	wl->rx_filter = WL1271_DEFAULT_RX_FILTER; | ||||
| 	wl->elp = false; | ||||
| 	wl->psm = 0; | ||||
| 	wl->psm_requested = false; | ||||
| 	wl->psm_entry_retry = 0; | ||||
| 	wl->tx_queue_stopped = false; | ||||
| 	wl->power_level = WL1271_DEFAULT_POWER_LEVEL; | ||||
| 	wl->basic_rate_set = WL1271_DEFAULT_BASIC_RATE_SET; | ||||
| 	wl->basic_rate_set = CONF_TX_RATE_MASK_BASIC; | ||||
| 	wl->rate_set = CONF_TX_RATE_MASK_BASIC; | ||||
| 	wl->sta_rate_set = 0; | ||||
| 	wl->band = IEEE80211_BAND_2GHZ; | ||||
| 	wl->vif = NULL; | ||||
| 	wl->joined = false; | ||||
| 	wl->flags = 0; | ||||
| 
 | ||||
| 	for (i = 0; i < ACX_TX_DESCRIPTORS; i++) | ||||
| 		wl->tx_frames[i] = NULL; | ||||
|  | ||||
| @ -39,12 +39,13 @@ void wl1271_elp_work(struct work_struct *work) | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 
 | ||||
| 	if (wl->elp || !wl->psm) | ||||
| 	if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) || | ||||
| 	    !test_bit(WL1271_FLAG_PSM, &wl->flags)) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_PSM, "chip to elp"); | ||||
| 	wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG_ADDR, ELPCTRL_SLEEP); | ||||
| 	wl->elp = true; | ||||
| 	set_bit(WL1271_FLAG_IN_ELP, &wl->flags); | ||||
| 
 | ||||
| out: | ||||
| 	mutex_unlock(&wl->mutex); | ||||
| @ -55,7 +56,7 @@ out: | ||||
| /* Routines to toggle sleep mode while in ELP */ | ||||
| void wl1271_ps_elp_sleep(struct wl1271 *wl) | ||||
| { | ||||
| 	if (wl->psm) { | ||||
| 	if (test_bit(WL1271_FLAG_PSM, &wl->flags)) { | ||||
| 		cancel_delayed_work(&wl->elp_work); | ||||
| 		ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, | ||||
| 					msecs_to_jiffies(ELP_ENTRY_DELAY)); | ||||
| @ -70,7 +71,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) | ||||
| 	u32 start_time = jiffies; | ||||
| 	bool pending = false; | ||||
| 
 | ||||
| 	if (!wl->elp) | ||||
| 	if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_PSM, "waking up chip from elp"); | ||||
| @ -101,7 +102,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	wl->elp = false; | ||||
| 	clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", | ||||
| 		     jiffies_to_msecs(jiffies - start_time)); | ||||
| @ -143,7 +144,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) | ||||
| 		if (ret < 0) | ||||
| 			return ret; | ||||
| 
 | ||||
| 		wl->psm = 1; | ||||
| 		set_bit(WL1271_FLAG_PSM, &wl->flags); | ||||
| 		break; | ||||
| 	case STATION_ACTIVE_MODE: | ||||
| 	default: | ||||
| @ -166,7 +167,7 @@ int wl1271_ps_set_mode(struct wl1271 *wl, enum wl1271_cmd_ps_mode mode) | ||||
| 		if (ret < 0) | ||||
| 			return ret; | ||||
| 
 | ||||
| 		wl->psm = 0; | ||||
| 		clear_bit(WL1271_FLAG_PSM, &wl->flags); | ||||
| 		break; | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -121,6 +121,11 @@ static int wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, | ||||
| 	pad = pad - skb->len; | ||||
| 	tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; | ||||
| 
 | ||||
| 	/* if the packets are destined for AP (have a STA entry) send them
 | ||||
| 	   with AP rate policies, otherwise use default basic rates */ | ||||
| 	if (control->control.sta) | ||||
| 		tx_attr |= ACX_TX_AP_FULL_RATE << TX_HW_ATTR_OFST_RATE_POLICY; | ||||
| 
 | ||||
| 	desc->tx_attr = cpu_to_le16(tx_attr); | ||||
| 
 | ||||
| 	wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d", pad); | ||||
| @ -214,18 +219,50 @@ static int wl1271_tx_frame(struct wl1271 *wl, struct sk_buff *skb) | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) | ||||
| { | ||||
| 	struct ieee80211_supported_band *band; | ||||
| 	u32 enabled_rates = 0; | ||||
| 	int bit; | ||||
| 
 | ||||
| 	band = wl->hw->wiphy->bands[wl->band]; | ||||
| 	for (bit = 0; bit < band->n_bitrates; bit++) { | ||||
| 		if (rate_set & 0x1) | ||||
| 			enabled_rates |= band->bitrates[bit].hw_value; | ||||
| 		rate_set >>= 1; | ||||
| 	} | ||||
| 
 | ||||
| 	return enabled_rates; | ||||
| } | ||||
| 
 | ||||
| void wl1271_tx_work(struct work_struct *work) | ||||
| { | ||||
| 	struct wl1271 *wl = container_of(work, struct wl1271, tx_work); | ||||
| 	struct sk_buff *skb; | ||||
| 	bool woken_up = false; | ||||
| 	u32 sta_rates = 0; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	/* check if the rates supported by the AP have changed */ | ||||
| 	if (unlikely(test_and_clear_bit(WL1271_FLAG_STA_RATES_CHANGED, | ||||
| 					&wl->flags))) { | ||||
| 		unsigned long flags; | ||||
| 		spin_lock_irqsave(&wl->wl_lock, flags); | ||||
| 		sta_rates = wl->sta_rate_set; | ||||
| 		spin_unlock_irqrestore(&wl->wl_lock, flags); | ||||
| 	} | ||||
| 
 | ||||
| 	mutex_lock(&wl->mutex); | ||||
| 
 | ||||
| 	if (unlikely(wl->state == WL1271_STATE_OFF)) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	/* if rates have changed, re-configure the rate policy */ | ||||
| 	if (unlikely(sta_rates)) { | ||||
| 		wl->rate_set = wl1271_tx_enabled_rates_get(wl, sta_rates); | ||||
| 		wl1271_acx_rate_policies(wl); | ||||
| 	} | ||||
| 
 | ||||
| 	while ((skb = skb_dequeue(&wl->tx_queue))) { | ||||
| 		if (!woken_up) { | ||||
| 			ret = wl1271_ps_elp_wakeup(wl, false); | ||||
| @ -240,18 +277,18 @@ void wl1271_tx_work(struct work_struct *work) | ||||
| 			wl1271_debug(DEBUG_TX, "tx_work: fw buffer full, " | ||||
| 				     "stop queues"); | ||||
| 			ieee80211_stop_queues(wl->hw); | ||||
| 			wl->tx_queue_stopped = true; | ||||
| 			set_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); | ||||
| 			skb_queue_head(&wl->tx_queue, skb); | ||||
| 			goto out; | ||||
| 		} else if (ret < 0) { | ||||
| 			dev_kfree_skb(skb); | ||||
| 			goto out; | ||||
| 		} else if (wl->tx_queue_stopped) { | ||||
| 		} else if (test_and_clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, | ||||
| 					      &wl->flags)) { | ||||
| 			/* firmware buffer has space, restart queues */ | ||||
| 			wl1271_debug(DEBUG_TX, | ||||
| 				     "complete_packet: waking queues"); | ||||
| 			ieee80211_wake_queues(wl->hw); | ||||
| 			wl->tx_queue_stopped = false; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -1325,151 +1325,11 @@ int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates) | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| static int ofdm_qual_db(u8 status_quality, u8 zd_rate, unsigned int size) | ||||
| { | ||||
| 	static const u16 constants[] = { | ||||
| 		715, 655, 585, 540, 470, 410, 360, 315, | ||||
| 		270, 235, 205, 175, 150, 125, 105,  85, | ||||
| 		 65,  50,  40,  25,  15 | ||||
| 	}; | ||||
| 
 | ||||
| 	int i; | ||||
| 	u32 x; | ||||
| 
 | ||||
| 	/* It seems that their quality parameter is somehow per signal
 | ||||
| 	 * and is now transferred per bit. | ||||
| 	 */ | ||||
| 	switch (zd_rate) { | ||||
| 	case ZD_OFDM_RATE_6M: | ||||
| 	case ZD_OFDM_RATE_12M: | ||||
| 	case ZD_OFDM_RATE_24M: | ||||
| 		size *= 2; | ||||
| 		break; | ||||
| 	case ZD_OFDM_RATE_9M: | ||||
| 	case ZD_OFDM_RATE_18M: | ||||
| 	case ZD_OFDM_RATE_36M: | ||||
| 	case ZD_OFDM_RATE_54M: | ||||
| 		size *= 4; | ||||
| 		size /= 3; | ||||
| 		break; | ||||
| 	case ZD_OFDM_RATE_48M: | ||||
| 		size *= 3; | ||||
| 		size /= 2; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	x = (10000 * status_quality)/size; | ||||
| 	for (i = 0; i < ARRAY_SIZE(constants); i++) { | ||||
| 		if (x > constants[i]) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	switch (zd_rate) { | ||||
| 	case ZD_OFDM_RATE_6M: | ||||
| 	case ZD_OFDM_RATE_9M: | ||||
| 		i += 3; | ||||
| 		break; | ||||
| 	case ZD_OFDM_RATE_12M: | ||||
| 	case ZD_OFDM_RATE_18M: | ||||
| 		i += 5; | ||||
| 		break; | ||||
| 	case ZD_OFDM_RATE_24M: | ||||
| 	case ZD_OFDM_RATE_36M: | ||||
| 		i += 9; | ||||
| 		break; | ||||
| 	case ZD_OFDM_RATE_48M: | ||||
| 	case ZD_OFDM_RATE_54M: | ||||
| 		i += 15; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	return i; | ||||
| } | ||||
| 
 | ||||
| static int ofdm_qual_percent(u8 status_quality, u8 zd_rate, unsigned int size) | ||||
| { | ||||
| 	int r; | ||||
| 
 | ||||
| 	r = ofdm_qual_db(status_quality, zd_rate, size); | ||||
| 	ZD_ASSERT(r >= 0); | ||||
| 	if (r < 0) | ||||
| 		r = 0; | ||||
| 
 | ||||
| 	r = (r * 100)/29; | ||||
| 	return r <= 100 ? r : 100; | ||||
| } | ||||
| 
 | ||||
| static unsigned int log10times100(unsigned int x) | ||||
| { | ||||
| 	static const u8 log10[] = { | ||||
| 		  0, | ||||
| 		  0,   30,   47,   60,   69,   77,   84,   90,   95,  100, | ||||
| 		104,  107,  111,  114,  117,  120,  123,  125,  127,  130, | ||||
| 		132,  134,  136,  138,  139,  141,  143,  144,  146,  147, | ||||
| 		149,  150,  151,  153,  154,  155,  156,  157,  159,  160, | ||||
| 		161,  162,  163,  164,  165,  166,  167,  168,  169,  169, | ||||
| 		170,  171,  172,  173,  174,  174,  175,  176,  177,  177, | ||||
| 		178,  179,  179,  180,  181,  181,  182,  183,  183,  184, | ||||
| 		185,  185,  186,  186,  187,  188,  188,  189,  189,  190, | ||||
| 		190,  191,  191,  192,  192,  193,  193,  194,  194,  195, | ||||
| 		195,  196,  196,  197,  197,  198,  198,  199,  199,  200, | ||||
| 		200,  200,  201,  201,  202,  202,  202,  203,  203,  204, | ||||
| 		204,  204,  205,  205,  206,  206,  206,  207,  207,  207, | ||||
| 		208,  208,  208,  209,  209,  210,  210,  210,  211,  211, | ||||
| 		211,  212,  212,  212,  213,  213,  213,  213,  214,  214, | ||||
| 		214,  215,  215,  215,  216,  216,  216,  217,  217,  217, | ||||
| 		217,  218,  218,  218,  219,  219,  219,  219,  220,  220, | ||||
| 		220,  220,  221,  221,  221,  222,  222,  222,  222,  223, | ||||
| 		223,  223,  223,  224,  224,  224,  224, | ||||
| 	}; | ||||
| 
 | ||||
| 	return x < ARRAY_SIZE(log10) ? log10[x] : 225; | ||||
| } | ||||
| 
 | ||||
| enum { | ||||
| 	MAX_CCK_EVM_DB = 45, | ||||
| }; | ||||
| 
 | ||||
| static int cck_evm_db(u8 status_quality) | ||||
| { | ||||
| 	return (20 * log10times100(status_quality)) / 100; | ||||
| } | ||||
| 
 | ||||
| static int cck_snr_db(u8 status_quality) | ||||
| { | ||||
| 	int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality); | ||||
| 	ZD_ASSERT(r >= 0); | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| static int cck_qual_percent(u8 status_quality) | ||||
| { | ||||
| 	int r; | ||||
| 
 | ||||
| 	r = cck_snr_db(status_quality); | ||||
| 	r = (100*r)/17; | ||||
| 	return r <= 100 ? r : 100; | ||||
| } | ||||
| 
 | ||||
| static inline u8 zd_rate_from_ofdm_plcp_header(const void *rx_frame) | ||||
| { | ||||
| 	return ZD_OFDM | zd_ofdm_plcp_header_rate(rx_frame); | ||||
| } | ||||
| 
 | ||||
| u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, | ||||
| 	              const struct rx_status *status) | ||||
| { | ||||
| 	return (status->frame_status&ZD_RX_OFDM) ? | ||||
| 		ofdm_qual_percent(status->signal_quality_ofdm, | ||||
| 				  zd_rate_from_ofdm_plcp_header(rx_frame), | ||||
| 			          size) : | ||||
| 		cck_qual_percent(status->signal_quality_cck); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * zd_rx_rate - report zd-rate | ||||
|  * @rx_frame - received frame | ||||
|  | ||||
| @ -929,9 +929,6 @@ static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval) | ||||
| 
 | ||||
| struct rx_status; | ||||
| 
 | ||||
| u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size, | ||||
| 	               const struct rx_status *status); | ||||
| 
 | ||||
| u8 zd_rx_rate(const void *rx_frame, const struct rx_status *status); | ||||
| 
 | ||||
| struct zd_mc_hash { | ||||
|  | ||||
| @ -828,9 +828,6 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) | ||||
| 	stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; | ||||
| 	stats.band = IEEE80211_BAND_2GHZ; | ||||
| 	stats.signal = status->signal_strength; | ||||
| 	stats.qual = zd_rx_qual_percent(buffer, | ||||
| 		                          length - sizeof(struct rx_status), | ||||
| 		                          status); | ||||
| 
 | ||||
| 	rate = zd_rx_rate(buffer, status); | ||||
| 
 | ||||
| @ -872,7 +869,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) | ||||
| } | ||||
| 
 | ||||
| static int zd_op_add_interface(struct ieee80211_hw *hw, | ||||
| 				struct ieee80211_if_init_conf *conf) | ||||
| 				struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct zd_mac *mac = zd_hw_mac(hw); | ||||
| 
 | ||||
| @ -880,22 +877,22 @@ static int zd_op_add_interface(struct ieee80211_hw *hw, | ||||
| 	if (mac->type != NL80211_IFTYPE_UNSPECIFIED) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	switch (conf->type) { | ||||
| 	switch (vif->type) { | ||||
| 	case NL80211_IFTYPE_MONITOR: | ||||
| 	case NL80211_IFTYPE_MESH_POINT: | ||||
| 	case NL80211_IFTYPE_STATION: | ||||
| 	case NL80211_IFTYPE_ADHOC: | ||||
| 		mac->type = conf->type; | ||||
| 		mac->type = vif->type; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return -EOPNOTSUPP; | ||||
| 	} | ||||
| 
 | ||||
| 	return zd_write_mac_addr(&mac->chip, conf->mac_addr); | ||||
| 	return zd_write_mac_addr(&mac->chip, vif->addr); | ||||
| } | ||||
| 
 | ||||
| static void zd_op_remove_interface(struct ieee80211_hw *hw, | ||||
| 				    struct ieee80211_if_init_conf *conf) | ||||
| 				    struct ieee80211_vif *vif) | ||||
| { | ||||
| 	struct zd_mac *mac = zd_hw_mac(hw); | ||||
| 	mac->type = NL80211_IFTYPE_UNSPECIFIED; | ||||
|  | ||||
| @ -1085,12 +1085,12 @@ enum ieee80211_eid { | ||||
| 	WLAN_EID_TIM = 5, | ||||
| 	WLAN_EID_IBSS_PARAMS = 6, | ||||
| 	WLAN_EID_CHALLENGE = 16, | ||||
| 	/* 802.11d */ | ||||
| 
 | ||||
| 	WLAN_EID_COUNTRY = 7, | ||||
| 	WLAN_EID_HP_PARAMS = 8, | ||||
| 	WLAN_EID_HP_TABLE = 9, | ||||
| 	WLAN_EID_REQUEST = 10, | ||||
| 	/* 802.11e */ | ||||
| 
 | ||||
| 	WLAN_EID_QBSS_LOAD = 11, | ||||
| 	WLAN_EID_EDCA_PARAM_SET = 12, | ||||
| 	WLAN_EID_TSPEC = 13, | ||||
| @ -1113,7 +1113,7 @@ enum ieee80211_eid { | ||||
| 	WLAN_EID_PREP = 69, | ||||
| 	WLAN_EID_PERR = 70, | ||||
| 	WLAN_EID_RANN = 49,	/* compatible with FreeBSD */ | ||||
| 	/* 802.11h */ | ||||
| 
 | ||||
| 	WLAN_EID_PWR_CONSTRAINT = 32, | ||||
| 	WLAN_EID_PWR_CAPABILITY = 33, | ||||
| 	WLAN_EID_TPC_REQUEST = 34, | ||||
| @ -1124,20 +1124,41 @@ enum ieee80211_eid { | ||||
| 	WLAN_EID_MEASURE_REPORT = 39, | ||||
| 	WLAN_EID_QUIET = 40, | ||||
| 	WLAN_EID_IBSS_DFS = 41, | ||||
| 	/* 802.11g */ | ||||
| 
 | ||||
| 	WLAN_EID_ERP_INFO = 42, | ||||
| 	WLAN_EID_EXT_SUPP_RATES = 50, | ||||
| 	/* 802.11n */ | ||||
| 
 | ||||
| 	WLAN_EID_HT_CAPABILITY = 45, | ||||
| 	WLAN_EID_HT_INFORMATION = 61, | ||||
| 	/* 802.11i */ | ||||
| 
 | ||||
| 	WLAN_EID_RSN = 48, | ||||
| 	WLAN_EID_TIMEOUT_INTERVAL = 56, | ||||
| 	WLAN_EID_MMIE = 76 /* 802.11w */, | ||||
| 	WLAN_EID_MMIE = 76, | ||||
| 	WLAN_EID_WPA = 221, | ||||
| 	WLAN_EID_GENERIC = 221, | ||||
| 	WLAN_EID_VENDOR_SPECIFIC = 221, | ||||
| 	WLAN_EID_QOS_PARAMETER = 222 | ||||
| 	WLAN_EID_QOS_PARAMETER = 222, | ||||
| 
 | ||||
| 	WLAN_EID_AP_CHAN_REPORT = 51, | ||||
| 	WLAN_EID_NEIGHBOR_REPORT = 52, | ||||
| 	WLAN_EID_RCPI = 53, | ||||
| 	WLAN_EID_BSS_AVG_ACCESS_DELAY = 63, | ||||
| 	WLAN_EID_ANTENNA_INFO = 64, | ||||
| 	WLAN_EID_RSNI = 65, | ||||
| 	WLAN_EID_MEASUREMENT_PILOT_TX_INFO = 66, | ||||
| 	WLAN_EID_BSS_AVAILABLE_CAPACITY = 67, | ||||
| 	WLAN_EID_BSS_AC_ACCESS_DELAY = 68, | ||||
| 	WLAN_EID_RRM_ENABLED_CAPABILITIES = 70, | ||||
| 	WLAN_EID_MULTIPLE_BSSID = 71, | ||||
| 
 | ||||
| 	WLAN_EID_MOBILITY_DOMAIN = 54, | ||||
| 	WLAN_EID_FAST_BSS_TRANSITION = 55, | ||||
| 	WLAN_EID_TIMEOUT_INTERVAL = 56, | ||||
| 	WLAN_EID_RIC_DATA = 57, | ||||
| 	WLAN_EID_RIC_DESCRIPTOR = 75, | ||||
| 
 | ||||
| 	WLAN_EID_DSE_REGISTERED_LOCATION = 58, | ||||
| 	WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, | ||||
| 	WLAN_EID_EXT_CHANSWITCH_ANN = 60, | ||||
| }; | ||||
| 
 | ||||
| /* Action category code */ | ||||
|  | ||||
| @ -270,6 +270,31 @@ | ||||
|  * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices | ||||
|  *	associated with this wiphy must be down and will follow. | ||||
|  * | ||||
|  * @NL80211_CMD_REMAIN_ON_CHANNEL: Request to remain awake on the specified | ||||
|  *	channel for the specified amount of time. This can be used to do | ||||
|  *	off-channel operations like transmit a Public Action frame and wait for | ||||
|  *	a response while being associated to an AP on another channel. | ||||
|  *	%NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify which | ||||
|  *	radio is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the | ||||
|  *	frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be | ||||
|  *	optionally used to specify additional channel parameters. | ||||
|  *	%NL80211_ATTR_DURATION is used to specify the duration in milliseconds | ||||
|  *	to remain on the channel. This command is also used as an event to | ||||
|  *	notify when the requested duration starts (it may take a while for the | ||||
|  *	driver to schedule this time due to other concurrent needs for the | ||||
|  *	radio). | ||||
|  *	When called, this operation returns a cookie (%NL80211_ATTR_COOKIE) | ||||
|  *	that will be included with any events pertaining to this request; | ||||
|  *	the cookie is also used to cancel the request. | ||||
|  * @NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL: This command can be used to cancel a | ||||
|  *	pending remain-on-channel duration if the desired operation has been | ||||
|  *	completed prior to expiration of the originally requested duration. | ||||
|  *	%NL80211_ATTR_WIPHY or %NL80211_ATTR_IFINDEX is used to specify the | ||||
|  *	radio. The %NL80211_ATTR_COOKIE attribute must be given as well to | ||||
|  *	uniquely identify the request. | ||||
|  *	This command is also used as an event to notify when a requested | ||||
|  *	remain-on-channel duration has expired. | ||||
|  * | ||||
|  * @NL80211_CMD_MAX: highest used command number | ||||
|  * @__NL80211_CMD_AFTER_LAST: internal use | ||||
|  */ | ||||
| @ -353,6 +378,9 @@ enum nl80211_commands { | ||||
| 	NL80211_CMD_DEL_PMKSA, | ||||
| 	NL80211_CMD_FLUSH_PMKSA, | ||||
| 
 | ||||
| 	NL80211_CMD_REMAIN_ON_CHANNEL, | ||||
| 	NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | ||||
| 
 | ||||
| 	/* add new commands above here */ | ||||
| 
 | ||||
| 	/* used to define NL80211_CMD_MAX below */ | ||||
| @ -606,6 +634,10 @@ enum nl80211_commands { | ||||
|  * @NL80211_ATTR_MAX_NUM_PMKIDS: maximum number of PMKIDs a firmware can | ||||
|  *	cache, a wiphy attribute. | ||||
|  * | ||||
|  * @NL80211_ATTR_DURATION: Duration of an operation in milliseconds, u32. | ||||
|  * | ||||
|  * @NL80211_ATTR_COOKIE: Generic 64-bit cookie to identify objects. | ||||
|  * | ||||
|  * @NL80211_ATTR_MAX: highest attribute number currently defined | ||||
|  * @__NL80211_ATTR_AFTER_LAST: internal use | ||||
|  */ | ||||
| @ -743,6 +775,10 @@ enum nl80211_attrs { | ||||
| 	NL80211_ATTR_PMKID, | ||||
| 	NL80211_ATTR_MAX_NUM_PMKIDS, | ||||
| 
 | ||||
| 	NL80211_ATTR_DURATION, | ||||
| 
 | ||||
| 	NL80211_ATTR_COOKIE, | ||||
| 
 | ||||
| 	/* add attributes here, update the policy in nl80211.c */ | ||||
| 
 | ||||
| 	__NL80211_ATTR_AFTER_LAST, | ||||
|  | ||||
| @ -988,6 +988,15 @@ struct cfg80211_pmksa { | ||||
|  * | ||||
|  * @dump_survey: get site survey information. | ||||
|  * | ||||
|  * @remain_on_channel: Request the driver to remain awake on the specified | ||||
|  *	channel for the specified duration to complete an off-channel | ||||
|  *	operation (e.g., public action frame exchange). When the driver is | ||||
|  *	ready on the requested channel, it must indicate this with an event | ||||
|  *	notification by calling cfg80211_ready_on_channel(). | ||||
|  * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation. | ||||
|  *	This allows the operation to be terminated prior to timeout based on | ||||
|  *	the duration value. | ||||
|  * | ||||
|  * @testmode_cmd: run a test mode command | ||||
|  * | ||||
|  * @set_pmksa: Cache a PMKID for a BSSID. This is mostly useful for fullmac | ||||
| @ -1123,6 +1132,16 @@ struct cfg80211_ops { | ||||
| 			     struct cfg80211_pmksa *pmksa); | ||||
| 	int	(*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); | ||||
| 
 | ||||
| 	int	(*remain_on_channel)(struct wiphy *wiphy, | ||||
| 				     struct net_device *dev, | ||||
| 				     struct ieee80211_channel *chan, | ||||
| 				     enum nl80211_channel_type channel_type, | ||||
| 				     unsigned int duration, | ||||
| 				     u64 *cookie); | ||||
| 	int	(*cancel_remain_on_channel)(struct wiphy *wiphy, | ||||
| 					    struct net_device *dev, | ||||
| 					    u64 cookie); | ||||
| 
 | ||||
| 	/* some temporary stuff to finish wext */ | ||||
| 	int	(*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, | ||||
| 				  bool enabled, int timeout); | ||||
| @ -2147,5 +2166,45 @@ void cfg80211_roamed(struct net_device *dev, const u8 *bssid, | ||||
| void cfg80211_disconnected(struct net_device *dev, u16 reason, | ||||
| 			   u8 *ie, size_t ie_len, gfp_t gfp); | ||||
| 
 | ||||
| /**
 | ||||
|  * cfg80211_ready_on_channel - notification of remain_on_channel start | ||||
|  * @dev: network device | ||||
|  * @cookie: the request cookie | ||||
|  * @chan: The current channel (from remain_on_channel request) | ||||
|  * @channel_type: Channel type | ||||
|  * @duration: Duration in milliseconds that the driver intents to remain on the | ||||
|  *	channel | ||||
|  * @gfp: allocation flags | ||||
|  */ | ||||
| void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, | ||||
| 			       struct ieee80211_channel *chan, | ||||
| 			       enum nl80211_channel_type channel_type, | ||||
| 			       unsigned int duration, gfp_t gfp); | ||||
| 
 | ||||
| /**
 | ||||
|  * cfg80211_remain_on_channel_expired - remain_on_channel duration expired | ||||
|  * @dev: network device | ||||
|  * @cookie: the request cookie | ||||
|  * @chan: The current channel (from remain_on_channel request) | ||||
|  * @channel_type: Channel type | ||||
|  * @gfp: allocation flags | ||||
|  */ | ||||
| void cfg80211_remain_on_channel_expired(struct net_device *dev, | ||||
| 					u64 cookie, | ||||
| 					struct ieee80211_channel *chan, | ||||
| 					enum nl80211_channel_type channel_type, | ||||
| 					gfp_t gfp); | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * cfg80211_new_sta - notify userspace about station | ||||
|  * | ||||
|  * @dev: the netdev | ||||
|  * @mac_addr: the station's address | ||||
|  * @sinfo: the station information | ||||
|  * @gfp: allocation flags | ||||
|  */ | ||||
| void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | ||||
| 		      struct station_info *sinfo, gfp_t gfp); | ||||
| 
 | ||||
| #endif /* __NET_CFG80211_H */ | ||||
|  | ||||
| @ -547,7 +547,6 @@ enum mac80211_rx_flags { | ||||
|  *	unspecified depending on the hardware capabilities flags | ||||
|  *	@IEEE80211_HW_SIGNAL_* | ||||
|  * @noise: noise when receiving this frame, in dBm. | ||||
|  * @qual: overall signal quality indication, in percent (0-100). | ||||
|  * @antenna: antenna used | ||||
|  * @rate_idx: index of data rate into band's supported rates or MCS index if | ||||
|  *	HT rates are use (RX_FLAG_HT) | ||||
| @ -559,7 +558,6 @@ struct ieee80211_rx_status { | ||||
| 	int freq; | ||||
| 	int signal; | ||||
| 	int noise; | ||||
| 	int __deprecated qual; | ||||
| 	int antenna; | ||||
| 	int rate_idx; | ||||
| 	int flag; | ||||
| @ -701,33 +699,6 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * struct ieee80211_if_init_conf - initial configuration of an interface | ||||
|  * | ||||
|  * @vif: pointer to a driver-use per-interface structure. The pointer | ||||
|  *	itself is also used for various functions including | ||||
|  *	ieee80211_beacon_get() and ieee80211_get_buffered_bc(). | ||||
|  * @type: one of &enum nl80211_iftype constants. Determines the type of | ||||
|  *	added/removed interface. | ||||
|  * @mac_addr: pointer to MAC address of the interface. This pointer is valid | ||||
|  *	until the interface is removed (i.e. it cannot be used after | ||||
|  *	remove_interface() callback was called for this interface). | ||||
|  * | ||||
|  * This structure is used in add_interface() and remove_interface() | ||||
|  * callbacks of &struct ieee80211_hw. | ||||
|  * | ||||
|  * When you allow multiple interfaces to be added to your PHY, take care | ||||
|  * that the hardware can actually handle multiple MAC addresses. However, | ||||
|  * also take care that when there's no interface left with mac_addr != %NULL | ||||
|  * you remove the MAC address from the device to avoid acknowledging packets | ||||
|  * in pure monitor mode. | ||||
|  */ | ||||
| struct ieee80211_if_init_conf { | ||||
| 	enum nl80211_iftype type; | ||||
| 	struct ieee80211_vif *vif; | ||||
| 	void *mac_addr; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * enum ieee80211_key_alg - key algorithm | ||||
|  * @ALG_WEP: WEP40 or WEP104 | ||||
| @ -1410,7 +1381,7 @@ enum ieee80211_ampdu_mlme_action { | ||||
|  *	When the device is started it should not have a MAC address | ||||
|  *	to avoid acknowledging frames before a non-monitor device | ||||
|  *	is added. | ||||
|  *	Must be implemented. | ||||
|  *	Must be implemented and can sleep. | ||||
|  * | ||||
|  * @stop: Called after last netdevice attached to the hardware | ||||
|  *	is disabled. This should turn off the hardware (at least | ||||
| @ -1418,7 +1389,7 @@ enum ieee80211_ampdu_mlme_action { | ||||
|  *	May be called right after add_interface if that rejects | ||||
|  *	an interface. If you added any work onto the mac80211 workqueue | ||||
|  *	you should ensure to cancel it on this callback. | ||||
|  *	Must be implemented. | ||||
|  *	Must be implemented and can sleep. | ||||
|  * | ||||
|  * @add_interface: Called when a netdevice attached to the hardware is | ||||
|  *	enabled. Because it is not called for monitor mode devices, @start | ||||
| @ -1428,7 +1399,7 @@ enum ieee80211_ampdu_mlme_action { | ||||
|  *	interface is given in the conf parameter. | ||||
|  *	The callback may refuse to add an interface by returning a | ||||
|  *	negative error code (which will be seen in userspace.) | ||||
|  *	Must be implemented. | ||||
|  *	Must be implemented and can sleep. | ||||
|  * | ||||
|  * @remove_interface: Notifies a driver that an interface is going down. | ||||
|  *	The @stop callback is called after this if it is the last interface | ||||
| @ -1437,19 +1408,20 @@ enum ieee80211_ampdu_mlme_action { | ||||
|  *	must be cleared so the device no longer acknowledges packets, | ||||
|  *	the mac_addr member of the conf structure is, however, set to the | ||||
|  *	MAC address of the device going away. | ||||
|  *	Hence, this callback must be implemented. | ||||
|  *	Hence, this callback must be implemented. It can sleep. | ||||
|  * | ||||
|  * @config: Handler for configuration requests. IEEE 802.11 code calls this | ||||
|  *	function to change hardware configuration, e.g., channel. | ||||
|  *	This function should never fail but returns a negative error code | ||||
|  *	if it does. | ||||
|  *	if it does. The callback can sleep. | ||||
|  * | ||||
|  * @bss_info_changed: Handler for configuration requests related to BSS | ||||
|  *	parameters that may vary during BSS's lifespan, and may affect low | ||||
|  *	level driver (e.g. assoc/disassoc status, erp parameters). | ||||
|  *	This function should not be used if no BSS has been set, unless | ||||
|  *	for association indication. The @changed parameter indicates which | ||||
|  *	of the bss parameters has changed when a call is made. | ||||
|  *	of the bss parameters has changed when a call is made. The callback | ||||
|  *	can sleep. | ||||
|  * | ||||
|  * @prepare_multicast: Prepare for multicast filter configuration. | ||||
|  *	This callback is optional, and its return value is passed | ||||
| @ -1457,20 +1429,22 @@ enum ieee80211_ampdu_mlme_action { | ||||
|  * | ||||
|  * @configure_filter: Configure the device's RX filter. | ||||
|  *	See the section "Frame filtering" for more information. | ||||
|  *	This callback must be implemented. | ||||
|  *	This callback must be implemented and can sleep. | ||||
|  * | ||||
|  * @set_tim: Set TIM bit. mac80211 calls this function when a TIM bit | ||||
|  * 	must be set or cleared for a given STA. Must be atomic. | ||||
|  * | ||||
|  * @set_key: See the section "Hardware crypto acceleration" | ||||
|  *	This callback can sleep, and is only called between add_interface | ||||
|  *	and remove_interface calls, i.e. while the given virtual interface | ||||
|  *	This callback is only called between add_interface and | ||||
|  *	remove_interface calls, i.e. while the given virtual interface | ||||
|  *	is enabled. | ||||
|  *	Returns a negative error code if the key can't be added. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @update_tkip_key: See the section "Hardware crypto acceleration" | ||||
|  * 	This callback will be called in the context of Rx. Called for drivers | ||||
|  * 	which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @hw_scan: Ask the hardware to service the scan request, no need to start | ||||
|  *	the scan state machine in stack. The scan must honour the channel | ||||
| @ -1484,21 +1458,28 @@ enum ieee80211_ampdu_mlme_action { | ||||
|  *	When the scan finishes, ieee80211_scan_completed() must be called; | ||||
|  *	note that it also must be called when the scan cannot finish due to | ||||
|  *	any error unless this callback returned a negative error code. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @sw_scan_start: Notifier function that is called just before a software scan | ||||
|  *	is started. Can be NULL, if the driver doesn't need this notification. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @sw_scan_complete: Notifier function that is called just after a software scan | ||||
|  *	finished. Can be NULL, if the driver doesn't need this notification. | ||||
|  * @sw_scan_complete: Notifier function that is called just after a | ||||
|  *	software scan finished. Can be NULL, if the driver doesn't need | ||||
|  *	this notification. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @get_stats: Return low-level statistics. | ||||
|  * 	Returns zero if statistics are available. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @get_tkip_seq: If your device implements TKIP encryption in hardware this | ||||
|  *	callback should be provided to read the TKIP transmit IVs (both IV32 | ||||
|  *	and IV16) for the given key from hardware. | ||||
|  *	The callback must be atomic. | ||||
|  * | ||||
|  * @set_rts_threshold: Configuration of RTS threshold (if device needs it) | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @sta_notify: Notifies low level driver about addition, removal or power | ||||
|  *	state transition of an associated station, AP,  IBSS/WDS/mesh peer etc. | ||||
| @ -1507,30 +1488,36 @@ enum ieee80211_ampdu_mlme_action { | ||||
|  * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), | ||||
|  *	bursting) for a hardware TX queue. | ||||
|  *	Returns a negative error code on failure. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @get_tx_stats: Get statistics of the current TX queue status. This is used | ||||
|  *	to get number of currently queued packets (queue length), maximum queue | ||||
|  *	size (limit), and total number of packets sent using each TX queue | ||||
|  *	(count). The 'stats' pointer points to an array that has hw->queues | ||||
|  *	items. | ||||
|  *	The callback must be atomic. | ||||
|  * | ||||
|  * @get_tsf: Get the current TSF timer value from firmware/hardware. Currently, | ||||
|  *	this is only used for IBSS mode BSSID merging and debugging. Is not a | ||||
|  *	required function. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @set_tsf: Set the TSF timer to the specified value in the firmware/hardware. | ||||
|  *      Currently, this is only used for IBSS mode debugging. Is not a | ||||
|  *	required function. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @reset_tsf: Reset the TSF timer and allow firmware/hardware to synchronize | ||||
|  *	with other STAs in the IBSS. This is only used in IBSS mode. This | ||||
|  *	function is optional if the firmware/hardware takes full care of | ||||
|  *	TSF synchronization. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @tx_last_beacon: Determine whether the last IBSS beacon was sent by us. | ||||
|  *	This is needed only for IBSS mode and the result of this function is | ||||
|  *	used to determine whether to reply to Probe Requests. | ||||
|  *	Returns non-zero if this device sent the last beacon. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @ampdu_action: Perform a certain A-MPDU action | ||||
|  * 	The RA/TID combination determines the destination and TID we want | ||||
| @ -1539,21 +1526,28 @@ enum ieee80211_ampdu_mlme_action { | ||||
|  * 	is the first frame we expect to perform the action on. Notice | ||||
|  * 	that TX/RX_STOP can pass NULL for this parameter. | ||||
|  *	Returns a negative error code on failure. | ||||
|  *	The callback must be atomic. | ||||
|  * | ||||
|  * @rfkill_poll: Poll rfkill hardware state. If you need this, you also | ||||
|  *	need to set wiphy->rfkill_poll to %true before registration, | ||||
|  *	and need to call wiphy_rfkill_set_hw_state() in the callback. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @testmode_cmd: Implement a cfg80211 test mode command. | ||||
|  *	The callback can sleep. | ||||
|  * | ||||
|  * @flush: Flush all pending frames from the hardware queue, making sure | ||||
|  *	that the hardware queues are empty. If the parameter @drop is set | ||||
|  *	to %true, pending frames may be dropped. The callback can sleep. | ||||
|  */ | ||||
| struct ieee80211_ops { | ||||
| 	int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); | ||||
| 	int (*start)(struct ieee80211_hw *hw); | ||||
| 	void (*stop)(struct ieee80211_hw *hw); | ||||
| 	int (*add_interface)(struct ieee80211_hw *hw, | ||||
| 			     struct ieee80211_if_init_conf *conf); | ||||
| 			     struct ieee80211_vif *vif); | ||||
| 	void (*remove_interface)(struct ieee80211_hw *hw, | ||||
| 				 struct ieee80211_if_init_conf *conf); | ||||
| 				 struct ieee80211_vif *vif); | ||||
| 	int (*config)(struct ieee80211_hw *hw, u32 changed); | ||||
| 	void (*bss_info_changed)(struct ieee80211_hw *hw, | ||||
| 				 struct ieee80211_vif *vif, | ||||
| @ -1601,6 +1595,7 @@ struct ieee80211_ops { | ||||
| #ifdef CONFIG_NL80211_TESTMODE | ||||
| 	int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); | ||||
| #endif | ||||
| 	void (*flush)(struct ieee80211_hw *hw, bool drop); | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
| @ -1840,7 +1835,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, | ||||
| /**
 | ||||
|  * ieee80211_beacon_get_tim - beacon generation function | ||||
|  * @hw: pointer obtained from ieee80211_alloc_hw(). | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||||
|  * @tim_offset: pointer to variable that will receive the TIM IE offset. | ||||
|  *	Set to 0 if invalid (in non-AP modes). | ||||
|  * @tim_length: pointer to variable that will receive the TIM IE length, | ||||
| @ -1868,7 +1863,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, | ||||
| /**
 | ||||
|  * ieee80211_beacon_get - beacon generation function | ||||
|  * @hw: pointer obtained from ieee80211_alloc_hw(). | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||||
|  * | ||||
|  * See ieee80211_beacon_get_tim(). | ||||
|  */ | ||||
| @ -1881,7 +1876,7 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, | ||||
| /**
 | ||||
|  * ieee80211_rts_get - RTS frame generation function | ||||
|  * @hw: pointer obtained from ieee80211_alloc_hw(). | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||||
|  * @frame: pointer to the frame that is going to be protected by the RTS. | ||||
|  * @frame_len: the frame length (in octets). | ||||
|  * @frame_txctl: &struct ieee80211_tx_info of the frame. | ||||
| @ -1900,7 +1895,7 @@ void ieee80211_rts_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | ||||
| /**
 | ||||
|  * ieee80211_rts_duration - Get the duration field for an RTS frame | ||||
|  * @hw: pointer obtained from ieee80211_alloc_hw(). | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||||
|  * @frame_len: the length of the frame that is going to be protected by the RTS. | ||||
|  * @frame_txctl: &struct ieee80211_tx_info of the frame. | ||||
|  * | ||||
| @ -1915,7 +1910,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, | ||||
| /**
 | ||||
|  * ieee80211_ctstoself_get - CTS-to-self frame generation function | ||||
|  * @hw: pointer obtained from ieee80211_alloc_hw(). | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||||
|  * @frame: pointer to the frame that is going to be protected by the CTS-to-self. | ||||
|  * @frame_len: the frame length (in octets). | ||||
|  * @frame_txctl: &struct ieee80211_tx_info of the frame. | ||||
| @ -1935,7 +1930,7 @@ void ieee80211_ctstoself_get(struct ieee80211_hw *hw, | ||||
| /**
 | ||||
|  * ieee80211_ctstoself_duration - Get the duration field for a CTS-to-self frame | ||||
|  * @hw: pointer obtained from ieee80211_alloc_hw(). | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||||
|  * @frame_len: the length of the frame that is going to be protected by the CTS-to-self. | ||||
|  * @frame_txctl: &struct ieee80211_tx_info of the frame. | ||||
|  * | ||||
| @ -1951,7 +1946,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, | ||||
| /**
 | ||||
|  * ieee80211_generic_frame_duration - Calculate the duration field for a frame | ||||
|  * @hw: pointer obtained from ieee80211_alloc_hw(). | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||||
|  * @frame_len: the length of the frame. | ||||
|  * @rate: the rate at which the frame is going to be transmitted. | ||||
|  * | ||||
| @ -1966,7 +1961,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, | ||||
| /**
 | ||||
|  * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames | ||||
|  * @hw: pointer as obtained from ieee80211_alloc_hw(). | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||||
|  * | ||||
|  * Function for accessing buffered broadcast and multicast frames. If | ||||
|  * hardware/firmware does not implement buffering of broadcast/multicast | ||||
| @ -2134,7 +2129,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *sta, u16 tid); | ||||
| 
 | ||||
| /**
 | ||||
|  * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback | ||||
|  * @ra: receiver address of the BA session recipient. | ||||
|  * @tid: the TID to BA on. | ||||
|  * | ||||
| @ -2145,7 +2140,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); | ||||
| 
 | ||||
| /**
 | ||||
|  * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback | ||||
|  * @ra: receiver address of the BA session recipient. | ||||
|  * @tid: the TID to BA on. | ||||
|  * | ||||
| @ -2173,7 +2168,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid, | ||||
| 
 | ||||
| /**
 | ||||
|  * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback | ||||
|  * @ra: receiver address of the BA session recipient. | ||||
|  * @tid: the desired TID to BA on. | ||||
|  * | ||||
| @ -2184,7 +2179,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); | ||||
| 
 | ||||
| /**
 | ||||
|  * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback | ||||
|  * @ra: receiver address of the BA session recipient. | ||||
|  * @tid: the desired TID to BA on. | ||||
|  * | ||||
| @ -2263,7 +2258,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, | ||||
| /**
 | ||||
|  * ieee80211_beacon_loss - inform hardware does not receive beacons | ||||
|  * | ||||
|  * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. | ||||
|  * @vif: &struct ieee80211_vif pointer from the add_interface callback. | ||||
|  * | ||||
|  * When beacon filtering is enabled with IEEE80211_HW_BEACON_FILTERING and | ||||
|  * IEEE80211_CONF_PS is set, the driver needs to inform whenever the | ||||
|  | ||||
| @ -6,10 +6,10 @@ mac80211-y := \ | ||||
| 	sta_info.o \
 | ||||
| 	wep.o \
 | ||||
| 	wpa.o \
 | ||||
| 	scan.o \
 | ||||
| 	scan.o offchannel.o \
 | ||||
| 	ht.o agg-tx.o agg-rx.o \
 | ||||
| 	ibss.o \
 | ||||
| 	mlme.o \
 | ||||
| 	mlme.o work.o \
 | ||||
| 	iface.o \
 | ||||
| 	rate.o \
 | ||||
| 	michael.o \
 | ||||
|  | ||||
| @ -78,17 +78,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, | ||||
| 				  enum nl80211_iftype type, u32 *flags, | ||||
| 				  struct vif_params *params) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (netif_running(dev)) | ||||
| 	if (ieee80211_sdata_running(sdata)) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	if (!nl80211_params_check(type, params)) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||
| 
 | ||||
| 	ret = ieee80211_if_change_type(sdata, type); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| @ -1345,7 +1343,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	ap = sdata->u.mgd.associated->cbss.bssid; | ||||
| 	ap = sdata->u.mgd.associated->bssid; | ||||
| 
 | ||||
| 	if (smps_mode == IEEE80211_SMPS_AUTOMATIC) { | ||||
| 		if (sdata->u.mgd.powersave) | ||||
| @ -1443,6 +1441,28 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, | ||||
| 	return -EINVAL; | ||||
| } | ||||
| 
 | ||||
| static int ieee80211_remain_on_channel(struct wiphy *wiphy, | ||||
| 				       struct net_device *dev, | ||||
| 				       struct ieee80211_channel *chan, | ||||
| 				       enum nl80211_channel_type channel_type, | ||||
| 				       unsigned int duration, | ||||
| 				       u64 *cookie) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||
| 
 | ||||
| 	return ieee80211_wk_remain_on_channel(sdata, chan, channel_type, | ||||
| 					      duration, cookie); | ||||
| } | ||||
| 
 | ||||
| static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, | ||||
| 					      struct net_device *dev, | ||||
| 					      u64 cookie) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||
| 
 | ||||
| 	return ieee80211_wk_cancel_remain_on_channel(sdata, cookie); | ||||
| } | ||||
| 
 | ||||
| struct cfg80211_ops mac80211_config_ops = { | ||||
| 	.add_virtual_intf = ieee80211_add_iface, | ||||
| 	.del_virtual_intf = ieee80211_del_iface, | ||||
| @ -1489,4 +1509,6 @@ struct cfg80211_ops mac80211_config_ops = { | ||||
| 	CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) | ||||
| 	.set_power_mgmt = ieee80211_set_power_mgmt, | ||||
| 	.set_bitrate_mask = ieee80211_set_bitrate_mask, | ||||
| 	.remain_on_channel = ieee80211_remain_on_channel, | ||||
| 	.cancel_remain_on_channel = ieee80211_cancel_remain_on_channel, | ||||
| }; | ||||
|  | ||||
| @ -133,7 +133,6 @@ IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC); | ||||
| /* STA attributes */ | ||||
| IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC); | ||||
| IEEE80211_IF_FILE(aid, u.mgd.aid, DEC); | ||||
| IEEE80211_IF_FILE(capab, u.mgd.capab, HEX); | ||||
| 
 | ||||
| static int ieee80211_set_smps(struct ieee80211_sub_if_data *sdata, | ||||
| 			      enum ieee80211_smps_mode smps_mode) | ||||
| @ -270,7 +269,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) | ||||
| 
 | ||||
| 	DEBUGFS_ADD(bssid, sta); | ||||
| 	DEBUGFS_ADD(aid, sta); | ||||
| 	DEBUGFS_ADD(capab, sta); | ||||
| 	DEBUGFS_ADD_MODE(smps, 0600); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -14,6 +14,8 @@ static inline int drv_start(struct ieee80211_local *local) | ||||
| { | ||||
| 	int ret; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	local->started = true; | ||||
| 	smp_mb(); | ||||
| 	ret = local->ops->start(&local->hw); | ||||
| @ -23,6 +25,8 @@ static inline int drv_start(struct ieee80211_local *local) | ||||
| 
 | ||||
| static inline void drv_stop(struct ieee80211_local *local) | ||||
| { | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	local->ops->stop(&local->hw); | ||||
| 	trace_drv_stop(local); | ||||
| 
 | ||||
| @ -36,23 +40,33 @@ static inline void drv_stop(struct ieee80211_local *local) | ||||
| } | ||||
| 
 | ||||
| static inline int drv_add_interface(struct ieee80211_local *local, | ||||
| 				    struct ieee80211_if_init_conf *conf) | ||||
| 				    struct ieee80211_vif *vif) | ||||
| { | ||||
| 	int ret = local->ops->add_interface(&local->hw, conf); | ||||
| 	trace_drv_add_interface(local, vif_to_sdata(conf->vif), ret); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	ret = local->ops->add_interface(&local->hw, vif); | ||||
| 	trace_drv_add_interface(local, vif_to_sdata(vif), ret); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static inline void drv_remove_interface(struct ieee80211_local *local, | ||||
| 					struct ieee80211_if_init_conf *conf) | ||||
| 					struct ieee80211_vif *vif) | ||||
| { | ||||
| 	local->ops->remove_interface(&local->hw, conf); | ||||
| 	trace_drv_remove_interface(local, vif_to_sdata(conf->vif)); | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	local->ops->remove_interface(&local->hw, vif); | ||||
| 	trace_drv_remove_interface(local, vif_to_sdata(vif)); | ||||
| } | ||||
| 
 | ||||
| static inline int drv_config(struct ieee80211_local *local, u32 changed) | ||||
| { | ||||
| 	int ret = local->ops->config(&local->hw, changed); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	ret = local->ops->config(&local->hw, changed); | ||||
| 	trace_drv_config(local, changed, ret); | ||||
| 	return ret; | ||||
| } | ||||
| @ -62,6 +76,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, | ||||
| 					struct ieee80211_bss_conf *info, | ||||
| 					u32 changed) | ||||
| { | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->bss_info_changed) | ||||
| 		local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed); | ||||
| 	trace_drv_bss_info_changed(local, sdata, info, changed); | ||||
| @ -111,7 +127,11 @@ static inline int drv_set_key(struct ieee80211_local *local, | ||||
| 			      struct ieee80211_sta *sta, | ||||
| 			      struct ieee80211_key_conf *key) | ||||
| { | ||||
| 	int ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key); | ||||
| 	trace_drv_set_key(local, cmd, sdata, sta, key, ret); | ||||
| 	return ret; | ||||
| } | ||||
| @ -121,6 +141,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, | ||||
| 				       const u8 *address, u32 iv32, | ||||
| 				       u16 *phase1key) | ||||
| { | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->update_tkip_key) | ||||
| 		local->ops->update_tkip_key(&local->hw, conf, address, | ||||
| 					    iv32, phase1key); | ||||
| @ -130,13 +152,19 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local, | ||||
| static inline int drv_hw_scan(struct ieee80211_local *local, | ||||
| 			      struct cfg80211_scan_request *req) | ||||
| { | ||||
| 	int ret = local->ops->hw_scan(&local->hw, req); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	ret = local->ops->hw_scan(&local->hw, req); | ||||
| 	trace_drv_hw_scan(local, req, ret); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static inline void drv_sw_scan_start(struct ieee80211_local *local) | ||||
| { | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->sw_scan_start) | ||||
| 		local->ops->sw_scan_start(&local->hw); | ||||
| 	trace_drv_sw_scan_start(local); | ||||
| @ -144,6 +172,8 @@ static inline void drv_sw_scan_start(struct ieee80211_local *local) | ||||
| 
 | ||||
| static inline void drv_sw_scan_complete(struct ieee80211_local *local) | ||||
| { | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->sw_scan_complete) | ||||
| 		local->ops->sw_scan_complete(&local->hw); | ||||
| 	trace_drv_sw_scan_complete(local); | ||||
| @ -154,6 +184,8 @@ static inline int drv_get_stats(struct ieee80211_local *local, | ||||
| { | ||||
| 	int ret = -EOPNOTSUPP; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->get_stats) | ||||
| 		ret = local->ops->get_stats(&local->hw, stats); | ||||
| 	trace_drv_get_stats(local, stats, ret); | ||||
| @ -173,6 +205,9 @@ static inline int drv_set_rts_threshold(struct ieee80211_local *local, | ||||
| 					u32 value) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->set_rts_threshold) | ||||
| 		ret = local->ops->set_rts_threshold(&local->hw, value); | ||||
| 	trace_drv_set_rts_threshold(local, value, ret); | ||||
| @ -193,6 +228,9 @@ static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue, | ||||
| 			      const struct ieee80211_tx_queue_params *params) | ||||
| { | ||||
| 	int ret = -EOPNOTSUPP; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->conf_tx) | ||||
| 		ret = local->ops->conf_tx(&local->hw, queue, params); | ||||
| 	trace_drv_conf_tx(local, queue, params, ret); | ||||
| @ -210,6 +248,9 @@ static inline int drv_get_tx_stats(struct ieee80211_local *local, | ||||
| static inline u64 drv_get_tsf(struct ieee80211_local *local) | ||||
| { | ||||
| 	u64 ret = -1ULL; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->get_tsf) | ||||
| 		ret = local->ops->get_tsf(&local->hw); | ||||
| 	trace_drv_get_tsf(local, ret); | ||||
| @ -218,6 +259,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local) | ||||
| 
 | ||||
| static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) | ||||
| { | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->set_tsf) | ||||
| 		local->ops->set_tsf(&local->hw, tsf); | ||||
| 	trace_drv_set_tsf(local, tsf); | ||||
| @ -225,6 +268,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf) | ||||
| 
 | ||||
| static inline void drv_reset_tsf(struct ieee80211_local *local) | ||||
| { | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->reset_tsf) | ||||
| 		local->ops->reset_tsf(&local->hw); | ||||
| 	trace_drv_reset_tsf(local); | ||||
| @ -233,6 +278,9 @@ static inline void drv_reset_tsf(struct ieee80211_local *local) | ||||
| static inline int drv_tx_last_beacon(struct ieee80211_local *local) | ||||
| { | ||||
| 	int ret = 1; | ||||
| 
 | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->tx_last_beacon) | ||||
| 		ret = local->ops->tx_last_beacon(&local->hw); | ||||
| 	trace_drv_tx_last_beacon(local, ret); | ||||
| @ -256,7 +304,18 @@ static inline int drv_ampdu_action(struct ieee80211_local *local, | ||||
| 
 | ||||
| static inline void drv_rfkill_poll(struct ieee80211_local *local) | ||||
| { | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	if (local->ops->rfkill_poll) | ||||
| 		local->ops->rfkill_poll(&local->hw); | ||||
| } | ||||
| 
 | ||||
| static inline void drv_flush(struct ieee80211_local *local, bool drop) | ||||
| { | ||||
| 	might_sleep(); | ||||
| 
 | ||||
| 	trace_drv_flush(local, drop); | ||||
| 	if (local->ops->flush) | ||||
| 		local->ops->flush(&local->hw, drop); | ||||
| } | ||||
| #endif /* __MAC80211_DRIVER_OPS */ | ||||
|  | ||||
| @ -690,6 +690,27 @@ TRACE_EVENT(drv_ampdu_action, | ||||
| 		LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret | ||||
| 	) | ||||
| ); | ||||
| 
 | ||||
| TRACE_EVENT(drv_flush, | ||||
| 	TP_PROTO(struct ieee80211_local *local, bool drop), | ||||
| 
 | ||||
| 	TP_ARGS(local, drop), | ||||
| 
 | ||||
| 	TP_STRUCT__entry( | ||||
| 		LOCAL_ENTRY | ||||
| 		__field(bool, drop) | ||||
| 	), | ||||
| 
 | ||||
| 	TP_fast_assign( | ||||
| 		LOCAL_ASSIGN; | ||||
| 		__entry->drop = drop; | ||||
| 	), | ||||
| 
 | ||||
| 	TP_printk( | ||||
| 		LOCAL_PR_FMT " drop:%d", | ||||
| 		LOCAL_PR_ARG, __entry->drop | ||||
| 	) | ||||
| ); | ||||
| #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ | ||||
| 
 | ||||
| #undef TRACE_INCLUDE_PATH | ||||
|  | ||||
| @ -187,15 +187,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||||
| static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||||
| 				    struct ieee80211_bss *bss) | ||||
| { | ||||
| 	struct cfg80211_bss *cbss = | ||||
| 		container_of((void *)bss, struct cfg80211_bss, priv); | ||||
| 	struct ieee80211_supported_band *sband; | ||||
| 	u32 basic_rates; | ||||
| 	int i, j; | ||||
| 	u16 beacon_int = bss->cbss.beacon_interval; | ||||
| 	u16 beacon_int = cbss->beacon_interval; | ||||
| 
 | ||||
| 	if (beacon_int < 10) | ||||
| 		beacon_int = 10; | ||||
| 
 | ||||
| 	sband = sdata->local->hw.wiphy->bands[bss->cbss.channel->band]; | ||||
| 	sband = sdata->local->hw.wiphy->bands[cbss->channel->band]; | ||||
| 
 | ||||
| 	basic_rates = 0; | ||||
| 
 | ||||
| @ -212,12 +214,12 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	__ieee80211_sta_join_ibss(sdata, bss->cbss.bssid, | ||||
| 	__ieee80211_sta_join_ibss(sdata, cbss->bssid, | ||||
| 				  beacon_int, | ||||
| 				  bss->cbss.channel, | ||||
| 				  cbss->channel, | ||||
| 				  basic_rates, | ||||
| 				  bss->cbss.capability, | ||||
| 				  bss->cbss.tsf); | ||||
| 				  cbss->capability, | ||||
| 				  cbss->tsf); | ||||
| } | ||||
| 
 | ||||
| static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||||
| @ -229,6 +231,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	int freq; | ||||
| 	struct cfg80211_bss *cbss; | ||||
| 	struct ieee80211_bss *bss; | ||||
| 	struct sta_info *sta; | ||||
| 	struct ieee80211_channel *channel; | ||||
| @ -283,8 +286,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||||
| 	if (!bss) | ||||
| 		return; | ||||
| 
 | ||||
| 	cbss = container_of((void *)bss, struct cfg80211_bss, priv); | ||||
| 
 | ||||
| 	/* was just updated in ieee80211_bss_info_update */ | ||||
| 	beacon_timestamp = bss->cbss.tsf; | ||||
| 	beacon_timestamp = cbss->tsf; | ||||
| 
 | ||||
| 	/* check if we need to merge IBSS */ | ||||
| 
 | ||||
| @ -297,11 +302,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||||
| 		goto put_bss; | ||||
| 
 | ||||
| 	/* not an IBSS */ | ||||
| 	if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS)) | ||||
| 	if (!(cbss->capability & WLAN_CAPABILITY_IBSS)) | ||||
| 		goto put_bss; | ||||
| 
 | ||||
| 	/* different channel */ | ||||
| 	if (bss->cbss.channel != local->oper_channel) | ||||
| 	if (cbss->channel != local->oper_channel) | ||||
| 		goto put_bss; | ||||
| 
 | ||||
| 	/* different SSID */ | ||||
| @ -311,7 +316,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||||
| 		goto put_bss; | ||||
| 
 | ||||
| 	/* same BSSID */ | ||||
| 	if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) | ||||
| 	if (memcmp(cbss->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) | ||||
| 		goto put_bss; | ||||
| 
 | ||||
| 	if (rx_status->flag & RX_FLAG_TSFT) { | ||||
| @ -382,6 +387,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | ||||
| struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||||
| 					u8 *bssid,u8 *addr, u32 supp_rates) | ||||
| { | ||||
| 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct sta_info *sta; | ||||
| 	int band = local->hw.conf.channel->band; | ||||
| @ -397,6 +403,9 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (compare_ether_addr(bssid, sdata->u.ibss.bssid)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| @ -514,7 +523,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | ||||
| { | ||||
| 	struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct ieee80211_bss *bss; | ||||
| 	struct cfg80211_bss *cbss; | ||||
| 	struct ieee80211_channel *chan = NULL; | ||||
| 	const u8 *bssid = NULL; | ||||
| 	int active_ibss; | ||||
| @ -538,21 +547,23 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | ||||
| 		chan = ifibss->channel; | ||||
| 	if (!is_zero_ether_addr(ifibss->bssid)) | ||||
| 		bssid = ifibss->bssid; | ||||
| 	bss = (void *)cfg80211_get_bss(local->hw.wiphy, chan, bssid, | ||||
| 				       ifibss->ssid, ifibss->ssid_len, | ||||
| 				       WLAN_CAPABILITY_IBSS | | ||||
| 				       WLAN_CAPABILITY_PRIVACY, | ||||
| 				       capability); | ||||
| 	cbss = cfg80211_get_bss(local->hw.wiphy, chan, bssid, | ||||
| 				ifibss->ssid, ifibss->ssid_len, | ||||
| 				WLAN_CAPABILITY_IBSS | WLAN_CAPABILITY_PRIVACY, | ||||
| 				capability); | ||||
| 
 | ||||
| 	if (bss) { | ||||
| 	if (cbss) { | ||||
| 		struct ieee80211_bss *bss; | ||||
| 
 | ||||
| 		bss = (void *)cbss->priv; | ||||
| #ifdef CONFIG_MAC80211_IBSS_DEBUG | ||||
| 		printk(KERN_DEBUG "   sta_find_ibss: selected %pM current " | ||||
| 		       "%pM\n", bss->cbss.bssid, ifibss->bssid); | ||||
| 		       "%pM\n", cbss->bssid, ifibss->bssid); | ||||
| #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | ||||
| 
 | ||||
| 		printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" | ||||
| 		       " based on configured SSID\n", | ||||
| 		       sdata->name, bss->cbss.bssid); | ||||
| 		       sdata->name, cbss->bssid); | ||||
| 
 | ||||
| 		ieee80211_sta_join_ibss(sdata, bss); | ||||
| 		ieee80211_rx_bss_put(local, bss); | ||||
| @ -744,7 +755,7 @@ static void ieee80211_ibss_work(struct work_struct *work) | ||||
| 	if (WARN_ON(local->suspended)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!netif_running(sdata->dev)) | ||||
| 	if (!ieee80211_sdata_running(sdata)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (local->scanning) | ||||
| @ -827,7 +838,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local) | ||||
| 
 | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||||
| 			continue; | ||||
|  | ||||
| @ -71,9 +71,6 @@ struct ieee80211_fragment_entry { | ||||
| 
 | ||||
| 
 | ||||
| struct ieee80211_bss { | ||||
| 	/* Yes, this is a hack */ | ||||
| 	struct cfg80211_bss cbss; | ||||
| 
 | ||||
| 	/* don't want to look up all the time */ | ||||
| 	size_t ssid_len; | ||||
| 	u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||||
| @ -227,31 +224,78 @@ struct mesh_preq_queue { | ||||
| 	u8 flags; | ||||
| }; | ||||
| 
 | ||||
| enum ieee80211_mgd_state { | ||||
| 	IEEE80211_MGD_STATE_IDLE, | ||||
| 	IEEE80211_MGD_STATE_PROBE, | ||||
| 	IEEE80211_MGD_STATE_AUTH, | ||||
| 	IEEE80211_MGD_STATE_ASSOC, | ||||
| enum ieee80211_work_type { | ||||
| 	IEEE80211_WORK_ABORT, | ||||
| 	IEEE80211_WORK_DIRECT_PROBE, | ||||
| 	IEEE80211_WORK_AUTH, | ||||
| 	IEEE80211_WORK_ASSOC, | ||||
| 	IEEE80211_WORK_REMAIN_ON_CHANNEL, | ||||
| }; | ||||
| 
 | ||||
| struct ieee80211_mgd_work { | ||||
| /**
 | ||||
|  * enum work_done_result - indicates what to do after work was done | ||||
|  * | ||||
|  * @WORK_DONE_DESTROY: This work item is no longer needed, destroy. | ||||
|  * @WORK_DONE_REQUEUE: This work item was reset to be reused, and | ||||
|  *	should be requeued. | ||||
|  */ | ||||
| enum work_done_result { | ||||
| 	WORK_DONE_DESTROY, | ||||
| 	WORK_DONE_REQUEUE, | ||||
| }; | ||||
| 
 | ||||
| struct ieee80211_work { | ||||
| 	struct list_head list; | ||||
| 	struct ieee80211_bss *bss; | ||||
| 	int ie_len; | ||||
| 	u8 prev_bssid[ETH_ALEN]; | ||||
| 	u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||||
| 	u8 ssid_len; | ||||
| 
 | ||||
| 	struct rcu_head rcu_head; | ||||
| 
 | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 
 | ||||
| 	enum work_done_result (*done)(struct ieee80211_work *wk, | ||||
| 				      struct sk_buff *skb); | ||||
| 
 | ||||
| 	struct ieee80211_channel *chan; | ||||
| 	enum nl80211_channel_type chan_type; | ||||
| 
 | ||||
| 	unsigned long timeout; | ||||
| 	enum ieee80211_mgd_state state; | ||||
| 	u16 auth_alg, auth_transaction; | ||||
| 	enum ieee80211_work_type type; | ||||
| 
 | ||||
| 	int tries; | ||||
| 	u8 filter_ta[ETH_ALEN]; | ||||
| 
 | ||||
| 	u8 key[WLAN_KEY_LEN_WEP104]; | ||||
| 	u8 key_len, key_idx; | ||||
| 	bool started; | ||||
| 
 | ||||
| 	union { | ||||
| 		struct { | ||||
| 			int tries; | ||||
| 			u16 algorithm, transaction; | ||||
| 			u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||||
| 			u8 ssid_len; | ||||
| 			u8 key[WLAN_KEY_LEN_WEP104]; | ||||
| 			u8 key_len, key_idx; | ||||
| 			bool privacy; | ||||
| 		} probe_auth; | ||||
| 		struct { | ||||
| 			struct cfg80211_bss *bss; | ||||
| 			const u8 *supp_rates; | ||||
| 			const u8 *ht_information_ie; | ||||
| 			enum ieee80211_smps_mode smps; | ||||
| 			int tries; | ||||
| 			u16 capability; | ||||
| 			u8 prev_bssid[ETH_ALEN]; | ||||
| 			u8 ssid[IEEE80211_MAX_SSID_LEN]; | ||||
| 			u8 ssid_len; | ||||
| 			u8 supp_rates_len; | ||||
| 			bool wmm_used, use_11n; | ||||
| 		} assoc; | ||||
| 		struct { | ||||
| 			u32 duration; | ||||
| 			bool started; | ||||
| 		} remain; | ||||
| 	}; | ||||
| 
 | ||||
| 	int ie_len; | ||||
| 	/* must be last */ | ||||
| 	u8 ie[0]; /* for auth or assoc frame, not probe */ | ||||
| 	u8 ie[0]; | ||||
| }; | ||||
| 
 | ||||
| /* flags used in struct ieee80211_if_managed.flags */ | ||||
| @ -259,17 +303,11 @@ enum ieee80211_sta_flags { | ||||
| 	IEEE80211_STA_BEACON_POLL	= BIT(0), | ||||
| 	IEEE80211_STA_CONNECTION_POLL	= BIT(1), | ||||
| 	IEEE80211_STA_CONTROL_PORT	= BIT(2), | ||||
| 	IEEE80211_STA_WMM_ENABLED	= BIT(3), | ||||
| 	IEEE80211_STA_DISABLE_11N	= BIT(4), | ||||
| 	IEEE80211_STA_CSA_RECEIVED	= BIT(5), | ||||
| 	IEEE80211_STA_MFP_ENABLED	= BIT(6), | ||||
| }; | ||||
| 
 | ||||
| /* flags for MLME request */ | ||||
| enum ieee80211_sta_request { | ||||
| 	IEEE80211_STA_REQ_SCAN, | ||||
| }; | ||||
| 
 | ||||
| struct ieee80211_if_managed { | ||||
| 	struct timer_list timer; | ||||
| 	struct timer_list conn_mon_timer; | ||||
| @ -284,14 +322,11 @@ struct ieee80211_if_managed { | ||||
| 	int probe_send_count; | ||||
| 
 | ||||
| 	struct mutex mtx; | ||||
| 	struct ieee80211_bss *associated; | ||||
| 	struct ieee80211_mgd_work *old_associate_work; | ||||
| 	struct list_head work_list; | ||||
| 	struct cfg80211_bss *associated; | ||||
| 
 | ||||
| 	u8 bssid[ETH_ALEN]; | ||||
| 
 | ||||
| 	u16 aid; | ||||
| 	u16 capab; | ||||
| 
 | ||||
| 	struct sk_buff_head skb_queue; | ||||
| 
 | ||||
| @ -300,8 +335,6 @@ struct ieee80211_if_managed { | ||||
| 	enum ieee80211_smps_mode req_smps, /* requested smps mode */ | ||||
| 				 ap_smps; /* smps mode AP thinks we're in */ | ||||
| 
 | ||||
| 	unsigned long request; | ||||
| 
 | ||||
| 	unsigned int flags; | ||||
| 
 | ||||
| 	u32 beacon_crc; | ||||
| @ -567,6 +600,15 @@ struct ieee80211_local { | ||||
| 
 | ||||
| 	const struct ieee80211_ops *ops; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * work stuff, potentially off-channel (in the future) | ||||
| 	 */ | ||||
| 	struct mutex work_mtx; | ||||
| 	struct list_head work_list; | ||||
| 	struct timer_list work_timer; | ||||
| 	struct work_struct work_work; | ||||
| 	struct sk_buff_head work_skb_queue; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * private workqueue to mac80211. mac80211 makes this accessible | ||||
| 	 * via ieee80211_queue_work() | ||||
| @ -695,6 +737,10 @@ struct ieee80211_local { | ||||
| 	enum nl80211_channel_type oper_channel_type; | ||||
| 	struct ieee80211_channel *oper_channel, *csa_channel; | ||||
| 
 | ||||
| 	/* Temporary remain-on-channel for off-channel operations */ | ||||
| 	struct ieee80211_channel *tmp_channel; | ||||
| 	enum nl80211_channel_type tmp_channel_type; | ||||
| 
 | ||||
| 	/* SNMP counters */ | ||||
| 	/* dot11CountersTable */ | ||||
| 	u32 dot11TransmittedFragmentCount; | ||||
| @ -752,7 +798,7 @@ struct ieee80211_local { | ||||
| 	unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ | ||||
| 
 | ||||
| 	bool pspolling; | ||||
| 	bool scan_ps_enabled; | ||||
| 	bool offchannel_ps_enabled; | ||||
| 	/*
 | ||||
| 	 * PS can only be enabled when we have exactly one managed | ||||
| 	 * interface (and monitors) in PS, this then points there. | ||||
| @ -947,6 +993,12 @@ ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | ||||
| void ieee80211_rx_bss_put(struct ieee80211_local *local, | ||||
| 			  struct ieee80211_bss *bss); | ||||
| 
 | ||||
| /* off-channel helpers */ | ||||
| void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local); | ||||
| void ieee80211_offchannel_stop_station(struct ieee80211_local *local); | ||||
| void ieee80211_offchannel_return(struct ieee80211_local *local, | ||||
| 				 bool enable_beaconing); | ||||
| 
 | ||||
| /* interface handling */ | ||||
| int ieee80211_iface_init(void); | ||||
| void ieee80211_iface_exit(void); | ||||
| @ -960,6 +1012,11 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local); | ||||
| u32 __ieee80211_recalc_idle(struct ieee80211_local *local); | ||||
| void ieee80211_recalc_idle(struct ieee80211_local *local); | ||||
| 
 | ||||
| static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata) | ||||
| { | ||||
| 	return netif_running(sdata->dev); | ||||
| } | ||||
| 
 | ||||
| /* tx handling */ | ||||
| void ieee80211_clear_tx_pending(struct ieee80211_local *local); | ||||
| void ieee80211_tx_pending(unsigned long data); | ||||
| @ -1106,6 +1163,24 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata, | ||||
| void ieee80211_recalc_smps(struct ieee80211_local *local, | ||||
| 			   struct ieee80211_sub_if_data *forsdata); | ||||
| 
 | ||||
| size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||||
| 			  const u8 *ids, int n_ids, size_t offset); | ||||
| size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset); | ||||
| 
 | ||||
| /* internal work items */ | ||||
| void ieee80211_work_init(struct ieee80211_local *local); | ||||
| void ieee80211_add_work(struct ieee80211_work *wk); | ||||
| void free_work(struct ieee80211_work *wk); | ||||
| void ieee80211_work_purge(struct ieee80211_sub_if_data *sdata); | ||||
| ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, | ||||
| 					   struct sk_buff *skb); | ||||
| int ieee80211_wk_remain_on_channel(struct ieee80211_sub_if_data *sdata, | ||||
| 				   struct ieee80211_channel *chan, | ||||
| 				   enum nl80211_channel_type channel_type, | ||||
| 				   unsigned int duration, u64 *cookie); | ||||
| int ieee80211_wk_cancel_remain_on_channel( | ||||
| 	struct ieee80211_sub_if_data *sdata, u64 cookie); | ||||
| 
 | ||||
| #ifdef CONFIG_MAC80211_NOINLINE | ||||
| #define debug_noinline noinline | ||||
| #else | ||||
|  | ||||
| @ -65,7 +65,7 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr) | ||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (netif_running(dev)) | ||||
| 	if (ieee80211_sdata_running(sdata)) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	ret = eth_mac_addr(dev, addr); | ||||
| @ -96,7 +96,6 @@ static int ieee80211_open(struct net_device *dev) | ||||
| 	struct ieee80211_sub_if_data *nsdata; | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct sta_info *sta; | ||||
| 	struct ieee80211_if_init_conf conf; | ||||
| 	u32 changed = 0; | ||||
| 	int res; | ||||
| 	u32 hw_reconf_flags = 0; | ||||
| @ -111,7 +110,7 @@ static int ieee80211_open(struct net_device *dev) | ||||
| 	list_for_each_entry(nsdata, &local->interfaces, list) { | ||||
| 		struct net_device *ndev = nsdata->dev; | ||||
| 
 | ||||
| 		if (ndev != dev && netif_running(ndev)) { | ||||
| 		if (ndev != dev && ieee80211_sdata_running(nsdata)) { | ||||
| 			/*
 | ||||
| 			 * Allow only a single IBSS interface to be up at any | ||||
| 			 * time. This is restricted because beacon distribution | ||||
| @ -197,7 +196,7 @@ static int ieee80211_open(struct net_device *dev) | ||||
| 		struct net_device *ndev = nsdata->dev; | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * No need to check netif_running since we do not allow | ||||
| 		 * No need to check running since we do not allow | ||||
| 		 * it to start up with this invalid address. | ||||
| 		 */ | ||||
| 		if (compare_ether_addr(null_addr, ndev->dev_addr) == 0) { | ||||
| @ -248,10 +247,7 @@ static int ieee80211_open(struct net_device *dev) | ||||
| 		ieee80211_configure_filter(local); | ||||
| 		break; | ||||
| 	default: | ||||
| 		conf.vif = &sdata->vif; | ||||
| 		conf.type = sdata->vif.type; | ||||
| 		conf.mac_addr = sdata->vif.addr; | ||||
| 		res = drv_add_interface(local, &conf); | ||||
| 		res = drv_add_interface(local, &sdata->vif); | ||||
| 		if (res) | ||||
| 			goto err_stop; | ||||
| 
 | ||||
| @ -334,7 +330,7 @@ static int ieee80211_open(struct net_device *dev) | ||||
| 
 | ||||
| 	return 0; | ||||
|  err_del_interface: | ||||
| 	drv_remove_interface(local, &conf); | ||||
| 	drv_remove_interface(local, &sdata->vif); | ||||
|  err_stop: | ||||
| 	if (!local->open_count) | ||||
| 		drv_stop(local); | ||||
| @ -349,7 +345,6 @@ static int ieee80211_stop(struct net_device *dev) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct ieee80211_if_init_conf conf; | ||||
| 	struct sta_info *sta; | ||||
| 	unsigned long flags; | ||||
| 	struct sk_buff *skb, *tmp; | ||||
| @ -361,6 +356,11 @@ static int ieee80211_stop(struct net_device *dev) | ||||
| 	 */ | ||||
| 	netif_stop_queue(dev); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Purge work for this interface. | ||||
| 	 */ | ||||
| 	ieee80211_work_purge(sdata); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Now delete all active aggregation sessions. | ||||
| 	 */ | ||||
| @ -528,12 +528,9 @@ static int ieee80211_stop(struct net_device *dev) | ||||
| 				BSS_CHANGED_BEACON_ENABLED); | ||||
| 		} | ||||
| 
 | ||||
| 		conf.vif = &sdata->vif; | ||||
| 		conf.type = sdata->vif.type; | ||||
| 		conf.mac_addr = sdata->vif.addr; | ||||
| 		/* disable all keys for as long as this netdev is down */ | ||||
| 		ieee80211_disable_keys(sdata); | ||||
| 		drv_remove_interface(local, &conf); | ||||
| 		drv_remove_interface(local, &sdata->vif); | ||||
| 	} | ||||
| 
 | ||||
| 	sdata->bss = NULL; | ||||
| @ -756,7 +753,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, | ||||
| 	 * and goes into the requested mode. | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (netif_running(sdata->dev)) | ||||
| 	if (ieee80211_sdata_running(sdata)) | ||||
| 		return -EBUSY; | ||||
| 
 | ||||
| 	/* Purge and reset type-dependent state. */ | ||||
| @ -917,6 +914,8 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local) | ||||
| 	       wiphy_name(local->hw.wiphy)); | ||||
| #endif | ||||
| 
 | ||||
| 	drv_flush(local, false); | ||||
| 
 | ||||
| 	local->hw.conf.flags |= IEEE80211_CONF_IDLE; | ||||
| 	return IEEE80211_CONF_CHANGE_IDLE; | ||||
| } | ||||
| @ -926,16 +925,18 @@ u32 __ieee80211_recalc_idle(struct ieee80211_local *local) | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 	int count = 0; | ||||
| 
 | ||||
| 	if (!list_empty(&local->work_list)) | ||||
| 		return ieee80211_idle_off(local, "working"); | ||||
| 
 | ||||
| 	if (local->scanning) | ||||
| 		return ieee80211_idle_off(local, "scanning"); | ||||
| 
 | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 		/* do not count disabled managed interfaces */ | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_STATION && | ||||
| 		    !sdata->u.mgd.associated && | ||||
| 		    list_empty(&sdata->u.mgd.work_list)) | ||||
| 		    !sdata->u.mgd.associated) | ||||
| 			continue; | ||||
| 		/* do not count unused IBSS interfaces */ | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_ADHOC && | ||||
|  | ||||
| @ -443,7 +443,7 @@ void ieee80211_key_link(struct ieee80211_key *key, | ||||
| 	add_todo(old_key, KEY_FLAG_TODO_DELETE); | ||||
| 
 | ||||
| 	add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); | ||||
| 	if (netif_running(sdata->dev)) | ||||
| 	if (ieee80211_sdata_running(sdata)) | ||||
| 		add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD); | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&sdata->local->key_lock, flags); | ||||
| @ -509,7 +509,7 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) | ||||
| { | ||||
| 	ASSERT_RTNL(); | ||||
| 
 | ||||
| 	if (WARN_ON(!netif_running(sdata->dev))) | ||||
| 	if (WARN_ON(!ieee80211_sdata_running(sdata))) | ||||
| 		return; | ||||
| 
 | ||||
| 	ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD); | ||||
|  | ||||
| @ -107,6 +107,9 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) | ||||
| 	if (scan_chan) { | ||||
| 		chan = scan_chan; | ||||
| 		channel_type = NL80211_CHAN_NO_HT; | ||||
| 	} else if (local->tmp_channel) { | ||||
| 		chan = scan_chan = local->tmp_channel; | ||||
| 		channel_type = local->tmp_channel_type; | ||||
| 	} else { | ||||
| 		chan = local->oper_channel; | ||||
| 		channel_type = local->oper_channel_type; | ||||
| @ -212,7 +215,7 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, | ||||
| 	} | ||||
| 
 | ||||
| 	if (changed & BSS_CHANGED_BEACON_ENABLED) { | ||||
| 		if (local->quiescing || !netif_running(sdata->dev) || | ||||
| 		if (local->quiescing || !ieee80211_sdata_running(sdata) || | ||||
| 		    test_bit(SCAN_SW_SCANNING, &local->scanning)) { | ||||
| 			sdata->vif.bss_conf.enable_beacon = false; | ||||
| 		} else { | ||||
| @ -359,9 +362,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | ||||
| 			WIPHY_FLAG_4ADDR_STATION; | ||||
| 	wiphy->privid = mac80211_wiphy_privid; | ||||
| 
 | ||||
| 	/* Yes, putting cfg80211_bss into ieee80211_bss is a hack */ | ||||
| 	wiphy->bss_priv_size = sizeof(struct ieee80211_bss) - | ||||
| 			       sizeof(struct cfg80211_bss); | ||||
| 	wiphy->bss_priv_size = sizeof(struct ieee80211_bss); | ||||
| 
 | ||||
| 	local = wiphy_priv(wiphy); | ||||
| 
 | ||||
| @ -395,6 +396,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, | ||||
| 
 | ||||
| 	INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); | ||||
| 
 | ||||
| 	ieee80211_work_init(local); | ||||
| 
 | ||||
| 	INIT_WORK(&local->restart_work, ieee80211_restart_work); | ||||
| 
 | ||||
| 	INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter); | ||||
|  | ||||
| @ -645,7 +645,7 @@ static void ieee80211_mesh_work(struct work_struct *work) | ||||
| 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||||
| 	struct sk_buff *skb; | ||||
| 
 | ||||
| 	if (!netif_running(sdata->dev)) | ||||
| 	if (!ieee80211_sdata_running(sdata)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (local->scanning) | ||||
|  | ||||
							
								
								
									
										1087
									
								
								net/mac80211/mlme.c
									
									
									
									
									
								
							
							
						
						
									
										1087
									
								
								net/mac80211/mlme.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										168
									
								
								net/mac80211/offchannel.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								net/mac80211/offchannel.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,168 @@ | ||||
| /*
 | ||||
|  * Off-channel operation helpers | ||||
|  * | ||||
|  * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi> | ||||
|  * Copyright 2004, Instant802 Networks, Inc. | ||||
|  * Copyright 2005, Devicescape Software, Inc. | ||||
|  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz> | ||||
|  * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||||
|  * Copyright 2009	Johannes Berg <johannes@sipsolutions.net> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  */ | ||||
| #include <net/mac80211.h> | ||||
| #include "ieee80211_i.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * inform AP that we will go to sleep so that it will buffer the frames | ||||
|  * while we scan | ||||
|  */ | ||||
| static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 
 | ||||
| 	local->offchannel_ps_enabled = false; | ||||
| 
 | ||||
| 	/* FIXME: what to do when local->pspolling is true? */ | ||||
| 
 | ||||
| 	del_timer_sync(&local->dynamic_ps_timer); | ||||
| 	cancel_work_sync(&local->dynamic_ps_enable_work); | ||||
| 
 | ||||
| 	if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||||
| 		local->offchannel_ps_enabled = true; | ||||
| 		local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||||
| 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!(local->offchannel_ps_enabled) || | ||||
| 	    !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) | ||||
| 		/*
 | ||||
| 		 * If power save was enabled, no need to send a nullfunc | ||||
| 		 * frame because AP knows that we are sleeping. But if the | ||||
| 		 * hardware is creating the nullfunc frame for power save | ||||
| 		 * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not | ||||
| 		 * enabled) and power save was enabled, the firmware just | ||||
| 		 * sent a null frame with power save disabled. So we need | ||||
| 		 * to send a new nullfunc frame to inform the AP that we | ||||
| 		 * are again sleeping. | ||||
| 		 */ | ||||
| 		ieee80211_send_nullfunc(local, sdata, 1); | ||||
| } | ||||
| 
 | ||||
| /* inform AP that we are awake again, unless power save is enabled */ | ||||
| static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata) | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 
 | ||||
| 	if (!local->ps_sdata) | ||||
| 		ieee80211_send_nullfunc(local, sdata, 0); | ||||
| 	else if (local->offchannel_ps_enabled) { | ||||
| 		/*
 | ||||
| 		 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware | ||||
| 		 * will send a nullfunc frame with the powersave bit set | ||||
| 		 * even though the AP already knows that we are sleeping. | ||||
| 		 * This could be avoided by sending a null frame with power | ||||
| 		 * save bit disabled before enabling the power save, but | ||||
| 		 * this doesn't gain anything. | ||||
| 		 * | ||||
| 		 * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need | ||||
| 		 * to send a nullfunc frame because AP already knows that | ||||
| 		 * we are sleeping, let's just enable power save mode in | ||||
| 		 * hardware. | ||||
| 		 */ | ||||
| 		local->hw.conf.flags |= IEEE80211_CONF_PS; | ||||
| 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||||
| 	} else if (local->hw.conf.dynamic_ps_timeout > 0) { | ||||
| 		/*
 | ||||
| 		 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer | ||||
| 		 * had been running before leaving the operating channel, | ||||
| 		 * restart the timer now and send a nullfunc frame to inform | ||||
| 		 * the AP that we are awake. | ||||
| 		 */ | ||||
| 		ieee80211_send_nullfunc(local, sdata, 0); | ||||
| 		mod_timer(&local->dynamic_ps_timer, jiffies + | ||||
| 			  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ieee80211_offchannel_stop_beaconing(struct ieee80211_local *local) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 
 | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/* disable beaconing */ | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_AP || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||||
| 			ieee80211_bss_info_change_notify( | ||||
| 				sdata, BSS_CHANGED_BEACON_ENABLED); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * only handle non-STA interfaces here, STA interfaces | ||||
| 		 * are handled in ieee80211_offchannel_stop_station(), | ||||
| 		 * e.g., from the background scan state machine. | ||||
| 		 * | ||||
| 		 * In addition, do not stop monitor interface to allow it to be | ||||
| 		 * used from user space controlled off-channel operations. | ||||
| 		 */ | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_STATION && | ||||
| 		    sdata->vif.type != NL80211_IFTYPE_MONITOR) | ||||
| 			netif_stop_queue(sdata->dev); | ||||
| 	} | ||||
| 	mutex_unlock(&local->iflist_mtx); | ||||
| } | ||||
| 
 | ||||
| void ieee80211_offchannel_stop_station(struct ieee80211_local *local) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * notify the AP about us leaving the channel and stop all STA interfaces | ||||
| 	 */ | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||||
| 			netif_stop_queue(sdata->dev); | ||||
| 			if (sdata->u.mgd.associated) | ||||
| 				ieee80211_offchannel_ps_enable(sdata); | ||||
| 		} | ||||
| 	} | ||||
| 	mutex_unlock(&local->iflist_mtx); | ||||
| } | ||||
| 
 | ||||
| void ieee80211_offchannel_return(struct ieee80211_local *local, | ||||
| 				 bool enable_beaconing) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 
 | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/* Tell AP we're back */ | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||||
| 			if (sdata->u.mgd.associated) | ||||
| 				ieee80211_offchannel_ps_disable(sdata); | ||||
| 			netif_wake_queue(sdata->dev); | ||||
| 		} | ||||
| 
 | ||||
| 		/* re-enable beaconing */ | ||||
| 		if (enable_beaconing && | ||||
| 		    (sdata->vif.type == NL80211_IFTYPE_AP || | ||||
| 		     sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||||
| 		     sdata->vif.type == NL80211_IFTYPE_MESH_POINT)) | ||||
| 			ieee80211_bss_info_change_notify( | ||||
| 				sdata, BSS_CHANGED_BEACON_ENABLED); | ||||
| 	} | ||||
| 	mutex_unlock(&local->iflist_mtx); | ||||
| } | ||||
| @ -10,7 +10,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | ||||
| { | ||||
| 	struct ieee80211_local *local = hw_to_local(hw); | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 	struct ieee80211_if_init_conf conf; | ||||
| 	struct sta_info *sta; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| @ -93,17 +92,14 @@ int __ieee80211_suspend(struct ieee80211_hw *hw) | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/* disable beaconing */ | ||||
| 		ieee80211_bss_info_change_notify(sdata, | ||||
| 			BSS_CHANGED_BEACON_ENABLED); | ||||
| 
 | ||||
| 		conf.vif = &sdata->vif; | ||||
| 		conf.type = sdata->vif.type; | ||||
| 		conf.mac_addr = sdata->vif.addr; | ||||
| 		drv_remove_interface(local, &conf); | ||||
| 		drv_remove_interface(local, &sdata->vif); | ||||
| 	} | ||||
| 
 | ||||
| 	/* stop hardware - this must stop RX */ | ||||
|  | ||||
| @ -289,7 +289,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, | ||||
| 		if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (prev_dev) { | ||||
| @ -1945,6 +1945,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata = rx->sdata; | ||||
| 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data; | ||||
| 	ieee80211_rx_result rxs; | ||||
| 
 | ||||
| 	if (!(rx->flags & IEEE80211_RX_RA_MATCH)) | ||||
| 		return RX_DROP_MONITOR; | ||||
| @ -1952,6 +1953,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) | ||||
| 	if (ieee80211_drop_unencrypted(rx, mgmt->frame_control)) | ||||
| 		return RX_DROP_MONITOR; | ||||
| 
 | ||||
| 	rxs = ieee80211_work_rx_mgmt(rx->sdata, rx->skb); | ||||
| 	if (rxs != RX_CONTINUE) | ||||
| 		return rxs; | ||||
| 
 | ||||
| 	if (ieee80211_vif_is_mesh(&sdata->vif)) | ||||
| 		return ieee80211_mesh_rx_mgmt(sdata, rx->skb); | ||||
| 
 | ||||
| @ -2056,7 +2061,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, | ||||
| 	skb->protocol = htons(ETH_P_802_2); | ||||
| 
 | ||||
| 	list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_MONITOR || | ||||
| @ -2318,7 +2323,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | ||||
| 	} | ||||
| 	if (!found_sta) { | ||||
| 		list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||||
| 			if (!netif_running(sdata->dev)) | ||||
| 			if (!ieee80211_sdata_running(sdata)) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (sdata->vif.type == NL80211_IFTYPE_MONITOR || | ||||
|  | ||||
| @ -29,16 +29,19 @@ struct ieee80211_bss * | ||||
| ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq, | ||||
| 		     u8 *ssid, u8 ssid_len) | ||||
| { | ||||
| 	return (void *)cfg80211_get_bss(local->hw.wiphy, | ||||
| 					ieee80211_get_channel(local->hw.wiphy, | ||||
| 							      freq), | ||||
| 					bssid, ssid, ssid_len, | ||||
| 					0, 0); | ||||
| 	struct cfg80211_bss *cbss; | ||||
| 
 | ||||
| 	cbss = cfg80211_get_bss(local->hw.wiphy, | ||||
| 				ieee80211_get_channel(local->hw.wiphy, freq), | ||||
| 				bssid, ssid, ssid_len, 0, 0); | ||||
| 	if (!cbss) | ||||
| 		return NULL; | ||||
| 	return (void *)cbss->priv; | ||||
| } | ||||
| 
 | ||||
| static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) | ||||
| { | ||||
| 	struct ieee80211_bss *bss = (void *)cbss; | ||||
| 	struct ieee80211_bss *bss = (void *)cbss->priv; | ||||
| 
 | ||||
| 	kfree(bss_mesh_id(bss)); | ||||
| 	kfree(bss_mesh_cfg(bss)); | ||||
| @ -47,7 +50,9 @@ static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss) | ||||
| void ieee80211_rx_bss_put(struct ieee80211_local *local, | ||||
| 			  struct ieee80211_bss *bss) | ||||
| { | ||||
| 	cfg80211_put_bss((struct cfg80211_bss *)bss); | ||||
| 	if (!bss) | ||||
| 		return; | ||||
| 	cfg80211_put_bss(container_of((void *)bss, struct cfg80211_bss, priv)); | ||||
| } | ||||
| 
 | ||||
| struct ieee80211_bss * | ||||
| @ -59,6 +64,7 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | ||||
| 			  struct ieee80211_channel *channel, | ||||
| 			  bool beacon) | ||||
| { | ||||
| 	struct cfg80211_bss *cbss; | ||||
| 	struct ieee80211_bss *bss; | ||||
| 	int clen; | ||||
| 	s32 signal = 0; | ||||
| @ -68,13 +74,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | ||||
| 	else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) | ||||
| 		signal = (rx_status->signal * 100) / local->hw.max_signal; | ||||
| 
 | ||||
| 	bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel, | ||||
| 						mgmt, len, signal, GFP_ATOMIC); | ||||
| 	cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, | ||||
| 					 mgmt, len, signal, GFP_ATOMIC); | ||||
| 
 | ||||
| 	if (!bss) | ||||
| 	if (!cbss) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	bss->cbss.free_priv = ieee80211_rx_bss_free; | ||||
| 	cbss->free_priv = ieee80211_rx_bss_free; | ||||
| 	bss = (void *)cbss->priv; | ||||
| 
 | ||||
| 	/* save the ERP value so that it is available at association time */ | ||||
| 	if (elems->erp_info && elems->erp_info_len >= 1) { | ||||
| @ -220,82 +227,9 @@ static bool ieee80211_prep_hw_scan(struct ieee80211_local *local) | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * inform AP that we will go to sleep so that it will buffer the frames | ||||
|  * while we scan | ||||
|  */ | ||||
| static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata) | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 
 | ||||
| 	local->scan_ps_enabled = false; | ||||
| 
 | ||||
| 	/* FIXME: what to do when local->pspolling is true? */ | ||||
| 
 | ||||
| 	del_timer_sync(&local->dynamic_ps_timer); | ||||
| 	cancel_work_sync(&local->dynamic_ps_enable_work); | ||||
| 
 | ||||
| 	if (local->hw.conf.flags & IEEE80211_CONF_PS) { | ||||
| 		local->scan_ps_enabled = true; | ||||
| 		local->hw.conf.flags &= ~IEEE80211_CONF_PS; | ||||
| 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!(local->scan_ps_enabled) || | ||||
| 	    !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) | ||||
| 		/*
 | ||||
| 		 * If power save was enabled, no need to send a nullfunc | ||||
| 		 * frame because AP knows that we are sleeping. But if the | ||||
| 		 * hardware is creating the nullfunc frame for power save | ||||
| 		 * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not | ||||
| 		 * enabled) and power save was enabled, the firmware just | ||||
| 		 * sent a null frame with power save disabled. So we need | ||||
| 		 * to send a new nullfunc frame to inform the AP that we | ||||
| 		 * are again sleeping. | ||||
| 		 */ | ||||
| 		ieee80211_send_nullfunc(local, sdata, 1); | ||||
| } | ||||
| 
 | ||||
| /* inform AP that we are awake again, unless power save is enabled */ | ||||
| static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata) | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 
 | ||||
| 	if (!local->ps_sdata) | ||||
| 		ieee80211_send_nullfunc(local, sdata, 0); | ||||
| 	else if (local->scan_ps_enabled) { | ||||
| 		/*
 | ||||
| 		 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware | ||||
| 		 * will send a nullfunc frame with the powersave bit set | ||||
| 		 * even though the AP already knows that we are sleeping. | ||||
| 		 * This could be avoided by sending a null frame with power | ||||
| 		 * save bit disabled before enabling the power save, but | ||||
| 		 * this doesn't gain anything. | ||||
| 		 * | ||||
| 		 * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need | ||||
| 		 * to send a nullfunc frame because AP already knows that | ||||
| 		 * we are sleeping, let's just enable power save mode in | ||||
| 		 * hardware. | ||||
| 		 */ | ||||
| 		local->hw.conf.flags |= IEEE80211_CONF_PS; | ||||
| 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); | ||||
| 	} else if (local->hw.conf.dynamic_ps_timeout > 0) { | ||||
| 		/*
 | ||||
| 		 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer | ||||
| 		 * had been running before leaving the operating channel, | ||||
| 		 * restart the timer now and send a nullfunc frame to inform | ||||
| 		 * the AP that we are awake. | ||||
| 		 */ | ||||
| 		ieee80211_send_nullfunc(local, sdata, 0); | ||||
| 		mod_timer(&local->dynamic_ps_timer, jiffies + | ||||
| 			  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | ||||
| { | ||||
| 	struct ieee80211_local *local = hw_to_local(hw); | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 	bool was_hw_scan; | ||||
| 
 | ||||
| 	mutex_lock(&local->scan_mtx); | ||||
| @ -344,28 +278,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted) | ||||
| 
 | ||||
| 	drv_sw_scan_complete(local); | ||||
| 
 | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/* Tell AP we're back */ | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||||
| 			if (sdata->u.mgd.associated) { | ||||
| 				ieee80211_scan_ps_disable(sdata); | ||||
| 				netif_wake_queue(sdata->dev); | ||||
| 			} | ||||
| 		} else | ||||
| 			netif_wake_queue(sdata->dev); | ||||
| 
 | ||||
| 		/* re-enable beaconing */ | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_AP || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||||
| 			ieee80211_bss_info_change_notify( | ||||
| 				sdata, BSS_CHANGED_BEACON_ENABLED); | ||||
| 	} | ||||
| 	mutex_unlock(&local->iflist_mtx); | ||||
| 	ieee80211_offchannel_return(local, true); | ||||
| 
 | ||||
|  done: | ||||
| 	ieee80211_recalc_idle(local); | ||||
| @ -377,8 +290,6 @@ EXPORT_SYMBOL(ieee80211_scan_completed); | ||||
| 
 | ||||
| static int ieee80211_start_sw_scan(struct ieee80211_local *local) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Hardware/driver doesn't support hw_scan, so use software | ||||
| 	 * scanning instead. First send a nullfunc frame with power save | ||||
| @ -394,33 +305,15 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local) | ||||
| 	 */ | ||||
| 	drv_sw_scan_start(local); | ||||
| 
 | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/* disable beaconing */ | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_AP || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_ADHOC || | ||||
| 		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT) | ||||
| 			ieee80211_bss_info_change_notify( | ||||
| 				sdata, BSS_CHANGED_BEACON_ENABLED); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * only handle non-STA interfaces here, STA interfaces | ||||
| 		 * are handled in the scan state machine | ||||
| 		 */ | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_STATION) | ||||
| 			netif_stop_queue(sdata->dev); | ||||
| 	} | ||||
| 	mutex_unlock(&local->iflist_mtx); | ||||
| 	ieee80211_offchannel_stop_beaconing(local); | ||||
| 
 | ||||
| 	local->next_scan_state = SCAN_DECISION; | ||||
| 	local->scan_channel_idx = 0; | ||||
| 
 | ||||
| 	drv_flush(local, false); | ||||
| 
 | ||||
| 	ieee80211_configure_filter(local); | ||||
| 
 | ||||
| 	/* TODO: start scan as soon as all nullfunc frames are ACKed */ | ||||
| 	ieee80211_queue_delayed_work(&local->hw, | ||||
| 				     &local->scan_work, | ||||
| 				     IEEE80211_CHANNEL_TIME); | ||||
| @ -433,7 +326,6 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | ||||
| 				  struct cfg80211_scan_request *req) | ||||
| { | ||||
| 	struct ieee80211_local *local = sdata->local; | ||||
| 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; | ||||
| 	int rc; | ||||
| 
 | ||||
| 	if (local->scan_req) | ||||
| @ -463,11 +355,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, | ||||
| 	local->scan_req = req; | ||||
| 	local->scan_sdata = sdata; | ||||
| 
 | ||||
| 	if (req != local->int_scan_req && | ||||
| 	    sdata->vif.type == NL80211_IFTYPE_STATION && | ||||
| 	    !list_empty(&ifmgd->work_list)) { | ||||
| 		/* actually wait for the work it's doing to finish/time out */ | ||||
| 		set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request); | ||||
| 	if (!list_empty(&local->work_list)) { | ||||
| 		/* wait for the work to finish/time out */ | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| @ -526,7 +415,7 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | ||||
| 	/* check if at least one STA interface is associated */ | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||||
| @ -564,56 +453,35 @@ static int ieee80211_scan_state_decision(struct ieee80211_local *local, | ||||
| static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local, | ||||
| 						    unsigned long *next_delay) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * notify the AP about us leaving the channel and stop all STA interfaces | ||||
| 	 */ | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||||
| 			netif_stop_queue(sdata->dev); | ||||
| 			if (sdata->u.mgd.associated) | ||||
| 				ieee80211_scan_ps_enable(sdata); | ||||
| 		} | ||||
| 	} | ||||
| 	mutex_unlock(&local->iflist_mtx); | ||||
| 	ieee80211_offchannel_stop_station(local); | ||||
| 
 | ||||
| 	__set_bit(SCAN_OFF_CHANNEL, &local->scanning); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * What if the nullfunc frames didn't arrive? | ||||
| 	 */ | ||||
| 	drv_flush(local, false); | ||||
| 	if (local->ops->flush) | ||||
| 		*next_delay = 0; | ||||
| 	else | ||||
| 		*next_delay = HZ / 10; | ||||
| 
 | ||||
| 	/* advance to the next channel to be scanned */ | ||||
| 	*next_delay = HZ / 10; | ||||
| 	local->next_scan_state = SCAN_SET_CHANNEL; | ||||
| } | ||||
| 
 | ||||
| static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local, | ||||
| 						    unsigned long *next_delay) | ||||
| { | ||||
| 	struct ieee80211_sub_if_data *sdata = local->scan_sdata; | ||||
| 
 | ||||
| 	/* switch back to the operating channel */ | ||||
| 	local->scan_channel = NULL; | ||||
| 	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * notify the AP about us being back and restart all STA interfaces | ||||
| 	 * Only re-enable station mode interface now; beaconing will be | ||||
| 	 * re-enabled once the full scan has been completed. | ||||
| 	 */ | ||||
| 	mutex_lock(&local->iflist_mtx); | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		/* Tell AP we're back */ | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||||
| 			if (sdata->u.mgd.associated) | ||||
| 				ieee80211_scan_ps_disable(sdata); | ||||
| 			netif_wake_queue(sdata->dev); | ||||
| 		} | ||||
| 	} | ||||
| 	mutex_unlock(&local->iflist_mtx); | ||||
| 	ieee80211_offchannel_return(local, false); | ||||
| 
 | ||||
| 	__clear_bit(SCAN_OFF_CHANNEL, &local->scanning); | ||||
| 
 | ||||
| @ -727,7 +595,7 @@ void ieee80211_scan_work(struct work_struct *work) | ||||
| 	/*
 | ||||
| 	 * Avoid re-scheduling when the sdata is going away. | ||||
| 	 */ | ||||
| 	if (!netif_running(sdata->dev)) { | ||||
| 	if (!ieee80211_sdata_running(sdata)) { | ||||
| 		ieee80211_scan_completed(&local->hw, true); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| @ -359,6 +359,7 @@ int sta_info_insert(struct sta_info *sta) | ||||
| { | ||||
| 	struct ieee80211_local *local = sta->local; | ||||
| 	struct ieee80211_sub_if_data *sdata = sta->sdata; | ||||
| 	struct station_info sinfo; | ||||
| 	unsigned long flags; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| @ -367,7 +368,7 @@ int sta_info_insert(struct sta_info *sta) | ||||
| 	 * something inserts a STA (on one CPU) without holding the RTNL | ||||
| 	 * and another CPU turns off the net device. | ||||
| 	 */ | ||||
| 	if (unlikely(!netif_running(sdata->dev))) { | ||||
| 	if (unlikely(!ieee80211_sdata_running(sdata))) { | ||||
| 		err = -ENETDOWN; | ||||
| 		goto out_free; | ||||
| 	} | ||||
| @ -408,6 +409,10 @@ int sta_info_insert(struct sta_info *sta) | ||||
| 
 | ||||
| 	spin_unlock_irqrestore(&local->sta_lock, flags); | ||||
| 
 | ||||
| 	sinfo.filled = 0; | ||||
| 	sinfo.generation = local->sta_generation; | ||||
| 	cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_ATOMIC); | ||||
| 
 | ||||
| #ifdef CONFIG_MAC80211_DEBUGFS | ||||
| 	/*
 | ||||
| 	 * Debugfs entry adding might sleep, so schedule process | ||||
|  | ||||
| @ -351,7 +351,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) | ||||
| 	rcu_read_lock(); | ||||
| 	list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||||
| 		if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { | ||||
| 			if (!netif_running(sdata->dev)) | ||||
| 			if (!ieee80211_sdata_running(sdata)) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if ((sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) && | ||||
|  | ||||
| @ -1418,6 +1418,10 @@ static bool need_dynamic_ps(struct ieee80211_local *local) | ||||
| 	if (!local->ps_sdata) | ||||
| 		return false; | ||||
| 
 | ||||
| 	/* No point if we're going to suspend */ | ||||
| 	if (local->quiescing) | ||||
| 		return false; | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| @ -1469,7 +1473,7 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | ||||
| 
 | ||||
| 			list_for_each_entry_rcu(tmp_sdata, &local->interfaces, | ||||
| 						list) { | ||||
| 				if (!netif_running(tmp_sdata->dev)) | ||||
| 				if (!ieee80211_sdata_running(tmp_sdata)) | ||||
| 					continue; | ||||
| 				if (tmp_sdata->vif.type != NL80211_IFTYPE_AP) | ||||
| 					continue; | ||||
|  | ||||
| @ -468,7 +468,7 @@ void ieee80211_iterate_active_interfaces( | ||||
| 		case NL80211_IFTYPE_MESH_POINT: | ||||
| 			break; | ||||
| 		} | ||||
| 		if (netif_running(sdata->dev)) | ||||
| 		if (ieee80211_sdata_running(sdata)) | ||||
| 			iterator(data, sdata->vif.addr, | ||||
| 				 &sdata->vif); | ||||
| 	} | ||||
| @ -502,7 +502,7 @@ void ieee80211_iterate_active_interfaces_atomic( | ||||
| 		case NL80211_IFTYPE_MESH_POINT: | ||||
| 			break; | ||||
| 		} | ||||
| 		if (netif_running(sdata->dev)) | ||||
| 		if (ieee80211_sdata_running(sdata)) | ||||
| 			iterator(data, sdata->vif.addr, | ||||
| 				 &sdata->vif); | ||||
| 	} | ||||
| @ -881,30 +881,66 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||||
| 			     enum ieee80211_band band) | ||||
| { | ||||
| 	struct ieee80211_supported_band *sband; | ||||
| 	u8 *pos, *supp_rates_len, *esupp_rates_len = NULL; | ||||
| 	int i; | ||||
| 	u8 *pos; | ||||
| 	size_t offset = 0, noffset; | ||||
| 	int supp_rates_len, i; | ||||
| 
 | ||||
| 	sband = local->hw.wiphy->bands[band]; | ||||
| 
 | ||||
| 	pos = buffer; | ||||
| 
 | ||||
| 	supp_rates_len = min_t(int, sband->n_bitrates, 8); | ||||
| 
 | ||||
| 	*pos++ = WLAN_EID_SUPP_RATES; | ||||
| 	supp_rates_len = pos; | ||||
| 	*pos++ = 0; | ||||
| 	*pos++ = supp_rates_len; | ||||
| 
 | ||||
| 	for (i = 0; i < sband->n_bitrates; i++) { | ||||
| 		struct ieee80211_rate *rate = &sband->bitrates[i]; | ||||
| 	for (i = 0; i < supp_rates_len; i++) { | ||||
| 		int rate = sband->bitrates[i].bitrate; | ||||
| 		*pos++ = (u8) (rate / 5); | ||||
| 	} | ||||
| 
 | ||||
| 		if (esupp_rates_len) { | ||||
| 			*esupp_rates_len += 1; | ||||
| 		} else if (*supp_rates_len == 8) { | ||||
| 			*pos++ = WLAN_EID_EXT_SUPP_RATES; | ||||
| 			esupp_rates_len = pos; | ||||
| 			*pos++ = 1; | ||||
| 		} else | ||||
| 			*supp_rates_len += 1; | ||||
| 	/* insert "request information" if in custom IEs */ | ||||
| 	if (ie && ie_len) { | ||||
| 		static const u8 before_extrates[] = { | ||||
| 			WLAN_EID_SSID, | ||||
| 			WLAN_EID_SUPP_RATES, | ||||
| 			WLAN_EID_REQUEST, | ||||
| 		}; | ||||
| 		noffset = ieee80211_ie_split(ie, ie_len, | ||||
| 					     before_extrates, | ||||
| 					     ARRAY_SIZE(before_extrates), | ||||
| 					     offset); | ||||
| 		memcpy(pos, ie + offset, noffset - offset); | ||||
| 		pos += noffset - offset; | ||||
| 		offset = noffset; | ||||
| 	} | ||||
| 
 | ||||
| 		*pos++ = rate->bitrate / 5; | ||||
| 	if (sband->n_bitrates > i) { | ||||
| 		*pos++ = WLAN_EID_EXT_SUPP_RATES; | ||||
| 		*pos++ = sband->n_bitrates - i; | ||||
| 
 | ||||
| 		for (; i < sband->n_bitrates; i++) { | ||||
| 			int rate = sband->bitrates[i].bitrate; | ||||
| 			*pos++ = (u8) (rate / 5); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* insert custom IEs that go before HT */ | ||||
| 	if (ie && ie_len) { | ||||
| 		static const u8 before_ht[] = { | ||||
| 			WLAN_EID_SSID, | ||||
| 			WLAN_EID_SUPP_RATES, | ||||
| 			WLAN_EID_REQUEST, | ||||
| 			WLAN_EID_EXT_SUPP_RATES, | ||||
| 			WLAN_EID_DS_PARAMS, | ||||
| 			WLAN_EID_SUPPORTED_REGULATORY_CLASSES, | ||||
| 		}; | ||||
| 		noffset = ieee80211_ie_split(ie, ie_len, | ||||
| 					     before_ht, ARRAY_SIZE(before_ht), | ||||
| 					     offset); | ||||
| 		memcpy(pos, ie + offset, noffset - offset); | ||||
| 		pos += noffset - offset; | ||||
| 		offset = noffset; | ||||
| 	} | ||||
| 
 | ||||
| 	if (sband->ht_cap.ht_supported) { | ||||
| @ -936,9 +972,11 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, | ||||
| 	 * that calculates local->scan_ies_len. | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (ie) { | ||||
| 		memcpy(pos, ie, ie_len); | ||||
| 		pos += ie_len; | ||||
| 	/* add any remaining custom IEs */ | ||||
| 	if (ie && ie_len) { | ||||
| 		noffset = ie_len; | ||||
| 		memcpy(pos, ie + offset, noffset - offset); | ||||
| 		pos += noffset - offset; | ||||
| 	} | ||||
| 
 | ||||
| 	return pos - buffer; | ||||
| @ -1037,7 +1075,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) | ||||
| { | ||||
| 	struct ieee80211_hw *hw = &local->hw; | ||||
| 	struct ieee80211_sub_if_data *sdata; | ||||
| 	struct ieee80211_if_init_conf conf; | ||||
| 	struct sta_info *sta; | ||||
| 	unsigned long flags; | ||||
| 	int res; | ||||
| @ -1047,7 +1084,19 @@ int ieee80211_reconfig(struct ieee80211_local *local) | ||||
| 
 | ||||
| 	/* restart hardware */ | ||||
| 	if (local->open_count) { | ||||
| 		/*
 | ||||
| 		 * Upon resume hardware can sometimes be goofy due to | ||||
| 		 * various platform / driver / bus issues, so restarting | ||||
| 		 * the device may at times not work immediately. Propagate | ||||
| 		 * the error. | ||||
| 		 */ | ||||
| 		res = drv_start(local); | ||||
| 		if (res) { | ||||
| 			WARN(local->suspended, "Harware became unavailable " | ||||
| 			     "upon resume. This is could be a software issue" | ||||
| 			     "prior to suspend or a harware issue\n"); | ||||
| 			return res; | ||||
| 		} | ||||
| 
 | ||||
| 		ieee80211_led_radio(local, true); | ||||
| 	} | ||||
| @ -1056,12 +1105,8 @@ int ieee80211_reconfig(struct ieee80211_local *local) | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN && | ||||
| 		    sdata->vif.type != NL80211_IFTYPE_MONITOR && | ||||
| 		    netif_running(sdata->dev)) { | ||||
| 			conf.vif = &sdata->vif; | ||||
| 			conf.type = sdata->vif.type; | ||||
| 			conf.mac_addr = sdata->vif.addr; | ||||
| 			res = drv_add_interface(local, &conf); | ||||
| 		} | ||||
| 		    ieee80211_sdata_running(sdata)) | ||||
| 			res = drv_add_interface(local, &sdata->vif); | ||||
| 	} | ||||
| 
 | ||||
| 	/* add STAs back */ | ||||
| @ -1103,7 +1148,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | ||||
| 	/* Finally also reconfigure all the BSS information */ | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) { | ||||
| 		u32 changed = ~0; | ||||
| 		if (!netif_running(sdata->dev)) | ||||
| 		if (!ieee80211_sdata_running(sdata)) | ||||
| 			continue; | ||||
| 		switch (sdata->vif.type) { | ||||
| 		case NL80211_IFTYPE_STATION: | ||||
| @ -1131,7 +1176,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) | ||||
| 
 | ||||
| 	/* add back keys */ | ||||
| 	list_for_each_entry(sdata, &local->interfaces, list) | ||||
| 		if (netif_running(sdata->dev)) | ||||
| 		if (ieee80211_sdata_running(sdata)) | ||||
| 			ieee80211_enable_keys(sdata); | ||||
| 
 | ||||
| 	ieee80211_wake_queues_by_reason(hw, | ||||
| @ -1252,3 +1297,59 @@ void ieee80211_recalc_smps(struct ieee80211_local *local, | ||||
| 	/* changed flag is auto-detected for this */ | ||||
| 	ieee80211_hw_config(local, 0); | ||||
| } | ||||
| 
 | ||||
| static bool ieee80211_id_in_list(const u8 *ids, int n_ids, u8 id) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < n_ids; i++) | ||||
| 		if (ids[i] == id) | ||||
| 			return true; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * ieee80211_ie_split - split an IE buffer according to ordering | ||||
|  * | ||||
|  * @ies: the IE buffer | ||||
|  * @ielen: the length of the IE buffer | ||||
|  * @ids: an array with element IDs that are allowed before | ||||
|  *	the split | ||||
|  * @n_ids: the size of the element ID array | ||||
|  * @offset: offset where to start splitting in the buffer | ||||
|  * | ||||
|  * This function splits an IE buffer by updating the @offset | ||||
|  * variable to point to the location where the buffer should be | ||||
|  * split. | ||||
|  * | ||||
|  * It assumes that the given IE buffer is well-formed, this | ||||
|  * has to be guaranteed by the caller! | ||||
|  * | ||||
|  * It also assumes that the IEs in the buffer are ordered | ||||
|  * correctly, if not the result of using this function will not | ||||
|  * be ordered correctly either, i.e. it does no reordering. | ||||
|  * | ||||
|  * The function returns the offset where the next part of the | ||||
|  * buffer starts, which may be @ielen if the entire (remainder) | ||||
|  * of the buffer should be used. | ||||
|  */ | ||||
| size_t ieee80211_ie_split(const u8 *ies, size_t ielen, | ||||
| 			  const u8 *ids, int n_ids, size_t offset) | ||||
| { | ||||
| 	size_t pos = offset; | ||||
| 
 | ||||
| 	while (pos < ielen && ieee80211_id_in_list(ids, n_ids, ies[pos])) | ||||
| 		pos += 2 + ies[pos + 1]; | ||||
| 
 | ||||
| 	return pos; | ||||
| } | ||||
| 
 | ||||
| size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset) | ||||
| { | ||||
| 	size_t pos = offset; | ||||
| 
 | ||||
| 	while (pos < ielen && ies[pos] != WLAN_EID_VENDOR_SPECIFIC) | ||||
| 		pos += 2 + ies[pos + 1]; | ||||
| 
 | ||||
| 	return pos; | ||||
| } | ||||
|  | ||||
							
								
								
									
										1086
									
								
								net/mac80211/work.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1086
									
								
								net/mac80211/work.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -94,21 +94,6 @@ config CFG80211_DEBUGFS | ||||
| 
 | ||||
| 	  If unsure, say N. | ||||
| 
 | ||||
| config WIRELESS_OLD_REGULATORY | ||||
| 	bool "Old wireless static regulatory definitions" | ||||
| 	default n | ||||
| 	depends on CFG80211 | ||||
| 	---help--- | ||||
| 	  This option enables the old static regulatory information | ||||
| 	  and uses it within the new framework. This option is available | ||||
| 	  for historical reasons and it is advised to leave it off. | ||||
| 
 | ||||
| 	  For details see: | ||||
| 
 | ||||
| 	  http://wireless.kernel.org/en/developers/Regulatory | ||||
| 
 | ||||
| 	  Say N and if you say Y, please tell us why. The default is N. | ||||
| 
 | ||||
| config CFG80211_INTERNAL_REGDB | ||||
| 	bool "use statically compiled regulatory rules database" if EMBEDDED | ||||
| 	default n | ||||
|  | ||||
| @ -41,12 +41,45 @@ rdev_fixed_channel(struct cfg80211_registered_device *rdev, | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| struct ieee80211_channel * | ||||
| rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | ||||
| 		  int freq, enum nl80211_channel_type channel_type) | ||||
| { | ||||
| 	struct ieee80211_channel *chan; | ||||
| 	struct ieee80211_sta_ht_cap *ht_cap; | ||||
| 
 | ||||
| 	chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||||
| 
 | ||||
| 	/* Primary channel not allowed */ | ||||
| 	if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (channel_type == NL80211_CHAN_HT40MINUS && | ||||
| 	    chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||||
| 		return NULL; | ||||
| 	else if (channel_type == NL80211_CHAN_HT40PLUS && | ||||
| 		 chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||||
| 
 | ||||
| 	if (channel_type != NL80211_CHAN_NO_HT) { | ||||
| 		if (!ht_cap->ht_supported) | ||||
| 			return NULL; | ||||
| 
 | ||||
| 		if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||||
| 		    ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | ||||
| 			return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	return chan; | ||||
| } | ||||
| 
 | ||||
| int rdev_set_freq(struct cfg80211_registered_device *rdev, | ||||
| 		  struct wireless_dev *for_wdev, | ||||
| 		  int freq, enum nl80211_channel_type channel_type) | ||||
| { | ||||
| 	struct ieee80211_channel *chan; | ||||
| 	struct ieee80211_sta_ht_cap *ht_cap; | ||||
| 	int result; | ||||
| 
 | ||||
| 	if (rdev_fixed_channel(rdev, for_wdev)) | ||||
| @ -55,30 +88,10 @@ int rdev_set_freq(struct cfg80211_registered_device *rdev, | ||||
| 	if (!rdev->ops->set_channel) | ||||
| 		return -EOPNOTSUPP; | ||||
| 
 | ||||
| 	chan = ieee80211_get_channel(&rdev->wiphy, freq); | ||||
| 
 | ||||
| 	/* Primary channel not allowed */ | ||||
| 	if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) | ||||
| 	chan = rdev_freq_to_chan(rdev, freq, channel_type); | ||||
| 	if (!chan) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (channel_type == NL80211_CHAN_HT40MINUS && | ||||
| 	    chan->flags & IEEE80211_CHAN_NO_HT40MINUS) | ||||
| 		return -EINVAL; | ||||
| 	else if (channel_type == NL80211_CHAN_HT40PLUS && | ||||
| 		 chan->flags & IEEE80211_CHAN_NO_HT40PLUS) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; | ||||
| 
 | ||||
| 	if (channel_type != NL80211_CHAN_NO_HT) { | ||||
| 		if (!ht_cap->ht_supported) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 		if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || | ||||
| 		    ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT) | ||||
| 			return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	result = rdev->ops->set_channel(&rdev->wiphy, chan, channel_type); | ||||
| 	if (result) | ||||
| 		return result; | ||||
|  | ||||
| @ -374,6 +374,9 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); | ||||
| struct ieee80211_channel * | ||||
| rdev_fixed_channel(struct cfg80211_registered_device *rdev, | ||||
| 		   struct wireless_dev *for_wdev); | ||||
| struct ieee80211_channel * | ||||
| rdev_freq_to_chan(struct cfg80211_registered_device *rdev, | ||||
| 		  int freq, enum nl80211_channel_type channel_type); | ||||
| int rdev_set_freq(struct cfg80211_registered_device *rdev, | ||||
| 		  struct wireless_dev *for_wdev, | ||||
| 		  int freq, enum nl80211_channel_type channel_type); | ||||
|  | ||||
| @ -93,7 +93,18 @@ void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len) | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		WARN_ON(!bss); | ||||
| 		/*
 | ||||
| 		 * We might be coming here because the driver reported | ||||
| 		 * a successful association at the same time as the | ||||
| 		 * user requested a deauth. In that case, we will have | ||||
| 		 * removed the BSS from the auth_bsses list due to the | ||||
| 		 * deauth request when the assoc response makes it. If | ||||
| 		 * the two code paths acquire the lock the other way | ||||
| 		 * around, that's just the standard situation of a | ||||
| 		 * deauth being requested while connected. | ||||
| 		 */ | ||||
| 		if (!bss) | ||||
| 			goto out; | ||||
| 	} else if (wdev->conn) { | ||||
| 		cfg80211_sme_failed_assoc(wdev); | ||||
| 		/*
 | ||||
| @ -680,3 +691,40 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, | ||||
| 			       struct ieee80211_channel *chan, | ||||
| 			       enum nl80211_channel_type channel_type, | ||||
| 			       unsigned int duration, gfp_t gfp) | ||||
| { | ||||
| 	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||||
| 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||||
| 
 | ||||
| 	nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type, | ||||
| 				       duration, gfp); | ||||
| } | ||||
| EXPORT_SYMBOL(cfg80211_ready_on_channel); | ||||
| 
 | ||||
| void cfg80211_remain_on_channel_expired(struct net_device *dev, | ||||
| 					u64 cookie, | ||||
| 					struct ieee80211_channel *chan, | ||||
| 					enum nl80211_channel_type channel_type, | ||||
| 					gfp_t gfp) | ||||
| { | ||||
| 	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||||
| 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||||
| 
 | ||||
| 	nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan, | ||||
| 					      channel_type, gfp); | ||||
| } | ||||
| EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); | ||||
| 
 | ||||
| void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr, | ||||
| 		      struct station_info *sinfo, gfp_t gfp) | ||||
| { | ||||
| 	struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | ||||
| 	struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | ||||
| 
 | ||||
| 	nl80211_send_sta_event(rdev, dev, mac_addr, sinfo, gfp); | ||||
| } | ||||
| EXPORT_SYMBOL(cfg80211_new_sta); | ||||
|  | ||||
| @ -141,6 +141,8 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { | ||||
| 	[NL80211_ATTR_4ADDR] = { .type = NLA_U8 }, | ||||
| 	[NL80211_ATTR_PMKID] = { .type = NLA_BINARY, | ||||
| 				 .len = WLAN_PMKID_LEN }, | ||||
| 	[NL80211_ATTR_DURATION] = { .type = NLA_U32 }, | ||||
| 	[NL80211_ATTR_COOKIE] = { .type = NLA_U64 }, | ||||
| }; | ||||
| 
 | ||||
| /* policy for the attributes */ | ||||
| @ -569,6 +571,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, | ||||
| 	CMD(set_pmksa, SET_PMKSA); | ||||
| 	CMD(del_pmksa, DEL_PMKSA); | ||||
| 	CMD(flush_pmksa, FLUSH_PMKSA); | ||||
| 	CMD(remain_on_channel, REMAIN_ON_CHANNEL); | ||||
| 	if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) { | ||||
| 		i++; | ||||
| 		NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS); | ||||
| @ -1639,7 +1642,7 @@ static int parse_station_flags(struct genl_info *info, | ||||
| 
 | ||||
| static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, | ||||
| 				int flags, struct net_device *dev, | ||||
| 				u8 *mac_addr, struct station_info *sinfo) | ||||
| 				const u8 *mac_addr, struct station_info *sinfo) | ||||
| { | ||||
| 	void *hdr; | ||||
| 	struct nlattr *sinfoattr, *txrate; | ||||
| @ -2550,12 +2553,6 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) | ||||
| 
 | ||||
| 	data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); | ||||
| 
 | ||||
| #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||||
| 	/* We ignore world regdom requests with the old regdom setup */ | ||||
| 	if (is_world_regdom(data)) | ||||
| 		return -EINVAL; | ||||
| #endif | ||||
| 
 | ||||
| 	r = regulatory_hint_user(data); | ||||
| 
 | ||||
| 	return r; | ||||
| @ -4289,6 +4286,143 @@ static int nl80211_flush_pmksa(struct sk_buff *skb, struct genl_info *info) | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| static int nl80211_remain_on_channel(struct sk_buff *skb, | ||||
| 				     struct genl_info *info) | ||||
| { | ||||
| 	struct cfg80211_registered_device *rdev; | ||||
| 	struct net_device *dev; | ||||
| 	struct ieee80211_channel *chan; | ||||
| 	struct sk_buff *msg; | ||||
| 	void *hdr; | ||||
| 	u64 cookie; | ||||
| 	enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; | ||||
| 	u32 freq, duration; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] || | ||||
| 	    !info->attrs[NL80211_ATTR_DURATION]) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	duration = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We should be on that channel for at least one jiffie, | ||||
| 	 * and more than 5 seconds seems excessive. | ||||
| 	 */ | ||||
| 	if (!duration || !msecs_to_jiffies(duration) || duration > 5000) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	rtnl_lock(); | ||||
| 
 | ||||
| 	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||||
| 	if (err) | ||||
| 		goto unlock_rtnl; | ||||
| 
 | ||||
| 	if (!rdev->ops->remain_on_channel) { | ||||
| 		err = -EOPNOTSUPP; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!netif_running(dev)) { | ||||
| 		err = -ENETDOWN; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { | ||||
| 		channel_type = nla_get_u32( | ||||
| 			info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); | ||||
| 		if (channel_type != NL80211_CHAN_NO_HT && | ||||
| 		    channel_type != NL80211_CHAN_HT20 && | ||||
| 		    channel_type != NL80211_CHAN_HT40PLUS && | ||||
| 		    channel_type != NL80211_CHAN_HT40MINUS) | ||||
| 			err = -EINVAL; | ||||
| 			goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); | ||||
| 	chan = rdev_freq_to_chan(rdev, freq, channel_type); | ||||
| 	if (chan == NULL) { | ||||
| 		err = -EINVAL; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||||
| 	if (!msg) { | ||||
| 		err = -ENOMEM; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, | ||||
| 			     NL80211_CMD_REMAIN_ON_CHANNEL); | ||||
| 
 | ||||
| 	if (IS_ERR(hdr)) { | ||||
| 		err = PTR_ERR(hdr); | ||||
| 		goto free_msg; | ||||
| 	} | ||||
| 
 | ||||
| 	err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, | ||||
| 					   channel_type, duration, &cookie); | ||||
| 
 | ||||
| 	if (err) | ||||
| 		goto free_msg; | ||||
| 
 | ||||
| 	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | ||||
| 
 | ||||
| 	genlmsg_end(msg, hdr); | ||||
| 	err = genlmsg_reply(msg, info); | ||||
| 	goto out; | ||||
| 
 | ||||
|  nla_put_failure: | ||||
| 	err = -ENOBUFS; | ||||
|  free_msg: | ||||
| 	nlmsg_free(msg); | ||||
|  out: | ||||
| 	cfg80211_unlock_rdev(rdev); | ||||
| 	dev_put(dev); | ||||
|  unlock_rtnl: | ||||
| 	rtnl_unlock(); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, | ||||
| 					    struct genl_info *info) | ||||
| { | ||||
| 	struct cfg80211_registered_device *rdev; | ||||
| 	struct net_device *dev; | ||||
| 	u64 cookie; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (!info->attrs[NL80211_ATTR_COOKIE]) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	rtnl_lock(); | ||||
| 
 | ||||
| 	err = get_rdev_dev_by_info_ifindex(info, &rdev, &dev); | ||||
| 	if (err) | ||||
| 		goto unlock_rtnl; | ||||
| 
 | ||||
| 	if (!rdev->ops->cancel_remain_on_channel) { | ||||
| 		err = -EOPNOTSUPP; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!netif_running(dev)) { | ||||
| 		err = -ENETDOWN; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); | ||||
| 
 | ||||
| 	err = rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); | ||||
| 
 | ||||
|  out: | ||||
| 	cfg80211_unlock_rdev(rdev); | ||||
| 	dev_put(dev); | ||||
|  unlock_rtnl: | ||||
| 	rtnl_unlock(); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static struct genl_ops nl80211_ops[] = { | ||||
| 	{ | ||||
| 		.cmd = NL80211_CMD_GET_WIPHY, | ||||
| @ -4551,8 +4685,20 @@ static struct genl_ops nl80211_ops[] = { | ||||
| 		.policy = nl80211_policy, | ||||
| 		.flags = GENL_ADMIN_PERM, | ||||
| 	}, | ||||
| 
 | ||||
| 	{ | ||||
| 		.cmd = NL80211_CMD_REMAIN_ON_CHANNEL, | ||||
| 		.doit = nl80211_remain_on_channel, | ||||
| 		.policy = nl80211_policy, | ||||
| 		.flags = GENL_ADMIN_PERM, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.cmd = NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | ||||
| 		.doit = nl80211_cancel_remain_on_channel, | ||||
| 		.policy = nl80211_policy, | ||||
| 		.flags = GENL_ADMIN_PERM, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static struct genl_multicast_group nl80211_mlme_mcgrp = { | ||||
| 	.name = "mlme", | ||||
| }; | ||||
| @ -5140,6 +5286,89 @@ nla_put_failure: | ||||
| 	nlmsg_free(msg); | ||||
| } | ||||
| 
 | ||||
| static void nl80211_send_remain_on_chan_event( | ||||
| 	int cmd, struct cfg80211_registered_device *rdev, | ||||
| 	struct net_device *netdev, u64 cookie, | ||||
| 	struct ieee80211_channel *chan, | ||||
| 	enum nl80211_channel_type channel_type, | ||||
| 	unsigned int duration, gfp_t gfp) | ||||
| { | ||||
| 	struct sk_buff *msg; | ||||
| 	void *hdr; | ||||
| 
 | ||||
| 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp); | ||||
| 	if (!msg) | ||||
| 		return; | ||||
| 
 | ||||
| 	hdr = nl80211hdr_put(msg, 0, 0, 0, cmd); | ||||
| 	if (!hdr) { | ||||
| 		nlmsg_free(msg); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx); | ||||
| 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex); | ||||
| 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq); | ||||
| 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type); | ||||
| 	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie); | ||||
| 
 | ||||
| 	if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL) | ||||
| 		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration); | ||||
| 
 | ||||
| 	if (genlmsg_end(msg, hdr) < 0) { | ||||
| 		nlmsg_free(msg); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||||
| 				nl80211_mlme_mcgrp.id, gfp); | ||||
| 	return; | ||||
| 
 | ||||
|  nla_put_failure: | ||||
| 	genlmsg_cancel(msg, hdr); | ||||
| 	nlmsg_free(msg); | ||||
| } | ||||
| 
 | ||||
| void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | ||||
| 				    struct net_device *netdev, u64 cookie, | ||||
| 				    struct ieee80211_channel *chan, | ||||
| 				    enum nl80211_channel_type channel_type, | ||||
| 				    unsigned int duration, gfp_t gfp) | ||||
| { | ||||
| 	nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, | ||||
| 					  rdev, netdev, cookie, chan, | ||||
| 					  channel_type, duration, gfp); | ||||
| } | ||||
| 
 | ||||
| void nl80211_send_remain_on_channel_cancel( | ||||
| 	struct cfg80211_registered_device *rdev, struct net_device *netdev, | ||||
| 	u64 cookie, struct ieee80211_channel *chan, | ||||
| 	enum nl80211_channel_type channel_type, gfp_t gfp) | ||||
| { | ||||
| 	nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, | ||||
| 					  rdev, netdev, cookie, chan, | ||||
| 					  channel_type, 0, gfp); | ||||
| } | ||||
| 
 | ||||
| void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | ||||
| 			    struct net_device *dev, const u8 *mac_addr, | ||||
| 			    struct station_info *sinfo, gfp_t gfp) | ||||
| { | ||||
| 	struct sk_buff *msg; | ||||
| 
 | ||||
| 	msg = nlmsg_new(NLMSG_GOODSIZE, gfp); | ||||
| 	if (!msg) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (nl80211_send_station(msg, 0, 0, 0, dev, mac_addr, sinfo) < 0) { | ||||
| 		nlmsg_free(msg); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, | ||||
| 				nl80211_mlme_mcgrp.id, gfp); | ||||
| } | ||||
| 
 | ||||
| /* initialisation/exit functions */ | ||||
| 
 | ||||
| int nl80211_init(void) | ||||
|  | ||||
| @ -59,4 +59,19 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, | ||||
| 			     struct net_device *netdev, const u8 *bssid, | ||||
| 			     gfp_t gfp); | ||||
| 
 | ||||
| void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, | ||||
| 				    struct net_device *netdev, | ||||
| 				    u64 cookie, | ||||
| 				    struct ieee80211_channel *chan, | ||||
| 				    enum nl80211_channel_type channel_type, | ||||
| 				    unsigned int duration, gfp_t gfp); | ||||
| void nl80211_send_remain_on_channel_cancel( | ||||
| 	struct cfg80211_registered_device *rdev, struct net_device *netdev, | ||||
| 	u64 cookie, struct ieee80211_channel *chan, | ||||
| 	enum nl80211_channel_type channel_type, gfp_t gfp); | ||||
| 
 | ||||
| void nl80211_send_sta_event(struct cfg80211_registered_device *rdev, | ||||
| 			    struct net_device *dev, const u8 *mac_addr, | ||||
| 			    struct station_info *sinfo, gfp_t gfp); | ||||
| 
 | ||||
| #endif /* __NET_WIRELESS_NL80211_H */ | ||||
|  | ||||
| @ -129,78 +129,6 @@ static char *ieee80211_regdom = "00"; | ||||
| module_param(ieee80211_regdom, charp, 0444); | ||||
| MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | ||||
| 
 | ||||
| #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||||
| /*
 | ||||
|  * We assume 40 MHz bandwidth for the old regulatory work. | ||||
|  * We make emphasis we are using the exact same frequencies | ||||
|  * as before | ||||
|  */ | ||||
| 
 | ||||
| static const struct ieee80211_regdomain us_regdom = { | ||||
| 	.n_reg_rules = 6, | ||||
| 	.alpha2 =  "US", | ||||
| 	.reg_rules = { | ||||
| 		/* IEEE 802.11b/g, channels 1..11 */ | ||||
| 		REG_RULE(2412-10, 2462+10, 40, 6, 27, 0), | ||||
| 		/* IEEE 802.11a, channel 36..48 */ | ||||
| 		REG_RULE(5180-10, 5240+10, 40, 6, 17, 0), | ||||
| 		/* IEEE 802.11a, channels 48..64 */ | ||||
| 		REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS), | ||||
| 		/* IEEE 802.11a, channels 100..124 */ | ||||
| 		REG_RULE(5500-10, 5590+10, 40, 6, 20, NL80211_RRF_DFS), | ||||
| 		/* IEEE 802.11a, channels 132..144 */ | ||||
| 		REG_RULE(5660-10, 5700+10, 40, 6, 20, NL80211_RRF_DFS), | ||||
| 		/* IEEE 802.11a, channels 149..165, outdoor */ | ||||
| 		REG_RULE(5745-10, 5825+10, 40, 6, 30, 0), | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| static const struct ieee80211_regdomain jp_regdom = { | ||||
| 	.n_reg_rules = 6, | ||||
| 	.alpha2 =  "JP", | ||||
| 	.reg_rules = { | ||||
| 		/* IEEE 802.11b/g, channels 1..11 */ | ||||
| 		REG_RULE(2412-10, 2462+10, 40, 6, 20, 0), | ||||
| 		/* IEEE 802.11b/g, channels 12..13 */ | ||||
| 		REG_RULE(2467-10, 2472+10, 20, 6, 20, 0), | ||||
| 		/* IEEE 802.11b/g, channel 14 */ | ||||
| 		REG_RULE(2484-10, 2484+10, 20, 6, 20, NL80211_RRF_NO_OFDM), | ||||
| 		/* IEEE 802.11a, channels 36..48 */ | ||||
| 		REG_RULE(5180-10, 5240+10, 40, 6, 20, 0), | ||||
| 		/* IEEE 802.11a, channels 52..64 */ | ||||
| 		REG_RULE(5260-10, 5320+10, 40, 6, 20, NL80211_RRF_DFS), | ||||
| 		/* IEEE 802.11a, channels 100..144 */ | ||||
| 		REG_RULE(5500-10, 5700+10, 40, 6, 23, NL80211_RRF_DFS), | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| static const struct ieee80211_regdomain *static_regdom(char *alpha2) | ||||
| { | ||||
| 	if (alpha2[0] == 'U' && alpha2[1] == 'S') | ||||
| 		return &us_regdom; | ||||
| 	if (alpha2[0] == 'J' && alpha2[1] == 'P') | ||||
| 		return &jp_regdom; | ||||
| 	/* Use world roaming rules for "EU", since it was a pseudo
 | ||||
| 	   domain anyway... */ | ||||
| 	if (alpha2[0] == 'E' && alpha2[1] == 'U') | ||||
| 		return &world_regdom; | ||||
| 	/* Default, world roaming rules */ | ||||
| 	return &world_regdom; | ||||
| } | ||||
| 
 | ||||
| static bool is_old_static_regdom(const struct ieee80211_regdomain *rd) | ||||
| { | ||||
| 	if (rd == &us_regdom || rd == &jp_regdom || rd == &world_regdom) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
| #else | ||||
| static inline bool is_old_static_regdom(const struct ieee80211_regdomain *rd) | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| static void reset_regdomains(void) | ||||
| { | ||||
| 	/* avoid freeing static information or freeing something twice */ | ||||
| @ -210,8 +138,6 @@ static void reset_regdomains(void) | ||||
| 		cfg80211_world_regdom = NULL; | ||||
| 	if (cfg80211_regdomain == &world_regdom) | ||||
| 		cfg80211_regdomain = NULL; | ||||
| 	if (is_old_static_regdom(cfg80211_regdomain)) | ||||
| 		cfg80211_regdomain = NULL; | ||||
| 
 | ||||
| 	kfree(cfg80211_regdomain); | ||||
| 	kfree(cfg80211_world_regdom); | ||||
| @ -1490,8 +1416,6 @@ static int ignore_request(struct wiphy *wiphy, | ||||
| 		return REG_INTERSECT; | ||||
| 	case NL80211_REGDOM_SET_BY_DRIVER: | ||||
| 		if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) { | ||||
| 			if (is_old_static_regdom(cfg80211_regdomain)) | ||||
| 				return 0; | ||||
| 			if (regdom_changes(pending_request->alpha2)) | ||||
| 				return 0; | ||||
| 			return -EALREADY; | ||||
| @ -1528,8 +1452,7 @@ static int ignore_request(struct wiphy *wiphy, | ||||
| 				return -EAGAIN; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!is_old_static_regdom(cfg80211_regdomain) && | ||||
| 		    !regdom_changes(pending_request->alpha2)) | ||||
| 		if (!regdom_changes(pending_request->alpha2)) | ||||
| 			return -EALREADY; | ||||
| 
 | ||||
| 		return 0; | ||||
| @ -2111,8 +2034,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) | ||||
| 		 * If someone else asked us to change the rd lets only bother | ||||
| 		 * checking if the alpha2 changes if CRDA was already called | ||||
| 		 */ | ||||
| 		if (!is_old_static_regdom(cfg80211_regdomain) && | ||||
| 		    !regdom_changes(rd->alpha2)) | ||||
| 		if (!regdom_changes(rd->alpha2)) | ||||
| 			return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| @ -2311,15 +2233,8 @@ int regulatory_init(void) | ||||
| 	spin_lock_init(®_requests_lock); | ||||
| 	spin_lock_init(®_pending_beacons_lock); | ||||
| 
 | ||||
| #ifdef CONFIG_WIRELESS_OLD_REGULATORY | ||||
| 	cfg80211_regdomain = static_regdom(ieee80211_regdom); | ||||
| 
 | ||||
| 	printk(KERN_INFO "cfg80211: Using static regulatory domain info\n"); | ||||
| 	print_regdomain_info(cfg80211_regdomain); | ||||
| #else | ||||
| 	cfg80211_regdomain = cfg80211_world_regdom; | ||||
| 
 | ||||
| #endif | ||||
| 	/* We always try to get an update for the static regdomain */ | ||||
| 	err = regulatory_hint_core(cfg80211_regdomain->alpha2); | ||||
| 	if (err) { | ||||
|  | ||||
| @ -601,7 +601,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, | ||||
| 	struct cfg80211_registered_device *rdev; | ||||
| 	struct wiphy *wiphy; | ||||
| 	struct iw_scan_req *wreq = NULL; | ||||
| 	struct cfg80211_scan_request *creq; | ||||
| 	struct cfg80211_scan_request *creq = NULL; | ||||
| 	int i, err, n_channels = 0; | ||||
| 	enum ieee80211_band band; | ||||
| 
 | ||||
| @ -694,8 +694,10 @@ int cfg80211_wext_siwscan(struct net_device *dev, | ||||
| 	/* translate "Scan for SSID" request */ | ||||
| 	if (wreq) { | ||||
| 		if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { | ||||
| 			if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) | ||||
| 				return -EINVAL; | ||||
| 			if (wreq->essid_len > IEEE80211_MAX_SSID_LEN) { | ||||
| 				err = -EINVAL; | ||||
| 				goto out; | ||||
| 			} | ||||
| 			memcpy(creq->ssids[0].ssid, wreq->essid, wreq->essid_len); | ||||
| 			creq->ssids[0].ssid_len = wreq->essid_len; | ||||
| 		} | ||||
| @ -707,12 +709,15 @@ int cfg80211_wext_siwscan(struct net_device *dev, | ||||
| 	err = rdev->ops->scan(wiphy, dev, creq); | ||||
| 	if (err) { | ||||
| 		rdev->scan_req = NULL; | ||||
| 		kfree(creq); | ||||
| 		/* creq will be freed below */ | ||||
| 	} else { | ||||
| 		nl80211_send_scan_start(rdev, dev); | ||||
| 		/* creq now owned by driver */ | ||||
| 		creq = NULL; | ||||
| 		dev_hold(dev); | ||||
| 	} | ||||
|  out: | ||||
| 	kfree(creq); | ||||
| 	cfg80211_unlock_rdev(rdev); | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user