diff options
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00config.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00config.c | 141 |
1 files changed, 101 insertions, 40 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 953dc4f2c6af..b704e5b183d0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c | |||
@@ -60,15 +60,15 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, | |||
60 | * Note that when NULL is passed as address we will send | 60 | * Note that when NULL is passed as address we will send |
61 | * 00:00:00:00:00 to the device to clear the address. | 61 | * 00:00:00:00:00 to the device to clear the address. |
62 | * This will prevent the device being confused when it wants | 62 | * This will prevent the device being confused when it wants |
63 | * to ACK frames or consideres itself associated. | 63 | * to ACK frames or considers itself associated. |
64 | */ | 64 | */ |
65 | memset(&conf.mac, 0, sizeof(conf.mac)); | 65 | memset(conf.mac, 0, sizeof(conf.mac)); |
66 | if (mac) | 66 | if (mac) |
67 | memcpy(&conf.mac, mac, ETH_ALEN); | 67 | memcpy(conf.mac, mac, ETH_ALEN); |
68 | 68 | ||
69 | memset(&conf.bssid, 0, sizeof(conf.bssid)); | 69 | memset(conf.bssid, 0, sizeof(conf.bssid)); |
70 | if (bssid) | 70 | if (bssid) |
71 | memcpy(&conf.bssid, bssid, ETH_ALEN); | 71 | memcpy(conf.bssid, bssid, ETH_ALEN); |
72 | 72 | ||
73 | flags |= CONFIG_UPDATE_TYPE; | 73 | flags |= CONFIG_UPDATE_TYPE; |
74 | if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)) | 74 | if (mac || (!rt2x00dev->intf_ap_count && !rt2x00dev->intf_sta_count)) |
@@ -81,7 +81,8 @@ void rt2x00lib_config_intf(struct rt2x00_dev *rt2x00dev, | |||
81 | 81 | ||
82 | void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, | 82 | void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, |
83 | struct rt2x00_intf *intf, | 83 | struct rt2x00_intf *intf, |
84 | struct ieee80211_bss_conf *bss_conf) | 84 | struct ieee80211_bss_conf *bss_conf, |
85 | u32 changed) | ||
85 | { | 86 | { |
86 | struct rt2x00lib_erp erp; | 87 | struct rt2x00lib_erp erp; |
87 | 88 | ||
@@ -99,19 +100,17 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, | |||
99 | erp.basic_rates = bss_conf->basic_rates; | 100 | erp.basic_rates = bss_conf->basic_rates; |
100 | erp.beacon_int = bss_conf->beacon_int; | 101 | erp.beacon_int = bss_conf->beacon_int; |
101 | 102 | ||
103 | /* Update the AID, this is needed for dynamic PS support */ | ||
104 | rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; | ||
105 | rt2x00dev->last_beacon = bss_conf->timestamp; | ||
106 | |||
102 | /* Update global beacon interval time, this is needed for PS support */ | 107 | /* Update global beacon interval time, this is needed for PS support */ |
103 | rt2x00dev->beacon_int = bss_conf->beacon_int; | 108 | rt2x00dev->beacon_int = bss_conf->beacon_int; |
104 | 109 | ||
105 | rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); | 110 | if (changed & BSS_CHANGED_HT) |
106 | } | 111 | erp.ht_opmode = bss_conf->ht_operation_mode; |
107 | 112 | ||
108 | static inline | 113 | rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp, changed); |
109 | enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, | ||
110 | enum antenna default_ant) | ||
111 | { | ||
112 | if (current_ant != ANTENNA_SW_DIVERSITY) | ||
113 | return current_ant; | ||
114 | return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B; | ||
115 | } | 114 | } |
116 | 115 | ||
117 | void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, | 116 | void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, |
@@ -122,35 +121,43 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, | |||
122 | struct antenna_setup *active = &rt2x00dev->link.ant.active; | 121 | struct antenna_setup *active = &rt2x00dev->link.ant.active; |
123 | 122 | ||
124 | /* | 123 | /* |
125 | * Failsafe: Make sure we are not sending the | 124 | * When the caller tries to send the SW diversity, |
126 | * ANTENNA_SW_DIVERSITY state to the driver. | 125 | * we must update the ANTENNA_RX_DIVERSITY flag to |
127 | * If that happens, fallback to hardware defaults, | 126 | * enable the antenna diversity in the link tuner. |
128 | * or our own default. | 127 | * |
129 | * If diversity handling is active for a particular antenna, | 128 | * Secondly, we must guarentee we never send the |
130 | * we shouldn't overwrite that antenna. | 129 | * software antenna diversity command to the driver. |
131 | * The calls to rt2x00lib_config_antenna_check() | ||
132 | * might have caused that we restore back to the already | ||
133 | * active setting. If that has happened we can quit. | ||
134 | */ | 130 | */ |
135 | if (!(ant->flags & ANTENNA_RX_DIVERSITY)) | 131 | if (!(ant->flags & ANTENNA_RX_DIVERSITY)) { |
136 | config.rx = rt2x00lib_config_antenna_check(config.rx, def->rx); | 132 | if (config.rx == ANTENNA_SW_DIVERSITY) { |
137 | else | 133 | ant->flags |= ANTENNA_RX_DIVERSITY; |
134 | |||
135 | if (def->rx == ANTENNA_SW_DIVERSITY) | ||
136 | config.rx = ANTENNA_B; | ||
137 | else | ||
138 | config.rx = def->rx; | ||
139 | } | ||
140 | } else if (config.rx == ANTENNA_SW_DIVERSITY) | ||
138 | config.rx = active->rx; | 141 | config.rx = active->rx; |
139 | 142 | ||
140 | if (!(ant->flags & ANTENNA_TX_DIVERSITY)) | 143 | if (!(ant->flags & ANTENNA_TX_DIVERSITY)) { |
141 | config.tx = rt2x00lib_config_antenna_check(config.tx, def->tx); | 144 | if (config.tx == ANTENNA_SW_DIVERSITY) { |
142 | else | 145 | ant->flags |= ANTENNA_TX_DIVERSITY; |
143 | config.tx = active->tx; | ||
144 | 146 | ||
145 | if (config.rx == active->rx && config.tx == active->tx) | 147 | if (def->tx == ANTENNA_SW_DIVERSITY) |
146 | return; | 148 | config.tx = ANTENNA_B; |
149 | else | ||
150 | config.tx = def->tx; | ||
151 | } | ||
152 | } else if (config.tx == ANTENNA_SW_DIVERSITY) | ||
153 | config.tx = active->tx; | ||
147 | 154 | ||
148 | /* | 155 | /* |
149 | * Antenna setup changes require the RX to be disabled, | 156 | * Antenna setup changes require the RX to be disabled, |
150 | * else the changes will be ignored by the device. | 157 | * else the changes will be ignored by the device. |
151 | */ | 158 | */ |
152 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | 159 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
153 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK); | 160 | rt2x00queue_stop_queue(rt2x00dev->rx); |
154 | 161 | ||
155 | /* | 162 | /* |
156 | * Write new antenna setup to device and reset the link tuner. | 163 | * Write new antenna setup to device and reset the link tuner. |
@@ -164,7 +171,35 @@ void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, | |||
164 | memcpy(active, &config, sizeof(config)); | 171 | memcpy(active, &config, sizeof(config)); |
165 | 172 | ||
166 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | 173 | if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
167 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); | 174 | rt2x00queue_start_queue(rt2x00dev->rx); |
175 | } | ||
176 | |||
177 | static u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev, | ||
178 | struct ieee80211_conf *conf) | ||
179 | { | ||
180 | struct hw_mode_spec *spec = &rt2x00dev->spec; | ||
181 | int center_channel; | ||
182 | u16 i; | ||
183 | |||
184 | /* | ||
185 | * Initialize center channel to current channel. | ||
186 | */ | ||
187 | center_channel = spec->channels[conf->channel->hw_value].channel; | ||
188 | |||
189 | /* | ||
190 | * Adjust center channel to HT40+ and HT40- operation. | ||
191 | */ | ||
192 | if (conf_is_ht40_plus(conf)) | ||
193 | center_channel += 2; | ||
194 | else if (conf_is_ht40_minus(conf)) | ||
195 | center_channel -= (center_channel == 14) ? 1 : 2; | ||
196 | |||
197 | for (i = 0; i < spec->num_channels; i++) | ||
198 | if (spec->channels[i].channel == center_channel) | ||
199 | return i; | ||
200 | |||
201 | WARN_ON(1); | ||
202 | return conf->channel->hw_value; | ||
168 | } | 203 | } |
169 | 204 | ||
170 | void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | 205 | void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, |
@@ -173,6 +208,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | |||
173 | { | 208 | { |
174 | struct rt2x00lib_conf libconf; | 209 | struct rt2x00lib_conf libconf; |
175 | u16 hw_value; | 210 | u16 hw_value; |
211 | u16 autowake_timeout; | ||
212 | u16 beacon_int; | ||
213 | u16 beacon_diff; | ||
176 | 214 | ||
177 | memset(&libconf, 0, sizeof(libconf)); | 215 | memset(&libconf, 0, sizeof(libconf)); |
178 | 216 | ||
@@ -180,10 +218,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | |||
180 | 218 | ||
181 | if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { | 219 | if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { |
182 | if (conf_is_ht40(conf)) { | 220 | if (conf_is_ht40(conf)) { |
183 | __set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); | 221 | set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); |
184 | hw_value = rt2x00ht_center_channel(rt2x00dev, conf); | 222 | hw_value = rt2x00ht_center_channel(rt2x00dev, conf); |
185 | } else { | 223 | } else { |
186 | __clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); | 224 | clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags); |
187 | hw_value = conf->channel->hw_value; | 225 | hw_value = conf->channel->hw_value; |
188 | } | 226 | } |
189 | 227 | ||
@@ -196,6 +234,10 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | |||
196 | sizeof(libconf.channel)); | 234 | sizeof(libconf.channel)); |
197 | } | 235 | } |
198 | 236 | ||
237 | if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && | ||
238 | (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) | ||
239 | cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); | ||
240 | |||
199 | /* | 241 | /* |
200 | * Start configuration. | 242 | * Start configuration. |
201 | */ | 243 | */ |
@@ -208,11 +250,30 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, | |||
208 | if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) | 250 | if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) |
209 | rt2x00link_reset_tuner(rt2x00dev, false); | 251 | rt2x00link_reset_tuner(rt2x00dev, false); |
210 | 252 | ||
253 | if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) && | ||
254 | test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) && | ||
255 | (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) && | ||
256 | (conf->flags & IEEE80211_CONF_PS)) { | ||
257 | beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon; | ||
258 | beacon_int = msecs_to_jiffies(rt2x00dev->beacon_int); | ||
259 | |||
260 | if (beacon_diff > beacon_int) | ||
261 | beacon_diff = 0; | ||
262 | |||
263 | autowake_timeout = (conf->max_sleep_period * beacon_int) - beacon_diff; | ||
264 | queue_delayed_work(rt2x00dev->workqueue, | ||
265 | &rt2x00dev->autowakeup_work, | ||
266 | autowake_timeout - 15); | ||
267 | } | ||
268 | |||
269 | if (conf->flags & IEEE80211_CONF_PS) | ||
270 | set_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); | ||
271 | else | ||
272 | clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags); | ||
273 | |||
211 | rt2x00dev->curr_band = conf->channel->band; | 274 | rt2x00dev->curr_band = conf->channel->band; |
275 | rt2x00dev->curr_freq = conf->channel->center_freq; | ||
212 | rt2x00dev->tx_power = conf->power_level; | 276 | rt2x00dev->tx_power = conf->power_level; |
213 | rt2x00dev->short_retry = conf->short_frame_max_tx_count; | 277 | rt2x00dev->short_retry = conf->short_frame_max_tx_count; |
214 | rt2x00dev->long_retry = conf->long_frame_max_tx_count; | 278 | rt2x00dev->long_retry = conf->long_frame_max_tx_count; |
215 | |||
216 | rt2x00dev->rx_status.band = conf->channel->band; | ||
217 | rt2x00dev->rx_status.freq = conf->channel->center_freq; | ||
218 | } | 279 | } |