blob: 2fe713eda7adaa0230a05bdce00f10b7e0d5f2b4 [file] [log] [blame]
Christian Lamparter4c8a32f2009-06-23 10:36:26 -05001/*
2 * EEPROM parser code for mac80211 Prism54 drivers
3 *
4 * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
5 * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
6 * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
7 *
8 * Based on:
9 * - the islsm (softmac prism54) driver, which is:
10 * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
11 * - stlc45xx driver
12 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 */
18
Christian Lamparter4c8a32f2009-06-23 10:36:26 -050019#include <linux/firmware.h>
20#include <linux/etherdevice.h>
Christian Lamparter1a9b6672009-07-11 01:22:26 +020021#include <linux/sort.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Christian Lamparter4c8a32f2009-06-23 10:36:26 -050023
24#include <net/mac80211.h>
Christian Lamparterd7eb50c2010-08-17 01:16:58 +020025#include <linux/crc-ccitt.h>
Paul Gortmakeree40fa02011-05-27 16:14:23 -040026#include <linux/export.h>
Christian Lamparter4c8a32f2009-06-23 10:36:26 -050027
28#include "p54.h"
29#include "eeprom.h"
30#include "lmac.h"
31
32static struct ieee80211_rate p54_bgrates[] = {
33 { .bitrate = 10, .hw_value = 0, },
34 { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
35 { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
36 { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
37 { .bitrate = 60, .hw_value = 4, },
38 { .bitrate = 90, .hw_value = 5, },
39 { .bitrate = 120, .hw_value = 6, },
40 { .bitrate = 180, .hw_value = 7, },
41 { .bitrate = 240, .hw_value = 8, },
42 { .bitrate = 360, .hw_value = 9, },
43 { .bitrate = 480, .hw_value = 10, },
44 { .bitrate = 540, .hw_value = 11, },
45};
46
Christian Lamparter4c8a32f2009-06-23 10:36:26 -050047static struct ieee80211_rate p54_arates[] = {
48 { .bitrate = 60, .hw_value = 4, },
49 { .bitrate = 90, .hw_value = 5, },
50 { .bitrate = 120, .hw_value = 6, },
51 { .bitrate = 180, .hw_value = 7, },
52 { .bitrate = 240, .hw_value = 8, },
53 { .bitrate = 360, .hw_value = 9, },
54 { .bitrate = 480, .hw_value = 10, },
55 { .bitrate = 540, .hw_value = 11, },
56};
57
Christian Lamparter7a047f42011-02-12 22:32:49 +010058static struct p54_rssi_db_entry p54_rssi_default = {
59 /*
60 * The defaults are taken from usb-logs of the
61 * vendor driver. So, they should be safe to
62 * use in case we can't get a match from the
63 * rssi <-> dBm conversion database.
64 */
65 .mul = 130,
66 .add = -398,
67};
68
Christian Lamparter1a9b6672009-07-11 01:22:26 +020069#define CHAN_HAS_CAL BIT(0)
70#define CHAN_HAS_LIMIT BIT(1)
71#define CHAN_HAS_CURVE BIT(2)
72#define CHAN_HAS_ALL (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
73
74struct p54_channel_entry {
75 u16 freq;
76 u16 data;
77 int index;
Christian Lamparter9bc63812012-07-28 02:57:51 +020078 int max_power;
Christian Lamparter1a9b6672009-07-11 01:22:26 +020079 enum ieee80211_band band;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -050080};
81
Christian Lamparter1a9b6672009-07-11 01:22:26 +020082struct p54_channel_list {
83 struct p54_channel_entry *channels;
84 size_t entries;
85 size_t max_entries;
86 size_t band_channel_num[IEEE80211_NUM_BANDS];
Christian Lamparter4c8a32f2009-06-23 10:36:26 -050087};
88
Christian Lamparter1a9b6672009-07-11 01:22:26 +020089static int p54_get_band_from_freq(u16 freq)
90{
91 /* FIXME: sync these values with the 802.11 spec */
92
93 if ((freq >= 2412) && (freq <= 2484))
94 return IEEE80211_BAND_2GHZ;
95
96 if ((freq >= 4920) && (freq <= 5825))
97 return IEEE80211_BAND_5GHZ;
98
99 return -1;
100}
101
Christian Lamparter7a047f42011-02-12 22:32:49 +0100102static int same_band(u16 freq, u16 freq2)
103{
104 return p54_get_band_from_freq(freq) == p54_get_band_from_freq(freq2);
105}
106
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200107static int p54_compare_channels(const void *_a,
108 const void *_b)
109{
110 const struct p54_channel_entry *a = _a;
111 const struct p54_channel_entry *b = _b;
112
Christian Lamparter192abec2011-02-12 21:49:38 +0100113 return a->freq - b->freq;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200114}
115
Christian Lamparter7a047f42011-02-12 22:32:49 +0100116static int p54_compare_rssichan(const void *_a,
117 const void *_b)
118{
119 const struct p54_rssi_db_entry *a = _a;
120 const struct p54_rssi_db_entry *b = _b;
121
122 return a->freq - b->freq;
123}
124
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200125static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
126 struct ieee80211_supported_band *band_entry,
127 enum ieee80211_band band)
128{
129 /* TODO: generate rate array dynamically */
130
131 switch (band) {
132 case IEEE80211_BAND_2GHZ:
133 band_entry->bitrates = p54_bgrates;
134 band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
135 break;
136 case IEEE80211_BAND_5GHZ:
137 band_entry->bitrates = p54_arates;
138 band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
139 break;
140 default:
141 return -EINVAL;
142 }
143
144 return 0;
145}
146
147static int p54_generate_band(struct ieee80211_hw *dev,
148 struct p54_channel_list *list,
Christian Lamparter0d781562011-08-20 01:53:59 +0200149 unsigned int *chan_num,
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200150 enum ieee80211_band band)
151{
152 struct p54_common *priv = dev->priv;
153 struct ieee80211_supported_band *tmp, *old;
154 unsigned int i, j;
155 int ret = -ENOMEM;
156
157 if ((!list->entries) || (!list->band_channel_num[band]))
Christian Lamparter93a59d72009-10-31 22:59:27 +0100158 return -EINVAL;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200159
160 tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
161 if (!tmp)
162 goto err_out;
163
164 tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
165 list->band_channel_num[band], GFP_KERNEL);
166 if (!tmp->channels)
167 goto err_out;
168
169 ret = p54_fill_band_bitrates(dev, tmp, band);
170 if (ret)
171 goto err_out;
172
173 for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
174 (i < list->entries); i++) {
Christian Lampartera3162ee2011-02-12 22:14:38 +0100175 struct p54_channel_entry *chan = &list->channels[i];
Christian Lamparter9bc63812012-07-28 02:57:51 +0200176 struct ieee80211_channel *dest = &tmp->channels[j];
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200177
Christian Lampartera3162ee2011-02-12 22:14:38 +0100178 if (chan->band != band)
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200179 continue;
180
Christian Lampartera3162ee2011-02-12 22:14:38 +0100181 if (chan->data != CHAN_HAS_ALL) {
182 wiphy_err(dev->wiphy, "%s%s%s is/are missing for "
183 "channel:%d [%d MHz].\n",
184 (chan->data & CHAN_HAS_CAL ? "" :
Joe Perchesc96c31e2010-07-26 14:39:58 -0700185 " [iqauto calibration data]"),
Christian Lampartera3162ee2011-02-12 22:14:38 +0100186 (chan->data & CHAN_HAS_LIMIT ? "" :
Joe Perchesc96c31e2010-07-26 14:39:58 -0700187 " [output power limits]"),
Christian Lampartera3162ee2011-02-12 22:14:38 +0100188 (chan->data & CHAN_HAS_CURVE ? "" :
Joe Perchesc96c31e2010-07-26 14:39:58 -0700189 " [curve data]"),
Christian Lampartera3162ee2011-02-12 22:14:38 +0100190 chan->index, chan->freq);
Christian Lamparter93a59d72009-10-31 22:59:27 +0100191 continue;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200192 }
193
Christian Lamparter9bc63812012-07-28 02:57:51 +0200194 dest->band = chan->band;
195 dest->center_freq = chan->freq;
196 dest->max_power = chan->max_power;
Christian Lamparter0d781562011-08-20 01:53:59 +0200197 priv->survey[*chan_num].channel = &tmp->channels[j];
198 priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
Johannes Berg4ed20be2014-11-14 16:35:34 +0100199 SURVEY_INFO_TIME |
200 SURVEY_INFO_TIME_BUSY |
201 SURVEY_INFO_TIME_TX;
Christian Lamparter9bc63812012-07-28 02:57:51 +0200202 dest->hw_value = (*chan_num);
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200203 j++;
Christian Lamparter0d781562011-08-20 01:53:59 +0200204 (*chan_num)++;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200205 }
206
Christian Lamparter93a59d72009-10-31 22:59:27 +0100207 if (j == 0) {
Joe Perches5db55842010-08-11 19:11:19 -0700208 wiphy_err(dev->wiphy, "Disabling totally damaged %d GHz band\n",
Joe Perchesc96c31e2010-07-26 14:39:58 -0700209 (band == IEEE80211_BAND_2GHZ) ? 2 : 5);
Christian Lamparter93a59d72009-10-31 22:59:27 +0100210
211 ret = -ENODATA;
212 goto err_out;
213 }
214
215 tmp->n_channels = j;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200216 old = priv->band_table[band];
217 priv->band_table[band] = tmp;
218 if (old) {
219 kfree(old->channels);
220 kfree(old);
221 }
222
223 return 0;
224
225err_out:
226 if (tmp) {
227 kfree(tmp->channels);
228 kfree(tmp);
229 }
230
231 return ret;
232}
233
Christian Lamparter9bc63812012-07-28 02:57:51 +0200234static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
235 u16 freq, u16 data)
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200236{
Christian Lamparter9bc63812012-07-28 02:57:51 +0200237 int i;
238 struct p54_channel_entry *entry = NULL;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200239
240 /*
241 * usually all lists in the eeprom are mostly sorted.
242 * so it's very likely that the entry we are looking for
243 * is right at the end of the list
244 */
245 for (i = list->entries; i >= 0; i--) {
246 if (freq == list->channels[i].freq) {
Christian Lamparter9bc63812012-07-28 02:57:51 +0200247 entry = &list->channels[i];
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200248 break;
249 }
250 }
251
252 if ((i < 0) && (list->entries < list->max_entries)) {
253 /* entry does not exist yet. Initialize a new one. */
Christian Lamparter9bc63812012-07-28 02:57:51 +0200254 int band = p54_get_band_from_freq(freq);
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200255
256 /*
257 * filter out frequencies which don't belong into
258 * any supported band.
259 */
Christian Lamparter9bc63812012-07-28 02:57:51 +0200260 if (band >= 0) {
261 i = list->entries++;
262 list->band_channel_num[band]++;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200263
Christian Lamparter9bc63812012-07-28 02:57:51 +0200264 entry = &list->channels[i];
265 entry->freq = freq;
266 entry->band = band;
267 entry->index = ieee80211_frequency_to_channel(freq);
268 entry->max_power = 0;
269 entry->data = 0;
270 }
271 }
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200272
Christian Lamparter9bc63812012-07-28 02:57:51 +0200273 if (entry)
274 entry->data |= data;
275
276 return entry;
277}
278
279static int p54_get_maxpower(struct p54_common *priv, void *data)
280{
281 switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) {
282 case PDR_SYNTH_FRONTEND_LONGBOW: {
283 struct pda_channel_output_limit_longbow *pda = data;
284 int j;
285 u16 rawpower = 0;
286 pda = data;
287 for (j = 0; j < ARRAY_SIZE(pda->point); j++) {
288 struct pda_channel_output_limit_point_longbow *point =
289 &pda->point[j];
Christian Lamparter22c56492012-08-11 13:09:20 +0200290 rawpower = max_t(u16,
291 rawpower, le16_to_cpu(point->val_qpsk));
292 rawpower = max_t(u16,
293 rawpower, le16_to_cpu(point->val_bpsk));
294 rawpower = max_t(u16,
295 rawpower, le16_to_cpu(point->val_16qam));
296 rawpower = max_t(u16,
297 rawpower, le16_to_cpu(point->val_64qam));
Christian Lamparter9bc63812012-07-28 02:57:51 +0200298 }
299 /* longbow seems to use 1/16 dBm units */
300 return rawpower / 16;
301 }
302
303 case PDR_SYNTH_FRONTEND_DUETTE3:
304 case PDR_SYNTH_FRONTEND_DUETTE2:
305 case PDR_SYNTH_FRONTEND_FRISBEE:
306 case PDR_SYNTH_FRONTEND_XBOW: {
307 struct pda_channel_output_limit *pda = data;
308 u8 rawpower = 0;
309 rawpower = max(rawpower, pda->val_qpsk);
310 rawpower = max(rawpower, pda->val_bpsk);
311 rawpower = max(rawpower, pda->val_16qam);
312 rawpower = max(rawpower, pda->val_64qam);
313 /* raw values are in 1/4 dBm units */
314 return rawpower / 4;
315 }
316
317 default:
318 return 20;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200319 }
320}
321
322static int p54_generate_channel_lists(struct ieee80211_hw *dev)
323{
324 struct p54_common *priv = dev->priv;
325 struct p54_channel_list *list;
Christian Lamparter0d781562011-08-20 01:53:59 +0200326 unsigned int i, j, k, max_channel_num;
Christian Lamparter93a59d72009-10-31 22:59:27 +0100327 int ret = 0;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200328 u16 freq;
329
330 if ((priv->iq_autocal_len != priv->curve_data->entries) ||
331 (priv->iq_autocal_len != priv->output_limit->entries))
Joe Perchesc96c31e2010-07-26 14:39:58 -0700332 wiphy_err(dev->wiphy,
333 "Unsupported or damaged EEPROM detected. "
334 "You may not be able to use all channels.\n");
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200335
336 max_channel_num = max_t(unsigned int, priv->output_limit->entries,
337 priv->iq_autocal_len);
338 max_channel_num = max_t(unsigned int, max_channel_num,
339 priv->curve_data->entries);
340
341 list = kzalloc(sizeof(*list), GFP_KERNEL);
Christian Lamparter93a59d72009-10-31 22:59:27 +0100342 if (!list) {
343 ret = -ENOMEM;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200344 goto free;
Christian Lamparter93a59d72009-10-31 22:59:27 +0100345 }
Christian Lamparter0d781562011-08-20 01:53:59 +0200346 priv->chan_num = max_channel_num;
347 priv->survey = kzalloc(sizeof(struct survey_info) * max_channel_num,
348 GFP_KERNEL);
349 if (!priv->survey) {
350 ret = -ENOMEM;
351 goto free;
352 }
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200353
354 list->max_entries = max_channel_num;
355 list->channels = kzalloc(sizeof(struct p54_channel_entry) *
356 max_channel_num, GFP_KERNEL);
Julia Lawall0d91f222010-10-15 15:00:06 +0200357 if (!list->channels) {
358 ret = -ENOMEM;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200359 goto free;
Julia Lawall0d91f222010-10-15 15:00:06 +0200360 }
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200361
362 for (i = 0; i < max_channel_num; i++) {
363 if (i < priv->iq_autocal_len) {
364 freq = le16_to_cpu(priv->iq_autocal[i].freq);
365 p54_update_channel_param(list, freq, CHAN_HAS_CAL);
366 }
367
368 if (i < priv->output_limit->entries) {
Christian Lamparter9bc63812012-07-28 02:57:51 +0200369 struct p54_channel_entry *tmp;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200370
Christian Lamparter9bc63812012-07-28 02:57:51 +0200371 void *data = (void *) ((unsigned long) i *
372 priv->output_limit->entry_size +
373 priv->output_limit->offset +
374 priv->output_limit->data);
375
376 freq = le16_to_cpup((__le16 *) data);
377 tmp = p54_update_channel_param(list, freq,
378 CHAN_HAS_LIMIT);
379 if (tmp) {
380 tmp->max_power = p54_get_maxpower(priv, data);
381 }
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200382 }
383
384 if (i < priv->curve_data->entries) {
385 freq = le16_to_cpup((__le16 *) (i *
386 priv->curve_data->entry_size +
387 priv->curve_data->offset +
388 priv->curve_data->data));
389
390 p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
391 }
392 }
393
Christian Lamparter192abec2011-02-12 21:49:38 +0100394 /* sort the channel list by frequency */
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200395 sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
396 p54_compare_channels, NULL);
397
Christian Lamparter0d781562011-08-20 01:53:59 +0200398 k = 0;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200399 for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
Christian Lamparter0d781562011-08-20 01:53:59 +0200400 if (p54_generate_band(dev, list, &k, i) == 0)
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200401 j++;
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200402 }
403 if (j == 0) {
404 /* no useable band available. */
405 ret = -EINVAL;
406 }
407
408free:
409 if (list) {
410 kfree(list->channels);
411 kfree(list);
412 }
Christian Lamparter0d781562011-08-20 01:53:59 +0200413 if (ret) {
414 kfree(priv->survey);
415 priv->survey = NULL;
416 }
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200417
418 return ret;
419}
420
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500421static int p54_convert_rev0(struct ieee80211_hw *dev,
422 struct pda_pa_curve_data *curve_data)
423{
424 struct p54_common *priv = dev->priv;
425 struct p54_pa_curve_data_sample *dst;
426 struct pda_pa_curve_data_sample_rev0 *src;
427 size_t cd_len = sizeof(*curve_data) +
428 (curve_data->points_per_channel*sizeof(*dst) + 2) *
429 curve_data->channels;
430 unsigned int i, j;
431 void *source, *target;
432
433 priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
434 GFP_KERNEL);
435 if (!priv->curve_data)
436 return -ENOMEM;
437
438 priv->curve_data->entries = curve_data->channels;
439 priv->curve_data->entry_size = sizeof(__le16) +
440 sizeof(*dst) * curve_data->points_per_channel;
441 priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
442 priv->curve_data->len = cd_len;
443 memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
444 source = curve_data->data;
445 target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
446 for (i = 0; i < curve_data->channels; i++) {
447 __le16 *freq = source;
448 source += sizeof(__le16);
449 *((__le16 *)target) = *freq;
450 target += sizeof(__le16);
451 for (j = 0; j < curve_data->points_per_channel; j++) {
452 dst = target;
453 src = source;
454
455 dst->rf_power = src->rf_power;
456 dst->pa_detector = src->pa_detector;
457 dst->data_64qam = src->pcv;
458 /* "invent" the points for the other modulations */
459#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
460 dst->data_16qam = SUB(src->pcv, 12);
461 dst->data_qpsk = SUB(dst->data_16qam, 12);
462 dst->data_bpsk = SUB(dst->data_qpsk, 12);
463 dst->data_barker = SUB(dst->data_bpsk, 14);
464#undef SUB
465 target += sizeof(*dst);
466 source += sizeof(*src);
467 }
468 }
469
470 return 0;
471}
472
473static int p54_convert_rev1(struct ieee80211_hw *dev,
474 struct pda_pa_curve_data *curve_data)
475{
476 struct p54_common *priv = dev->priv;
477 struct p54_pa_curve_data_sample *dst;
478 struct pda_pa_curve_data_sample_rev1 *src;
479 size_t cd_len = sizeof(*curve_data) +
480 (curve_data->points_per_channel*sizeof(*dst) + 2) *
481 curve_data->channels;
482 unsigned int i, j;
483 void *source, *target;
484
485 priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
486 GFP_KERNEL);
487 if (!priv->curve_data)
488 return -ENOMEM;
489
490 priv->curve_data->entries = curve_data->channels;
491 priv->curve_data->entry_size = sizeof(__le16) +
492 sizeof(*dst) * curve_data->points_per_channel;
493 priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
494 priv->curve_data->len = cd_len;
495 memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
496 source = curve_data->data;
497 target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
498 for (i = 0; i < curve_data->channels; i++) {
499 __le16 *freq = source;
500 source += sizeof(__le16);
501 *((__le16 *)target) = *freq;
502 target += sizeof(__le16);
503 for (j = 0; j < curve_data->points_per_channel; j++) {
504 memcpy(target, source, sizeof(*src));
505
506 target += sizeof(*dst);
507 source += sizeof(*src);
508 }
509 source++;
510 }
511
512 return 0;
513}
514
515static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
516 "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
517
Christian Lamparter7a047f42011-02-12 22:32:49 +0100518static int p54_parse_rssical(struct ieee80211_hw *dev,
519 u8 *data, int len, u16 type)
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500520{
521 struct p54_common *priv = dev->priv;
Christian Lamparter7a047f42011-02-12 22:32:49 +0100522 struct p54_rssi_db_entry *entry;
523 size_t db_len, entries;
524 int offset = 0, i;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500525
Christian Lamparter7a047f42011-02-12 22:32:49 +0100526 if (type != PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
527 entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
528 if (len != sizeof(struct pda_rssi_cal_entry) * entries) {
529 wiphy_err(dev->wiphy, "rssical size mismatch.\n");
530 goto err_data;
531 }
532 } else {
533 /*
534 * Some devices (Dell 1450 USB, Xbow 5GHz card, etc...)
535 * have an empty two byte header.
536 */
537 if (*((__le16 *)&data[offset]) == cpu_to_le16(0))
538 offset += 2;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500539
Christian Lamparter7a047f42011-02-12 22:32:49 +0100540 entries = (len - offset) /
541 sizeof(struct pda_rssi_cal_ext_entry);
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500542
Dan Carpenter6dac3442012-12-02 13:36:09 +0300543 if (len < offset ||
544 (len - offset) % sizeof(struct pda_rssi_cal_ext_entry) ||
545 entries == 0) {
Christian Lamparter7a047f42011-02-12 22:32:49 +0100546 wiphy_err(dev->wiphy, "invalid rssi database.\n");
547 goto err_data;
548 }
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500549 }
550
Christian Lamparter7a047f42011-02-12 22:32:49 +0100551 db_len = sizeof(*entry) * entries;
552 priv->rssi_db = kzalloc(db_len + sizeof(*priv->rssi_db), GFP_KERNEL);
553 if (!priv->rssi_db)
554 return -ENOMEM;
555
556 priv->rssi_db->offset = 0;
557 priv->rssi_db->entries = entries;
558 priv->rssi_db->entry_size = sizeof(*entry);
559 priv->rssi_db->len = db_len;
560
561 entry = (void *)((unsigned long)priv->rssi_db->data + priv->rssi_db->offset);
562 if (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
563 struct pda_rssi_cal_ext_entry *cal = (void *) &data[offset];
564
565 for (i = 0; i < entries; i++) {
566 entry[i].freq = le16_to_cpu(cal[i].freq);
567 entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
568 entry[i].add = (s16) le16_to_cpu(cal[i].add);
569 }
570 } else {
571 struct pda_rssi_cal_entry *cal = (void *) &data[offset];
572
573 for (i = 0; i < entries; i++) {
John W. Linvillece6cac82011-04-29 15:09:39 -0400574 u16 freq = 0;
Christian Lamparter7a047f42011-02-12 22:32:49 +0100575 switch (i) {
576 case IEEE80211_BAND_2GHZ:
577 freq = 2437;
578 break;
579 case IEEE80211_BAND_5GHZ:
580 freq = 5240;
581 break;
582 }
583
584 entry[i].freq = freq;
585 entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
586 entry[i].add = (s16) le16_to_cpu(cal[i].add);
587 }
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500588 }
Christian Lamparter7a047f42011-02-12 22:32:49 +0100589
590 /* sort the list by channel frequency */
591 sort(entry, entries, sizeof(*entry), p54_compare_rssichan, NULL);
592 return 0;
593
594err_data:
595 wiphy_err(dev->wiphy,
596 "rssi calibration data packing type:(%x) len:%d.\n",
597 type, len);
598
599 print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, data, len);
600
601 wiphy_err(dev->wiphy, "please report this issue.\n");
602 return -EINVAL;
603}
604
605struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *priv, const u16 freq)
606{
Felix Fietkaua5a71032011-02-27 22:19:22 +0100607 struct p54_rssi_db_entry *entry;
Christian Lamparter7a047f42011-02-12 22:32:49 +0100608 int i, found = -1;
609
Felix Fietkaua5a71032011-02-27 22:19:22 +0100610 if (!priv->rssi_db)
611 return &p54_rssi_default;
612
613 entry = (void *)(priv->rssi_db->data + priv->rssi_db->offset);
Christian Lamparter7a047f42011-02-12 22:32:49 +0100614 for (i = 0; i < priv->rssi_db->entries; i++) {
615 if (!same_band(freq, entry[i].freq))
616 continue;
617
618 if (found == -1) {
619 found = i;
620 continue;
621 }
622
623 /* nearest match */
624 if (abs(freq - entry[i].freq) <
625 abs(freq - entry[found].freq)) {
626 found = i;
627 continue;
628 } else {
629 break;
630 }
631 }
632
633 return found < 0 ? &p54_rssi_default : &entry[found];
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500634}
635
636static void p54_parse_default_country(struct ieee80211_hw *dev,
637 void *data, int len)
638{
639 struct pda_country *country;
640
641 if (len != sizeof(*country)) {
Joe Perchesc96c31e2010-07-26 14:39:58 -0700642 wiphy_err(dev->wiphy,
643 "found possible invalid default country eeprom entry. (entry size: %d)\n",
644 len);
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500645
646 print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
647 data, len);
648
Joe Perchesc96c31e2010-07-26 14:39:58 -0700649 wiphy_err(dev->wiphy, "please report this issue.\n");
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500650 return;
651 }
652
653 country = (struct pda_country *) data;
654 if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
655 regulatory_hint(dev->wiphy, country->alpha2);
656 else {
657 /* TODO:
658 * write a shared/common function that converts
659 * "Regulatory domain codes" (802.11-2007 14.8.2.2)
660 * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
661 */
662 }
663}
664
665static int p54_convert_output_limits(struct ieee80211_hw *dev,
666 u8 *data, size_t len)
667{
668 struct p54_common *priv = dev->priv;
669
670 if (len < 2)
671 return -EINVAL;
672
673 if (data[0] != 0) {
Joe Perchesc96c31e2010-07-26 14:39:58 -0700674 wiphy_err(dev->wiphy, "unknown output power db revision:%x\n",
675 data[0]);
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500676 return -EINVAL;
677 }
678
679 if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
680 return -EINVAL;
681
682 priv->output_limit = kmalloc(data[1] *
683 sizeof(struct pda_channel_output_limit) +
684 sizeof(*priv->output_limit), GFP_KERNEL);
685
686 if (!priv->output_limit)
687 return -ENOMEM;
688
689 priv->output_limit->offset = 0;
690 priv->output_limit->entries = data[1];
691 priv->output_limit->entry_size =
692 sizeof(struct pda_channel_output_limit);
693 priv->output_limit->len = priv->output_limit->entry_size *
694 priv->output_limit->entries +
695 priv->output_limit->offset;
696
697 memcpy(priv->output_limit->data, &data[2],
698 data[1] * sizeof(struct pda_channel_output_limit));
699
700 return 0;
701}
702
703static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
704 size_t total_len)
705{
706 struct p54_cal_database *dst;
707 size_t payload_len, entries, entry_size, offset;
708
709 payload_len = le16_to_cpu(src->len);
710 entries = le16_to_cpu(src->entries);
711 entry_size = le16_to_cpu(src->entry_size);
712 offset = le16_to_cpu(src->offset);
713 if (((entries * entry_size + offset) != payload_len) ||
714 (payload_len + sizeof(*src) != total_len))
715 return NULL;
716
717 dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
718 if (!dst)
719 return NULL;
720
721 dst->entries = entries;
722 dst->entry_size = entry_size;
723 dst->offset = offset;
724 dst->len = payload_len;
725
726 memcpy(dst->data, src->data, payload_len);
727 return dst;
728}
729
730int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
731{
732 struct p54_common *priv = dev->priv;
Larry Fingere6a3f552009-07-19 21:53:14 -0500733 struct eeprom_pda_wrap *wrap;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500734 struct pda_entry *entry;
735 unsigned int data_len, entry_len;
736 void *tmp;
737 int err;
738 u8 *end = (u8 *)eeprom + len;
739 u16 synth = 0;
Christian Lamparterd7eb50c2010-08-17 01:16:58 +0200740 u16 crc16 = ~0;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500741
742 wrap = (struct eeprom_pda_wrap *) eeprom;
743 entry = (void *)wrap->data + le16_to_cpu(wrap->len);
744
745 /* verify that at least the entry length/code fits */
746 while ((u8 *)entry <= end - sizeof(*entry)) {
747 entry_len = le16_to_cpu(entry->len);
748 data_len = ((entry_len - 1) << 1);
749
750 /* abort if entry exceeds whole structure */
751 if ((u8 *)entry + sizeof(*entry) + data_len > end)
752 break;
753
754 switch (le16_to_cpu(entry->code)) {
755 case PDR_MAC_ADDRESS:
756 if (data_len != ETH_ALEN)
757 break;
758 SET_IEEE80211_PERM_ADDR(dev, entry->data);
759 break;
760 case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
761 if (priv->output_limit)
762 break;
763 err = p54_convert_output_limits(dev, entry->data,
764 data_len);
765 if (err)
766 goto err;
767 break;
768 case PDR_PRISM_PA_CAL_CURVE_DATA: {
769 struct pda_pa_curve_data *curve_data =
770 (struct pda_pa_curve_data *)entry->data;
771 if (data_len < sizeof(*curve_data)) {
772 err = -EINVAL;
773 goto err;
774 }
775
776 switch (curve_data->cal_method_rev) {
777 case 0:
778 err = p54_convert_rev0(dev, curve_data);
779 break;
780 case 1:
781 err = p54_convert_rev1(dev, curve_data);
782 break;
783 default:
Joe Perchesc96c31e2010-07-26 14:39:58 -0700784 wiphy_err(dev->wiphy,
785 "unknown curve data revision %d\n",
786 curve_data->cal_method_rev);
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500787 err = -ENODEV;
788 break;
789 }
790 if (err)
791 goto err;
792 }
793 break;
794 case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
Julia Lawall27b81bb2010-05-15 23:22:55 +0200795 priv->iq_autocal = kmemdup(entry->data, data_len,
796 GFP_KERNEL);
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500797 if (!priv->iq_autocal) {
798 err = -ENOMEM;
799 goto err;
800 }
801
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500802 priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
803 break;
804 case PDR_DEFAULT_COUNTRY:
805 p54_parse_default_country(dev, entry->data, data_len);
806 break;
807 case PDR_INTERFACE_LIST:
808 tmp = entry->data;
809 while ((u8 *)tmp < entry->data + data_len) {
810 struct exp_if *exp_if = tmp;
811 if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
812 synth = le16_to_cpu(exp_if->variant);
813 tmp += sizeof(*exp_if);
814 }
815 break;
816 case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
817 if (data_len < 2)
818 break;
819 priv->version = *(u8 *)(entry->data + 1);
820 break;
821 case PDR_RSSI_LINEAR_APPROXIMATION:
822 case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
823 case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
Christian Lamparter7a047f42011-02-12 22:32:49 +0100824 err = p54_parse_rssical(dev, entry->data, data_len,
825 le16_to_cpu(entry->code));
826 if (err)
827 goto err;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500828 break;
Christian Lamparter7a047f42011-02-12 22:32:49 +0100829 case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2: {
830 struct pda_custom_wrapper *pda = (void *) entry->data;
831 __le16 *src;
832 u16 *dst;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500833 int i;
834
Christian Lamparter7a047f42011-02-12 22:32:49 +0100835 if (priv->rssi_db || data_len < sizeof(*pda))
836 break;
837
838 priv->rssi_db = p54_convert_db(pda, data_len);
839 if (!priv->rssi_db)
840 break;
841
842 src = (void *) priv->rssi_db->data;
843 dst = (void *) priv->rssi_db->data;
844
845 for (i = 0; i < priv->rssi_db->entries; i++)
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500846 *(dst++) = (s16) le16_to_cpu(*(src++));
Christian Lamparter7a047f42011-02-12 22:32:49 +0100847
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500848 }
849 break;
850 case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
851 struct pda_custom_wrapper *pda = (void *) entry->data;
852 if (priv->output_limit || data_len < sizeof(*pda))
853 break;
854 priv->output_limit = p54_convert_db(pda, data_len);
855 }
856 break;
857 case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
858 struct pda_custom_wrapper *pda = (void *) entry->data;
859 if (priv->curve_data || data_len < sizeof(*pda))
860 break;
861 priv->curve_data = p54_convert_db(pda, data_len);
862 }
863 break;
864 case PDR_END:
Christian Lamparterd7eb50c2010-08-17 01:16:58 +0200865 crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry));
866 if (crc16 != le16_to_cpup((__le16 *)entry->data)) {
867 wiphy_err(dev->wiphy, "eeprom failed checksum "
868 "test!\n");
869 err = -ENOMSG;
870 goto err;
871 } else {
872 goto good_eeprom;
873 }
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500874 break;
875 default:
876 break;
877 }
878
Christian Lamparterd7eb50c2010-08-17 01:16:58 +0200879 crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2);
880 entry = (void *)entry + (entry_len + 1) * 2;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500881 }
882
Christian Lamparterd7eb50c2010-08-17 01:16:58 +0200883 wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n");
884 err = -ENODATA;
885 goto err;
886
887good_eeprom:
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500888 if (!synth || !priv->iq_autocal || !priv->output_limit ||
889 !priv->curve_data) {
Joe Perchesc96c31e2010-07-26 14:39:58 -0700890 wiphy_err(dev->wiphy,
891 "not all required entries found in eeprom!\n");
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500892 err = -EINVAL;
893 goto err;
894 }
895
Christian Lamparter9bc63812012-07-28 02:57:51 +0200896 priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
897
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200898 err = p54_generate_channel_lists(dev);
899 if (err)
900 goto err;
901
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500902 if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
903 p54_init_xbow_synth(priv);
904 if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200905 dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
906 priv->band_table[IEEE80211_BAND_2GHZ];
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500907 if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
Christian Lamparter1a9b6672009-07-11 01:22:26 +0200908 dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
909 priv->band_table[IEEE80211_BAND_5GHZ];
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500910 if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
911 priv->rx_diversity_mask = 3;
912 if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
913 priv->tx_diversity_mask = 3;
914
915 if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
916 u8 perm_addr[ETH_ALEN];
917
Joe Perchesc96c31e2010-07-26 14:39:58 -0700918 wiphy_warn(dev->wiphy,
Joe Perches5db55842010-08-11 19:11:19 -0700919 "Invalid hwaddr! Using randomly generated MAC addr\n");
Joe Perchesf4f7f4142012-07-12 19:33:08 +0000920 eth_random_addr(perm_addr);
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500921 SET_IEEE80211_PERM_ADDR(dev, perm_addr);
922 }
923
Christian Lamparter7a047f42011-02-12 22:32:49 +0100924 priv->cur_rssi = &p54_rssi_default;
925
Joe Perches5db55842010-08-11 19:11:19 -0700926 wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n",
Joe Perchesc96c31e2010-07-26 14:39:58 -0700927 dev->wiphy->perm_addr, priv->version,
928 p54_rf_chips[priv->rxhw]);
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500929
930 return 0;
931
932err:
933 kfree(priv->iq_autocal);
934 kfree(priv->output_limit);
935 kfree(priv->curve_data);
Christian Lamparter7a047f42011-02-12 22:32:49 +0100936 kfree(priv->rssi_db);
Christian Lamparter0d781562011-08-20 01:53:59 +0200937 kfree(priv->survey);
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500938 priv->iq_autocal = NULL;
939 priv->output_limit = NULL;
940 priv->curve_data = NULL;
Christian Lamparter7a047f42011-02-12 22:32:49 +0100941 priv->rssi_db = NULL;
Christian Lamparter0d781562011-08-20 01:53:59 +0200942 priv->survey = NULL;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500943
Joe Perchesc96c31e2010-07-26 14:39:58 -0700944 wiphy_err(dev->wiphy, "eeprom parse failed!\n");
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500945 return err;
946}
947EXPORT_SYMBOL_GPL(p54_parse_eeprom);
948
949int p54_read_eeprom(struct ieee80211_hw *dev)
950{
951 struct p54_common *priv = dev->priv;
952 size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
953 int ret = -ENOMEM;
Larry Fingere6a3f552009-07-19 21:53:14 -0500954 void *eeprom;
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500955
956 maxblocksize = EEPROM_READBACK_LEN;
957 if (priv->fw_var >= 0x509)
958 maxblocksize -= 0xc;
959 else
960 maxblocksize -= 0x4;
961
962 eeprom = kzalloc(eeprom_size, GFP_KERNEL);
963 if (unlikely(!eeprom))
964 goto free;
965
966 while (eeprom_size) {
967 blocksize = min(eeprom_size, maxblocksize);
Joe Perches2c208892012-06-04 12:44:17 +0000968 ret = p54_download_eeprom(priv, eeprom + offset,
Christian Lamparter4c8a32f2009-06-23 10:36:26 -0500969 offset, blocksize);
970 if (unlikely(ret))
971 goto free;
972
973 offset += blocksize;
974 eeprom_size -= blocksize;
975 }
976
977 ret = p54_parse_eeprom(dev, eeprom, offset);
978free:
979 kfree(eeprom);
980 return ret;
981}
982EXPORT_SYMBOL_GPL(p54_read_eeprom);