]>
Commit | Line | Data |
---|---|---|
95ea3627 | 1 | /* |
811aa9ca | 2 | Copyright (C) 2004 - 2008 rt2x00 SourceForge Project |
95ea3627 ID |
3 | <http://rt2x00.serialmonkey.com> |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the | |
17 | Free Software Foundation, Inc., | |
18 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 | */ | |
20 | ||
21 | /* | |
22 | Module: rt2x00lib | |
23 | Abstract: rt2x00 generic configuration routines. | |
24 | */ | |
25 | ||
95ea3627 ID |
26 | #include <linux/kernel.h> |
27 | #include <linux/module.h> | |
28 | ||
29 | #include "rt2x00.h" | |
30 | #include "rt2x00lib.h" | |
31 | ||
4abee4bb ID |
32 | |
33 | /* | |
34 | * The MAC and BSSID addressess are simple array of bytes, | |
35 | * these arrays are little endian, so when sending the addressess | |
36 | * to the drivers, copy the it into a endian-signed variable. | |
37 | * | |
38 | * Note that all devices (except rt2500usb) have 32 bits | |
39 | * register word sizes. This means that whatever variable we | |
40 | * pass _must_ be a multiple of 32 bits. Otherwise the device | |
41 | * might not accept what we are sending to it. | |
42 | * This will also make it easier for the driver to write | |
43 | * the data to the device. | |
44 | * | |
45 | * Also note that when NULL is passed as address the | |
46 | * we will send 00:00:00:00:00 to the device to clear the address. | |
47 | * This will prevent the device being confused when it wants | |
48 | * to ACK frames or consideres itself associated. | |
49 | */ | |
95ea3627 ID |
50 | void rt2x00lib_config_mac_addr(struct rt2x00_dev *rt2x00dev, u8 *mac) |
51 | { | |
4abee4bb ID |
52 | __le32 reg[2]; |
53 | ||
54 | memset(®, 0, sizeof(reg)); | |
95ea3627 | 55 | if (mac) |
4abee4bb ID |
56 | memcpy(®, mac, ETH_ALEN); |
57 | ||
58 | rt2x00dev->ops->lib->config_mac_addr(rt2x00dev, ®[0]); | |
95ea3627 ID |
59 | } |
60 | ||
61 | void rt2x00lib_config_bssid(struct rt2x00_dev *rt2x00dev, u8 *bssid) | |
62 | { | |
4abee4bb ID |
63 | __le32 reg[2]; |
64 | ||
65 | memset(®, 0, sizeof(reg)); | |
95ea3627 | 66 | if (bssid) |
4abee4bb ID |
67 | memcpy(®, bssid, ETH_ALEN); |
68 | ||
69 | rt2x00dev->ops->lib->config_bssid(rt2x00dev, ®[0]); | |
95ea3627 ID |
70 | } |
71 | ||
feb24691 | 72 | void rt2x00lib_config_type(struct rt2x00_dev *rt2x00dev, const int type) |
95ea3627 | 73 | { |
feb24691 ID |
74 | int tsf_sync; |
75 | ||
76 | switch (type) { | |
77 | case IEEE80211_IF_TYPE_IBSS: | |
78 | case IEEE80211_IF_TYPE_AP: | |
79 | tsf_sync = TSF_SYNC_BEACON; | |
80 | break; | |
81 | case IEEE80211_IF_TYPE_STA: | |
82 | tsf_sync = TSF_SYNC_INFRA; | |
83 | break; | |
84 | default: | |
85 | tsf_sync = TSF_SYNC_NONE; | |
86 | break; | |
87 | } | |
88 | ||
89 | rt2x00dev->ops->lib->config_type(rt2x00dev, type, tsf_sync); | |
95ea3627 ID |
90 | } |
91 | ||
69f81a2c ID |
92 | void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, |
93 | enum antenna rx, enum antenna tx) | |
94 | { | |
95 | struct rt2x00lib_conf libconf; | |
96 | ||
97 | libconf.ant.rx = rx; | |
98 | libconf.ant.tx = tx; | |
99 | ||
05253c93 ID |
100 | if (rx == rt2x00dev->link.ant.active.rx && |
101 | tx == rt2x00dev->link.ant.active.tx) | |
102 | return; | |
103 | ||
e25c4bb9 ID |
104 | /* |
105 | * Antenna setup changes require the RX to be disabled, | |
106 | * else the changes will be ignored by the device. | |
107 | */ | |
108 | if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) | |
61667d8d | 109 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF_LINK); |
e25c4bb9 | 110 | |
69f81a2c ID |
111 | /* |
112 | * Write new antenna setup to device and reset the link tuner. | |
113 | * The latter is required since we need to recalibrate the | |
114 | * noise-sensitivity ratio for the new setup. | |
115 | */ | |
116 | rt2x00dev->ops->lib->config(rt2x00dev, CONFIG_UPDATE_ANTENNA, &libconf); | |
117 | rt2x00lib_reset_link_tuner(rt2x00dev); | |
118 | ||
119 | rt2x00dev->link.ant.active.rx = libconf.ant.rx; | |
120 | rt2x00dev->link.ant.active.tx = libconf.ant.tx; | |
e25c4bb9 ID |
121 | |
122 | if (test_bit(DEVICE_ENABLED_RADIO, &rt2x00dev->flags)) | |
61667d8d | 123 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON_LINK); |
69f81a2c ID |
124 | } |
125 | ||
066cb637 ID |
126 | void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, |
127 | struct ieee80211_conf *conf, const int force_config) | |
95ea3627 | 128 | { |
5c58ee51 ID |
129 | struct rt2x00lib_conf libconf; |
130 | struct ieee80211_hw_mode *mode; | |
131 | struct ieee80211_rate *rate; | |
addc81bd | 132 | struct antenna_setup *default_ant = &rt2x00dev->default_ant; |
69f81a2c | 133 | struct antenna_setup *active_ant = &rt2x00dev->link.ant.active; |
95ea3627 | 134 | int flags = 0; |
5c58ee51 | 135 | int short_slot_time; |
95ea3627 ID |
136 | |
137 | /* | |
066cb637 ID |
138 | * In some situations we want to force all configurations |
139 | * to be reloaded (When resuming for instance). | |
95ea3627 | 140 | */ |
066cb637 | 141 | if (force_config) { |
95ea3627 ID |
142 | flags = CONFIG_UPDATE_ALL; |
143 | goto config; | |
144 | } | |
145 | ||
146 | /* | |
147 | * Check which configuration options have been | |
148 | * updated and should be send to the device. | |
149 | */ | |
150 | if (rt2x00dev->rx_status.phymode != conf->phymode) | |
151 | flags |= CONFIG_UPDATE_PHYMODE; | |
152 | if (rt2x00dev->rx_status.channel != conf->channel) | |
153 | flags |= CONFIG_UPDATE_CHANNEL; | |
154 | if (rt2x00dev->tx_power != conf->power_level) | |
155 | flags |= CONFIG_UPDATE_TXPOWER; | |
addc81bd ID |
156 | |
157 | /* | |
158 | * Determining changes in the antenna setups request several checks: | |
159 | * antenna_sel_{r,t}x = 0 | |
160 | * -> Does active_{r,t}x match default_{r,t}x | |
161 | * -> Is default_{r,t}x SW_DIVERSITY | |
162 | * antenna_sel_{r,t}x = 1/2 | |
163 | * -> Does active_{r,t}x match antenna_sel_{r,t}x | |
164 | * The reason for not updating the antenna while SW diversity | |
165 | * should be used is simple: Software diversity means that | |
166 | * we should switch between the antenna's based on the | |
167 | * quality. This means that the current antenna is good enough | |
168 | * to work with untill the link tuner decides that an antenna | |
169 | * switch should be performed. | |
170 | */ | |
171 | if (!conf->antenna_sel_rx && | |
172 | default_ant->rx != ANTENNA_SW_DIVERSITY && | |
173 | default_ant->rx != active_ant->rx) | |
174 | flags |= CONFIG_UPDATE_ANTENNA; | |
175 | else if (conf->antenna_sel_rx && | |
176 | conf->antenna_sel_rx != active_ant->rx) | |
177 | flags |= CONFIG_UPDATE_ANTENNA; | |
16b1951f MN |
178 | else if (active_ant->rx == ANTENNA_SW_DIVERSITY) |
179 | flags |= CONFIG_UPDATE_ANTENNA; | |
addc81bd ID |
180 | |
181 | if (!conf->antenna_sel_tx && | |
182 | default_ant->tx != ANTENNA_SW_DIVERSITY && | |
183 | default_ant->tx != active_ant->tx) | |
184 | flags |= CONFIG_UPDATE_ANTENNA; | |
185 | else if (conf->antenna_sel_tx && | |
186 | conf->antenna_sel_tx != active_ant->tx) | |
95ea3627 | 187 | flags |= CONFIG_UPDATE_ANTENNA; |
16b1951f MN |
188 | else if (active_ant->tx == ANTENNA_SW_DIVERSITY) |
189 | flags |= CONFIG_UPDATE_ANTENNA; | |
95ea3627 ID |
190 | |
191 | /* | |
192 | * The following configuration options are never | |
193 | * stored anywhere and will always be updated. | |
194 | */ | |
195 | flags |= CONFIG_UPDATE_SLOT_TIME; | |
196 | flags |= CONFIG_UPDATE_BEACON_INT; | |
197 | ||
5c58ee51 ID |
198 | /* |
199 | * We have determined what options should be updated, | |
200 | * now precalculate device configuration values depending | |
201 | * on what configuration options need to be updated. | |
202 | */ | |
95ea3627 | 203 | config: |
5c58ee51 ID |
204 | memset(&libconf, 0, sizeof(libconf)); |
205 | ||
206 | if (flags & CONFIG_UPDATE_PHYMODE) { | |
207 | switch (conf->phymode) { | |
208 | case MODE_IEEE80211A: | |
209 | libconf.phymode = HWMODE_A; | |
210 | break; | |
211 | case MODE_IEEE80211B: | |
212 | libconf.phymode = HWMODE_B; | |
213 | break; | |
214 | case MODE_IEEE80211G: | |
215 | libconf.phymode = HWMODE_G; | |
216 | break; | |
217 | default: | |
218 | ERROR(rt2x00dev, | |
219 | "Attempt to configure unsupported mode (%d)" | |
220 | "Defaulting to 802.11b", conf->phymode); | |
221 | libconf.phymode = HWMODE_B; | |
222 | } | |
223 | ||
224 | mode = &rt2x00dev->hwmodes[libconf.phymode]; | |
225 | rate = &mode->rates[mode->num_rates - 1]; | |
226 | ||
227 | libconf.basic_rates = | |
228 | DEVICE_GET_RATE_FIELD(rate->val, RATEMASK) & DEV_BASIC_RATEMASK; | |
229 | } | |
230 | ||
231 | if (flags & CONFIG_UPDATE_CHANNEL) { | |
232 | memcpy(&libconf.rf, | |
233 | &rt2x00dev->spec.channels[conf->channel_val], | |
234 | sizeof(libconf.rf)); | |
235 | } | |
236 | ||
addc81bd ID |
237 | if (flags & CONFIG_UPDATE_ANTENNA) { |
238 | if (conf->antenna_sel_rx) | |
239 | libconf.ant.rx = conf->antenna_sel_rx; | |
240 | else if (default_ant->rx != ANTENNA_SW_DIVERSITY) | |
241 | libconf.ant.rx = default_ant->rx; | |
242 | else if (active_ant->rx == ANTENNA_SW_DIVERSITY) | |
243 | libconf.ant.rx = ANTENNA_B; | |
244 | ||
245 | if (conf->antenna_sel_tx) | |
246 | libconf.ant.tx = conf->antenna_sel_tx; | |
247 | else if (default_ant->tx != ANTENNA_SW_DIVERSITY) | |
248 | libconf.ant.tx = default_ant->tx; | |
249 | else if (active_ant->tx == ANTENNA_SW_DIVERSITY) | |
250 | libconf.ant.tx = ANTENNA_B; | |
251 | } | |
252 | ||
5c58ee51 ID |
253 | if (flags & CONFIG_UPDATE_SLOT_TIME) { |
254 | short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; | |
255 | ||
256 | libconf.slot_time = | |
257 | short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME; | |
258 | libconf.sifs = SIFS; | |
259 | libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS; | |
260 | libconf.difs = short_slot_time ? SHORT_DIFS : DIFS; | |
261 | libconf.eifs = EIFS; | |
262 | } | |
263 | ||
264 | libconf.conf = conf; | |
265 | ||
266 | /* | |
267 | * Start configuration. | |
268 | */ | |
269 | rt2x00dev->ops->lib->config(rt2x00dev, flags, &libconf); | |
95ea3627 ID |
270 | |
271 | /* | |
272 | * Some configuration changes affect the link quality | |
273 | * which means we need to reset the link tuner. | |
274 | */ | |
275 | if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) | |
276 | rt2x00lib_reset_link_tuner(rt2x00dev); | |
277 | ||
16b1951f MN |
278 | if (flags & CONFIG_UPDATE_PHYMODE) { |
279 | rt2x00dev->curr_hwmode = libconf.phymode; | |
280 | rt2x00dev->rx_status.phymode = conf->phymode; | |
281 | } | |
282 | ||
95ea3627 ID |
283 | rt2x00dev->rx_status.freq = conf->freq; |
284 | rt2x00dev->rx_status.channel = conf->channel; | |
285 | rt2x00dev->tx_power = conf->power_level; | |
16b1951f MN |
286 | |
287 | if (flags & CONFIG_UPDATE_ANTENNA) { | |
288 | rt2x00dev->link.ant.active.rx = libconf.ant.rx; | |
289 | rt2x00dev->link.ant.active.tx = libconf.ant.tx; | |
290 | } | |
95ea3627 | 291 | } |