diff options
author | Christian Lamparter <chunkeey@googlemail.com> | 2012-07-27 20:57:51 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-08-10 15:17:14 -0400 |
commit | 9bc63816be9bf504414d350e605a4b30f857907d (patch) | |
tree | 67fd903805199135fd7dbb8a85be615ce6a584b1 | |
parent | 57f784fed3b9a33084c0cd0f6d08d98f87d2193f (diff) |
p54: parse output power table
For the upcoming tpc changes, the driver needs
to provide sensible max output values for each
supported channel.
And while the eeprom always had a output_limit
table, which defines the upper limit for each
frequency and modulation, it was never really
useful for anything... until now.
Note: For anyone wondering about what your card
is calibrated for: check "iw list".
* 2412 MHz [1] (18.0 dBm)
* 2437 MHz [6] (19.0 dBm)
[...]
* 5180 MHz [36] (18.0 dBm)
* 5260 MHz [52] (17.0 dBm) (radar detection)
* 5680 MHz [136] (19.0 dBm) (radar detection)
(for a Dell Wireless 1450 USB Adapter)
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/p54/eeprom.c | 104 | ||||
-rw-r--r-- | drivers/net/wireless/p54/eeprom.h | 12 |
2 files changed, 92 insertions, 24 deletions
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index 14037092ba89..d4d86107e05a 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c | |||
@@ -76,6 +76,7 @@ struct p54_channel_entry { | |||
76 | u16 freq; | 76 | u16 freq; |
77 | u16 data; | 77 | u16 data; |
78 | int index; | 78 | int index; |
79 | int max_power; | ||
79 | enum ieee80211_band band; | 80 | enum ieee80211_band band; |
80 | }; | 81 | }; |
81 | 82 | ||
@@ -173,6 +174,7 @@ static int p54_generate_band(struct ieee80211_hw *dev, | |||
173 | for (i = 0, j = 0; (j < list->band_channel_num[band]) && | 174 | for (i = 0, j = 0; (j < list->band_channel_num[band]) && |
174 | (i < list->entries); i++) { | 175 | (i < list->entries); i++) { |
175 | struct p54_channel_entry *chan = &list->channels[i]; | 176 | struct p54_channel_entry *chan = &list->channels[i]; |
177 | struct ieee80211_channel *dest = &tmp->channels[j]; | ||
176 | 178 | ||
177 | if (chan->band != band) | 179 | if (chan->band != band) |
178 | continue; | 180 | continue; |
@@ -190,14 +192,15 @@ static int p54_generate_band(struct ieee80211_hw *dev, | |||
190 | continue; | 192 | continue; |
191 | } | 193 | } |
192 | 194 | ||
193 | tmp->channels[j].band = chan->band; | 195 | dest->band = chan->band; |
194 | tmp->channels[j].center_freq = chan->freq; | 196 | dest->center_freq = chan->freq; |
197 | dest->max_power = chan->max_power; | ||
195 | priv->survey[*chan_num].channel = &tmp->channels[j]; | 198 | priv->survey[*chan_num].channel = &tmp->channels[j]; |
196 | priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM | | 199 | priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM | |
197 | SURVEY_INFO_CHANNEL_TIME | | 200 | SURVEY_INFO_CHANNEL_TIME | |
198 | SURVEY_INFO_CHANNEL_TIME_BUSY | | 201 | SURVEY_INFO_CHANNEL_TIME_BUSY | |
199 | SURVEY_INFO_CHANNEL_TIME_TX; | 202 | SURVEY_INFO_CHANNEL_TIME_TX; |
200 | tmp->channels[j].hw_value = (*chan_num); | 203 | dest->hw_value = (*chan_num); |
201 | j++; | 204 | j++; |
202 | (*chan_num)++; | 205 | (*chan_num)++; |
203 | } | 206 | } |
@@ -229,10 +232,11 @@ err_out: | |||
229 | return ret; | 232 | return ret; |
230 | } | 233 | } |
231 | 234 | ||
232 | static void p54_update_channel_param(struct p54_channel_list *list, | 235 | static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list, |
233 | u16 freq, u16 data) | 236 | u16 freq, u16 data) |
234 | { | 237 | { |
235 | int band, i; | 238 | int i; |
239 | struct p54_channel_entry *entry = NULL; | ||
236 | 240 | ||
237 | /* | 241 | /* |
238 | * usually all lists in the eeprom are mostly sorted. | 242 | * usually all lists in the eeprom are mostly sorted. |
@@ -241,30 +245,74 @@ static void p54_update_channel_param(struct p54_channel_list *list, | |||
241 | */ | 245 | */ |
242 | for (i = list->entries; i >= 0; i--) { | 246 | for (i = list->entries; i >= 0; i--) { |
243 | if (freq == list->channels[i].freq) { | 247 | if (freq == list->channels[i].freq) { |
244 | list->channels[i].data |= data; | 248 | entry = &list->channels[i]; |
245 | break; | 249 | break; |
246 | } | 250 | } |
247 | } | 251 | } |
248 | 252 | ||
249 | if ((i < 0) && (list->entries < list->max_entries)) { | 253 | if ((i < 0) && (list->entries < list->max_entries)) { |
250 | /* entry does not exist yet. Initialize a new one. */ | 254 | /* entry does not exist yet. Initialize a new one. */ |
251 | band = p54_get_band_from_freq(freq); | 255 | int band = p54_get_band_from_freq(freq); |
252 | 256 | ||
253 | /* | 257 | /* |
254 | * filter out frequencies which don't belong into | 258 | * filter out frequencies which don't belong into |
255 | * any supported band. | 259 | * any supported band. |
256 | */ | 260 | */ |
257 | if (band < 0) | 261 | if (band >= 0) { |
258 | return ; | 262 | i = list->entries++; |
263 | list->band_channel_num[band]++; | ||
264 | |||
265 | entry = &list->channels[i]; | ||
266 | entry->freq = freq; | ||
267 | entry->band = band; | ||
268 | entry->index = ieee80211_frequency_to_channel(freq); | ||
269 | entry->max_power = 0; | ||
270 | entry->data = 0; | ||
271 | } | ||
272 | } | ||
259 | 273 | ||
260 | i = list->entries++; | 274 | if (entry) |
261 | list->band_channel_num[band]++; | 275 | entry->data |= data; |
262 | 276 | ||
263 | list->channels[i].freq = freq; | 277 | return entry; |
264 | list->channels[i].data = data; | 278 | } |
265 | list->channels[i].band = band; | 279 | |
266 | list->channels[i].index = ieee80211_frequency_to_channel(freq); | 280 | static int p54_get_maxpower(struct p54_common *priv, void *data) |
267 | /* TODO: parse output_limit and fill max_power */ | 281 | { |
282 | switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) { | ||
283 | case PDR_SYNTH_FRONTEND_LONGBOW: { | ||
284 | struct pda_channel_output_limit_longbow *pda = data; | ||
285 | int j; | ||
286 | u16 rawpower = 0; | ||
287 | pda = data; | ||
288 | for (j = 0; j < ARRAY_SIZE(pda->point); j++) { | ||
289 | struct pda_channel_output_limit_point_longbow *point = | ||
290 | &pda->point[j]; | ||
291 | rawpower = max(rawpower, le16_to_cpu(point->val_qpsk)); | ||
292 | rawpower = max(rawpower, le16_to_cpu(point->val_bpsk)); | ||
293 | rawpower = max(rawpower, le16_to_cpu(point->val_16qam)); | ||
294 | rawpower = max(rawpower, le16_to_cpu(point->val_64qam)); | ||
295 | } | ||
296 | /* longbow seems to use 1/16 dBm units */ | ||
297 | return rawpower / 16; | ||
298 | } | ||
299 | |||
300 | case PDR_SYNTH_FRONTEND_DUETTE3: | ||
301 | case PDR_SYNTH_FRONTEND_DUETTE2: | ||
302 | case PDR_SYNTH_FRONTEND_FRISBEE: | ||
303 | case PDR_SYNTH_FRONTEND_XBOW: { | ||
304 | struct pda_channel_output_limit *pda = data; | ||
305 | u8 rawpower = 0; | ||
306 | rawpower = max(rawpower, pda->val_qpsk); | ||
307 | rawpower = max(rawpower, pda->val_bpsk); | ||
308 | rawpower = max(rawpower, pda->val_16qam); | ||
309 | rawpower = max(rawpower, pda->val_64qam); | ||
310 | /* raw values are in 1/4 dBm units */ | ||
311 | return rawpower / 4; | ||
312 | } | ||
313 | |||
314 | default: | ||
315 | return 20; | ||
268 | } | 316 | } |
269 | } | 317 | } |
270 | 318 | ||
@@ -315,12 +363,19 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev) | |||
315 | } | 363 | } |
316 | 364 | ||
317 | if (i < priv->output_limit->entries) { | 365 | if (i < priv->output_limit->entries) { |
318 | freq = le16_to_cpup((__le16 *) (i * | 366 | struct p54_channel_entry *tmp; |
319 | priv->output_limit->entry_size + | 367 | |
320 | priv->output_limit->offset + | 368 | void *data = (void *) ((unsigned long) i * |
321 | priv->output_limit->data)); | 369 | priv->output_limit->entry_size + |
322 | 370 | priv->output_limit->offset + | |
323 | p54_update_channel_param(list, freq, CHAN_HAS_LIMIT); | 371 | priv->output_limit->data); |
372 | |||
373 | freq = le16_to_cpup((__le16 *) data); | ||
374 | tmp = p54_update_channel_param(list, freq, | ||
375 | CHAN_HAS_LIMIT); | ||
376 | if (tmp) { | ||
377 | tmp->max_power = p54_get_maxpower(priv, data); | ||
378 | } | ||
324 | } | 379 | } |
325 | 380 | ||
326 | if (i < priv->curve_data->entries) { | 381 | if (i < priv->curve_data->entries) { |
@@ -834,11 +889,12 @@ good_eeprom: | |||
834 | goto err; | 889 | goto err; |
835 | } | 890 | } |
836 | 891 | ||
892 | priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; | ||
893 | |||
837 | err = p54_generate_channel_lists(dev); | 894 | err = p54_generate_channel_lists(dev); |
838 | if (err) | 895 | if (err) |
839 | goto err; | 896 | goto err; |
840 | 897 | ||
841 | priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; | ||
842 | if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) | 898 | if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW) |
843 | p54_init_xbow_synth(priv); | 899 | p54_init_xbow_synth(priv); |
844 | if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) | 900 | if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) |
diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h index afde72b84606..20ebe39a3f4e 100644 --- a/drivers/net/wireless/p54/eeprom.h +++ b/drivers/net/wireless/p54/eeprom.h | |||
@@ -57,6 +57,18 @@ struct pda_channel_output_limit { | |||
57 | u8 rate_set_size; | 57 | u8 rate_set_size; |
58 | } __packed; | 58 | } __packed; |
59 | 59 | ||
60 | struct pda_channel_output_limit_point_longbow { | ||
61 | __le16 val_bpsk; | ||
62 | __le16 val_qpsk; | ||
63 | __le16 val_16qam; | ||
64 | __le16 val_64qam; | ||
65 | } __packed; | ||
66 | |||
67 | struct pda_channel_output_limit_longbow { | ||
68 | __le16 freq; | ||
69 | struct pda_channel_output_limit_point_longbow point[3]; | ||
70 | } __packed; | ||
71 | |||
60 | struct pda_pa_curve_data_sample_rev0 { | 72 | struct pda_pa_curve_data_sample_rev0 { |
61 | u8 rf_power; | 73 | u8 rf_power; |
62 | u8 pa_detector; | 74 | u8 pa_detector; |