195ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn/*
29c9a0d145fee73b5e821bb460732ac2a66c680b3Gertjan van Wingerde	Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
395ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	<http://rt2x00.serialmonkey.com>
495ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
595ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	This program is free software; you can redistribute it and/or modify
695ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	it under the terms of the GNU General Public License as published by
795ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	the Free Software Foundation; either version 2 of the License, or
895ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	(at your option) any later version.
995ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
1095ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	This program is distributed in the hope that it will be useful,
1195ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	but WITHOUT ANY WARRANTY; without even the implied warranty of
1295ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1395ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	GNU General Public License for more details.
1495ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
1595ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	You should have received a copy of the GNU General Public License
1695ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	along with this program; if not, write to the
1795ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	Free Software Foundation, Inc.,
1895ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1995ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn */
2095ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
2195ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn/*
2295ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	Module: rt2x00lib
2395ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	Abstract: rt2x00 generic configuration routines.
2495ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn */
2595ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
2695ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn#include <linux/kernel.h>
2795ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn#include <linux/module.h>
2895ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
2995ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn#include "rt2x00.h"
3095ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn#include "rt2x00lib.h"
3195ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
326bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doornvoid rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev,
336bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn			   struct rt2x00_intf *intf,
3405c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg			   enum nl80211_iftype type,
355f936f11613c32ca7f8ed5fa333bb38a4501deebJohannes Berg			   const u8 *mac, const u8 *bssid)
3695ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn{
376bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	struct rt2x00intf_conf conf;
386bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	unsigned int flags = 0;
3995ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
406bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	conf.type = type;
41feb24691e3e87a740caec4568be1a202db786f20Ivo van Doorn
42feb24691e3e87a740caec4568be1a202db786f20Ivo van Doorn	switch (type) {
4305c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_ADHOC:
44ab8966ddc2f7fa3e631efa7478ea2c76d6c9942fHelmut Schaa		conf.sync = TSF_SYNC_ADHOC;
45ab8966ddc2f7fa3e631efa7478ea2c76d6c9942fHelmut Schaa		break;
4605c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_AP:
47a07dbea210e146aedf8929cdabe082b58696260cAndrey Yurovsky	case NL80211_IFTYPE_MESH_POINT:
48ce292a640228fded0d2e232216a19cba33e2cd0fIvo van Doorn	case NL80211_IFTYPE_WDS:
49ab8966ddc2f7fa3e631efa7478ea2c76d6c9942fHelmut Schaa		conf.sync = TSF_SYNC_AP_NONE;
50feb24691e3e87a740caec4568be1a202db786f20Ivo van Doorn		break;
5105c914fe330fa8e1cc67870dc0d3809dfd96c107Johannes Berg	case NL80211_IFTYPE_STATION:
526bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn		conf.sync = TSF_SYNC_INFRA;
53feb24691e3e87a740caec4568be1a202db786f20Ivo van Doorn		break;
54feb24691e3e87a740caec4568be1a202db786f20Ivo van Doorn	default:
556bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn		conf.sync = TSF_SYNC_NONE;
56feb24691e3e87a740caec4568be1a202db786f20Ivo van Doorn		break;
57feb24691e3e87a740caec4568be1a202db786f20Ivo van Doorn	}
58feb24691e3e87a740caec4568be1a202db786f20Ivo van Doorn
596bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	/*
606bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	 * Note that when NULL is passed as address we will send
616bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	 * 00:00:00:00:00 to the device to clear the address.
626bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	 * This will prevent the device being confused when it wants
6325985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	 * to ACK frames or considers itself associated.
646bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	 */
65736e3acadce8438e610b897af2b1c472ed58444bGertjan van Wingerde	memset(conf.mac, 0, sizeof(conf.mac));
666bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	if (mac)
67736e3acadce8438e610b897af2b1c472ed58444bGertjan van Wingerde		memcpy(conf.mac, mac, ETH_ALEN);
686bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn
69736e3acadce8438e610b897af2b1c472ed58444bGertjan van Wingerde	memset(conf.bssid, 0, sizeof(conf.bssid));
706bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	if (bssid)
71736e3acadce8438e610b897af2b1c472ed58444bGertjan van Wingerde		memcpy(conf.bssid, bssid, ETH_ALEN);
726bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn
736bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	flags |= CONFIG_UPDATE_TYPE;
746bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
756bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn		flags |= CONFIG_UPDATE_MAC;
766bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	if (bssid || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count))
776bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn		flags |= CONFIG_UPDATE_BSSID;
786bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn
796bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn	rt2x00dev->ops->lib->config_intf(rt2x00dev, intf, &conf, flags);
806bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn}
816bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn
82728103794316f7ff8d98bc2ce044aff7a260ee21Ivo van Doornvoid rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev,
83728103794316f7ff8d98bc2ce044aff7a260ee21Ivo van Doorn			  struct rt2x00_intf *intf,
840204464329c17ba6d293e1899f71223599a0e582Helmut Schaa			  struct ieee80211_bss_conf *bss_conf,
850204464329c17ba6d293e1899f71223599a0e582Helmut Schaa			  u32 changed)
866bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn{
87728103794316f7ff8d98bc2ce044aff7a260ee21Ivo van Doorn	struct rt2x00lib_erp erp;
886bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn
89728103794316f7ff8d98bc2ce044aff7a260ee21Ivo van Doorn	memset(&erp, 0, sizeof(erp));
90728103794316f7ff8d98bc2ce044aff7a260ee21Ivo van Doorn
91728103794316f7ff8d98bc2ce044aff7a260ee21Ivo van Doorn	erp.short_preamble = bss_conf->use_short_preamble;
92e360c4cb2bc2fb2a37981809685984efe8433c52Ivo van Doorn	erp.cts_protection = bss_conf->use_cts_prot;
93e360c4cb2bc2fb2a37981809685984efe8433c52Ivo van Doorn
94e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME;
95e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	erp.sifs = SIFS;
96e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS;
97e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS;
98e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS;
996bb40dd13b458beb55f5c60dba1cb28e814bd640Ivo van Doorn
100e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	erp.basic_rates = bss_conf->basic_rates;
1018a566afea0639fc387add782bc799009512a911bIvo van Doorn	erp.beacon_int = bss_conf->beacon_int;
102e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn
1031c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	/* Update the AID, this is needed for dynamic PS support */
1041c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0;
105e9ac0745c734d39cb55ce45f1fb03a85c972b35aJohannes Berg	rt2x00dev->last_beacon = bss_conf->last_tsf;
1061c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn
1076b347bff145f9a8a0972ca8fc3c44dd1f91b0f16Ivo van Doorn	/* Update global beacon interval time, this is needed for PS support */
1086b347bff145f9a8a0972ca8fc3c44dd1f91b0f16Ivo van Doorn	rt2x00dev->beacon_int = bss_conf->beacon_int;
1096b347bff145f9a8a0972ca8fc3c44dd1f91b0f16Ivo van Doorn
11087c1915d2c271a8998a79f16bcf5353e2c28db45Helmut Schaa	if (changed & BSS_CHANGED_HT)
11187c1915d2c271a8998a79f16bcf5353e2c28db45Helmut Schaa		erp.ht_opmode = bss_conf->ht_operation_mode;
11287c1915d2c271a8998a79f16bcf5353e2c28db45Helmut Schaa
1130204464329c17ba6d293e1899f71223599a0e582Helmut Schaa	rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed);
11495ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn}
11595ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
11669f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doornvoid rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev,
117bdfa500b8b8ca87dfe7a311f569fe8b39746c299Ivo van Doorn			      struct antenna_setup config)
11869f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn{
119bdfa500b8b8ca87dfe7a311f569fe8b39746c299Ivo van Doorn	struct link_ant *ant = &rt2x00dev->link.ant;
1200b927a079106e5f66c736e297370d3feb008e28eIvo van Doorn	struct antenna_setup *def = &rt2x00dev->default_ant;
1210b927a079106e5f66c736e297370d3feb008e28eIvo van Doorn	struct antenna_setup *active = &rt2x00dev->link.ant.active;
1220b927a079106e5f66c736e297370d3feb008e28eIvo van Doorn
1236d64360ac56cda95243f15738a06f2a123c663e5Ivo van Doorn	/*
1240ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	 * When the caller tries to send the SW diversity,
1250ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	 * we must update the ANTENNA_RX_DIVERSITY flag to
1260ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	 * enable the antenna diversity in the link tuner.
1270ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	 *
1280ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	 * Secondly, we must guarentee we never send the
1290ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	 * software antenna diversity command to the driver.
1306d64360ac56cda95243f15738a06f2a123c663e5Ivo van Doorn	 */
1310ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	if (!(ant->flags & ANTENNA_RX_DIVERSITY)) {
1320ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn		if (config.rx == ANTENNA_SW_DIVERSITY) {
1330ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn			ant->flags |= ANTENNA_RX_DIVERSITY;
1340ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn
1350ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn			if (def->rx == ANTENNA_SW_DIVERSITY)
1360ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn				config.rx = ANTENNA_B;
1370ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn			else
1380ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn				config.rx = def->rx;
1390ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn		}
1400ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	} else if (config.rx == ANTENNA_SW_DIVERSITY)
141bdfa500b8b8ca87dfe7a311f569fe8b39746c299Ivo van Doorn		config.rx = active->rx;
14269f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn
1430ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	if (!(ant->flags & ANTENNA_TX_DIVERSITY)) {
1440ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn		if (config.tx == ANTENNA_SW_DIVERSITY) {
1450ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn			ant->flags |= ANTENNA_TX_DIVERSITY;
1460ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn
1470ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn			if (def->tx == ANTENNA_SW_DIVERSITY)
1480ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn				config.tx = ANTENNA_B;
1490ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn			else
1500ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn				config.tx = def->tx;
1510ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn		}
1520ed7b3c04434788ef03d267190c5e9e6e3f8e9ceIvo van Doorn	} else if (config.tx == ANTENNA_SW_DIVERSITY)
153bdfa500b8b8ca87dfe7a311f569fe8b39746c299Ivo van Doorn		config.tx = active->tx;
154bdfa500b8b8ca87dfe7a311f569fe8b39746c299Ivo van Doorn
15569f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn	/*
156e25c4bb913e54d729631ba7eb50daf1d9aacbef6Ivo van Doorn	 * Antenna setup changes require the RX to be disabled,
157e25c4bb913e54d729631ba7eb50daf1d9aacbef6Ivo van Doorn	 * else the changes will be ignored by the device.
158e25c4bb913e54d729631ba7eb50daf1d9aacbef6Ivo van Doorn	 */
1590262ab0df64a67d4c0ed7577a29b7d866819cc68Ivo van Doorn	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
1600b7fde54f94979edc67bbf86b5adba702ebfefe8Ivo van Doorn		rt2x00queue_stop_queue(rt2x00dev->rx);
161e25c4bb913e54d729631ba7eb50daf1d9aacbef6Ivo van Doorn
162e25c4bb913e54d729631ba7eb50daf1d9aacbef6Ivo van Doorn	/*
16369f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn	 * Write new antenna setup to device and reset the link tuner.
16469f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn	 * The latter is required since we need to recalibrate the
16569f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn	 * noise-sensitivity ratio for the new setup.
16669f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn	 */
167bdfa500b8b8ca87dfe7a311f569fe8b39746c299Ivo van Doorn	rt2x00dev->ops->lib->config_ant(rt2x00dev, &config);
168e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn
16984e3196ff867c623056eea02c11a45e046490d89Ivo van Doorn	rt2x00link_reset_tuner(rt2x00dev, true);
17069f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn
171bdfa500b8b8ca87dfe7a311f569fe8b39746c299Ivo van Doorn	memcpy(active, &config, sizeof(config));
172e25c4bb913e54d729631ba7eb50daf1d9aacbef6Ivo van Doorn
1730262ab0df64a67d4c0ed7577a29b7d866819cc68Ivo van Doorn	if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
1740b7fde54f94979edc67bbf86b5adba702ebfefe8Ivo van Doorn		rt2x00queue_start_queue(rt2x00dev->rx);
17569f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn}
17669f81a2cac860cf183eb9ef7787525c3552d4612Ivo van Doorn
17746a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerdestatic u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
17846a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde				   struct ieee80211_conf *conf)
17946a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde{
18046a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	struct hw_mode_spec *spec = &rt2x00dev->spec;
18146a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	int center_channel;
18246a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	u16 i;
18346a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde
18446a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	/*
18546a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	 * Initialize center channel to current channel.
18646a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	 */
18746a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	center_channel = spec->channels[conf->channel->hw_value].channel;
18846a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde
18946a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	/*
19046a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	 * Adjust center channel to HT40+ and HT40- operation.
19146a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	 */
19246a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	if (conf_is_ht40_plus(conf))
19346a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde		center_channel += 2;
19446a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	else if (conf_is_ht40_minus(conf))
19546a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde		center_channel -= (center_channel == 14) ? 1 : 2;
19646a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde
19746a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	for (i = 0; i < spec->num_channels; i++)
19846a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde		if (spec->channels[i].channel == center_channel)
19946a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde			return i;
20046a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde
20146a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	WARN_ON(1);
20246a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde	return conf->channel->hw_value;
20346a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde}
20446a01ec00d05581c5bd0c37e680d5b37af4953b4Gertjan van Wingerde
205066cb637b1b562bebd09d237bfaaca6724f247e5Ivo van Doornvoid rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
206e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn		      struct ieee80211_conf *conf,
207e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn		      unsigned int ieee80211_flags)
20895ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn{
2095c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn	struct rt2x00lib_conf libconf;
21006443e46c65915d74b03fe1de10c00748e4706eeGertjan van Wingerde	u16 hw_value;
2111c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	u16 autowake_timeout;
2121c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	u16 beacon_int;
2131c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	u16 beacon_diff;
21495ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
2155c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn	memset(&libconf, 0, sizeof(libconf));
2165c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn
217e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	libconf.conf = conf;
2185c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn
219e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
22006443e46c65915d74b03fe1de10c00748e4706eeGertjan van Wingerde		if (conf_is_ht40(conf)) {
2217dab73b37f5e8885cb73efd25e73861f9b4f0246Ivo van Doorn			set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
22206443e46c65915d74b03fe1de10c00748e4706eeGertjan van Wingerde			hw_value = rt2x00ht_center_channel(rt2x00dev, conf);
22306443e46c65915d74b03fe1de10c00748e4706eeGertjan van Wingerde		} else {
2247dab73b37f5e8885cb73efd25e73861f9b4f0246Ivo van Doorn			clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
22506443e46c65915d74b03fe1de10c00748e4706eeGertjan van Wingerde			hw_value = conf->channel->hw_value;
22606443e46c65915d74b03fe1de10c00748e4706eeGertjan van Wingerde		}
22735f00cfcc06bb85e0659f9847400518008d78145Ivo van Doorn
2285c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn		memcpy(&libconf.rf,
22906443e46c65915d74b03fe1de10c00748e4706eeGertjan van Wingerde		       &rt2x00dev->spec.channels[hw_value],
2305c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn		       sizeof(libconf.rf));
2318c5e7a5f59f9d11597bd47de28334da318ea0e80Ivo van Doorn
2328c5e7a5f59f9d11597bd47de28334da318ea0e80Ivo van Doorn		memcpy(&libconf.channel,
23306443e46c65915d74b03fe1de10c00748e4706eeGertjan van Wingerde		       &rt2x00dev->spec.channels_info[hw_value],
2348c5e7a5f59f9d11597bd47de28334da318ea0e80Ivo van Doorn		       sizeof(libconf.channel));
2352e9c43dd45ced5bd77c94d4216f96b4a49448d73John Li
2362e9c43dd45ced5bd77c94d4216f96b4a49448d73John Li		/* Used for VCO periodic calibration */
2372e9c43dd45ced5bd77c94d4216f96b4a49448d73John Li		rt2x00dev->rf_channel = libconf.rf.channel;
2385c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn	}
2395c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn
2401c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
2411c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	    (ieee80211_flags & IEEE80211_CONF_CHANGE_PS))
2421c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn		cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
2431c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn
2445c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn	/*
2455c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn	 * Start configuration.
2465c58ee51ff8c0aca74c225e0263bc5dd2b917781Ivo van Doorn	 */
247e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags);
24895ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
24995ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	/*
25095ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	 * Some configuration changes affect the link quality
25195ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	 * which means we need to reset the link tuner.
25295ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	 */
253e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
25484e3196ff867c623056eea02c11a45e046490d89Ivo van Doorn		rt2x00link_reset_tuner(rt2x00dev, false);
25595ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn
2563bb42a64960253353278876ca8da6b0a7d3bea87Stanislaw Gruszka	if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
2573bb42a64960253353278876ca8da6b0a7d3bea87Stanislaw Gruszka	    test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
2581c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	    (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) &&
2591c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	    (conf->flags & IEEE80211_CONF_PS)) {
2601c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn		beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon;
2611c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn		beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int);
2621c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn
2631c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn		if (beacon_diff > beacon_int)
2641c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn			beacon_diff = 0;
2651c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn
2661c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn		autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff;
2671c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn		queue_delayed_work(rt2x00dev->workqueue,
2681c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn				   &rt2x00dev->autowakeup_work,
2691c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn				   autowake_timeout - 15);
2701c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	}
2711c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn
2721c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	if (conf->flags & IEEE80211_CONF_PS)
2731c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn		set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
2741c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn	else
2751c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn		clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
2761c0bcf89d85cc97a0d9ce4cd909351a81fa4fddeIvo van Doorn
277e4ea1c403acece78c271bf9cd6f797d1cb093df9Ivo van Doorn	rt2x00dev->curr_band = conf->channel->band;
278e5ef5bad345f97f1fef7ccdc01a88c298629a5d9Ivo van Doorn	rt2x00dev->curr_freq = conf->channel->center_freq;
27995ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn	rt2x00dev->tx_power = conf->power_level;
28042c8285767dd17f450d986bdb163a8d56fb0330aIvo van Doorn	rt2x00dev->short_retry = conf->short_frame_max_tx_count;
28142c8285767dd17f450d986bdb163a8d56fb0330aIvo van Doorn	rt2x00dev->long_retry = conf->long_frame_max_tx_count;
28295ea36275f3c9a1d3d04c217b4b576c657c4e70eIvo van Doorn}
283