aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/p54/eeprom.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/p54/eeprom.c')
-rw-r--r--drivers/net/wireless/p54/eeprom.c236
1 files changed, 190 insertions, 46 deletions
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 78347041ec40..54cc0bba66b9 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -23,6 +23,7 @@
23#include <linux/slab.h> 23#include <linux/slab.h>
24 24
25#include <net/mac80211.h> 25#include <net/mac80211.h>
26#include <linux/crc-ccitt.h>
26 27
27#include "p54.h" 28#include "p54.h"
28#include "eeprom.h" 29#include "eeprom.h"
@@ -54,6 +55,17 @@ static struct ieee80211_rate p54_arates[] = {
54 { .bitrate = 540, .hw_value = 11, }, 55 { .bitrate = 540, .hw_value = 11, },
55}; 56};
56 57
58static 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
57#define CHAN_HAS_CAL BIT(0) 69#define CHAN_HAS_CAL BIT(0)
58#define CHAN_HAS_LIMIT BIT(1) 70#define CHAN_HAS_LIMIT BIT(1)
59#define CHAN_HAS_CURVE BIT(2) 71#define CHAN_HAS_CURVE BIT(2)
@@ -86,13 +98,27 @@ static int p54_get_band_from_freq(u16 freq)
86 return -1; 98 return -1;
87} 99}
88 100
101static int same_band(u16 freq, u16 freq2)
102{
103 return p54_get_band_from_freq(freq) == p54_get_band_from_freq(freq2);
104}
105
89static int p54_compare_channels(const void *_a, 106static int p54_compare_channels(const void *_a,
90 const void *_b) 107 const void *_b)
91{ 108{
92 const struct p54_channel_entry *a = _a; 109 const struct p54_channel_entry *a = _a;
93 const struct p54_channel_entry *b = _b; 110 const struct p54_channel_entry *b = _b;
94 111
95 return a->index - b->index; 112 return a->freq - b->freq;
113}
114
115static int p54_compare_rssichan(const void *_a,
116 const void *_b)
117{
118 const struct p54_rssi_db_entry *a = _a;
119 const struct p54_rssi_db_entry *b = _b;
120
121 return a->freq - b->freq;
96} 122}
97 123
98static int p54_fill_band_bitrates(struct ieee80211_hw *dev, 124static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
@@ -144,25 +170,26 @@ static int p54_generate_band(struct ieee80211_hw *dev,
144 170
145 for (i = 0, j = 0; (j < list->band_channel_num[band]) && 171 for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
146 (i < list->entries); i++) { 172 (i < list->entries); i++) {
173 struct p54_channel_entry *chan = &list->channels[i];
147 174
148 if (list->channels[i].band != band) 175 if (chan->band != band)
149 continue; 176 continue;
150 177
151 if (list->channels[i].data != CHAN_HAS_ALL) { 178 if (chan->data != CHAN_HAS_ALL) {
152 wiphy_err(dev->wiphy, 179 wiphy_err(dev->wiphy, "%s%s%s is/are missing for "
153 "%s%s%s is/are missing for channel:%d [%d MHz].\n", 180 "channel:%d [%d MHz].\n",
154 (list->channels[i].data & CHAN_HAS_CAL ? "" : 181 (chan->data & CHAN_HAS_CAL ? "" :
155 " [iqauto calibration data]"), 182 " [iqauto calibration data]"),
156 (list->channels[i].data & CHAN_HAS_LIMIT ? "" : 183 (chan->data & CHAN_HAS_LIMIT ? "" :
157 " [output power limits]"), 184 " [output power limits]"),
158 (list->channels[i].data & CHAN_HAS_CURVE ? "" : 185 (chan->data & CHAN_HAS_CURVE ? "" :
159 " [curve data]"), 186 " [curve data]"),
160 list->channels[i].index, list->channels[i].freq); 187 chan->index, chan->freq);
161 continue; 188 continue;
162 } 189 }
163 190
164 tmp->channels[j].band = list->channels[i].band; 191 tmp->channels[j].band = chan->band;
165 tmp->channels[j].center_freq = list->channels[i].freq; 192 tmp->channels[j].center_freq = chan->freq;
166 j++; 193 j++;
167 } 194 }
168 195
@@ -260,8 +287,10 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
260 list->max_entries = max_channel_num; 287 list->max_entries = max_channel_num;
261 list->channels = kzalloc(sizeof(struct p54_channel_entry) * 288 list->channels = kzalloc(sizeof(struct p54_channel_entry) *
262 max_channel_num, GFP_KERNEL); 289 max_channel_num, GFP_KERNEL);
263 if (!list->channels) 290 if (!list->channels) {
291 ret = -ENOMEM;
264 goto free; 292 goto free;
293 }
265 294
266 for (i = 0; i < max_channel_num; i++) { 295 for (i = 0; i < max_channel_num; i++) {
267 if (i < priv->iq_autocal_len) { 296 if (i < priv->iq_autocal_len) {
@@ -288,7 +317,7 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
288 } 317 }
289 } 318 }
290 319
291 /* sort the list by the channel index */ 320 /* sort the channel list by frequency */
292 sort(list->channels, list->entries, sizeof(struct p54_channel_entry), 321 sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
293 p54_compare_channels, NULL); 322 p54_compare_channels, NULL);
294 323
@@ -407,33 +436,121 @@ static int p54_convert_rev1(struct ieee80211_hw *dev,
407static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2", 436static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
408 "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" }; 437 "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
409 438
410static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, 439static int p54_parse_rssical(struct ieee80211_hw *dev,
411 u16 type) 440 u8 *data, int len, u16 type)
412{ 441{
413 struct p54_common *priv = dev->priv; 442 struct p54_common *priv = dev->priv;
414 int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; 443 struct p54_rssi_db_entry *entry;
415 int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; 444 size_t db_len, entries;
416 int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; 445 int offset = 0, i;
417 int i; 446
447 if (type != PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
448 entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
449 if (len != sizeof(struct pda_rssi_cal_entry) * entries) {
450 wiphy_err(dev->wiphy, "rssical size mismatch.\n");
451 goto err_data;
452 }
453 } else {
454 /*
455 * Some devices (Dell 1450 USB, Xbow 5GHz card, etc...)
456 * have an empty two byte header.
457 */
458 if (*((__le16 *)&data[offset]) == cpu_to_le16(0))
459 offset += 2;
418 460
419 if (len != (entry_size * num_entries)) { 461 entries = (len - offset) /
420 wiphy_err(dev->wiphy, 462 sizeof(struct pda_rssi_cal_ext_entry);
421 "unknown rssi calibration data packing type:(%x) len:%d.\n",
422 type, len);
423 463
424 print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, 464 if ((len - offset) % sizeof(struct pda_rssi_cal_ext_entry) ||
425 data, len); 465 entries <= 0) {
466 wiphy_err(dev->wiphy, "invalid rssi database.\n");
467 goto err_data;
468 }
469 }
426 470
427 wiphy_err(dev->wiphy, "please report this issue.\n"); 471 db_len = sizeof(*entry) * entries;
428 return; 472 priv->rssi_db = kzalloc(db_len + sizeof(*priv->rssi_db), GFP_KERNEL);
473 if (!priv->rssi_db)
474 return -ENOMEM;
475
476 priv->rssi_db->offset = 0;
477 priv->rssi_db->entries = entries;
478 priv->rssi_db->entry_size = sizeof(*entry);
479 priv->rssi_db->len = db_len;
480
481 entry = (void *)((unsigned long)priv->rssi_db->data + priv->rssi_db->offset);
482 if (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
483 struct pda_rssi_cal_ext_entry *cal = (void *) &data[offset];
484
485 for (i = 0; i < entries; i++) {
486 entry[i].freq = le16_to_cpu(cal[i].freq);
487 entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
488 entry[i].add = (s16) le16_to_cpu(cal[i].add);
489 }
490 } else {
491 struct pda_rssi_cal_entry *cal = (void *) &data[offset];
492
493 for (i = 0; i < entries; i++) {
494 u16 freq = 0;
495 switch (i) {
496 case IEEE80211_BAND_2GHZ:
497 freq = 2437;
498 break;
499 case IEEE80211_BAND_5GHZ:
500 freq = 5240;
501 break;
502 }
503
504 entry[i].freq = freq;
505 entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
506 entry[i].add = (s16) le16_to_cpu(cal[i].add);
507 }
429 } 508 }
430 509
431 for (i = 0; i < num_entries; i++) { 510 /* sort the list by channel frequency */
432 struct pda_rssi_cal_entry *cal = data + 511 sort(entry, entries, sizeof(*entry), p54_compare_rssichan, NULL);
433 (offset + i * entry_size); 512 return 0;
434 priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); 513
435 priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add); 514err_data:
515 wiphy_err(dev->wiphy,
516 "rssi calibration data packing type:(%x) len:%d.\n",
517 type, len);
518
519 print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, data, len);
520
521 wiphy_err(dev->wiphy, "please report this issue.\n");
522 return -EINVAL;
523}
524
525struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *priv, const u16 freq)
526{
527 struct p54_rssi_db_entry *entry;
528 int i, found = -1;
529
530 if (!priv->rssi_db)
531 return &p54_rssi_default;
532
533 entry = (void *)(priv->rssi_db->data + priv->rssi_db->offset);
534 for (i = 0; i < priv->rssi_db->entries; i++) {
535 if (!same_band(freq, entry[i].freq))
536 continue;
537
538 if (found == -1) {
539 found = i;
540 continue;
541 }
542
543 /* nearest match */
544 if (abs(freq - entry[i].freq) <
545 abs(freq - entry[found].freq)) {
546 found = i;
547 continue;
548 } else {
549 break;
550 }
436 } 551 }
552
553 return found < 0 ? &p54_rssi_default : &entry[found];
437} 554}
438 555
439static void p54_parse_default_country(struct ieee80211_hw *dev, 556static void p54_parse_default_country(struct ieee80211_hw *dev,
@@ -540,6 +657,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
540 int err; 657 int err;
541 u8 *end = (u8 *)eeprom + len; 658 u8 *end = (u8 *)eeprom + len;
542 u16 synth = 0; 659 u16 synth = 0;
660 u16 crc16 = ~0;
543 661
544 wrap = (struct eeprom_pda_wrap *) eeprom; 662 wrap = (struct eeprom_pda_wrap *) eeprom;
545 entry = (void *)wrap->data + le16_to_cpu(wrap->len); 663 entry = (void *)wrap->data + le16_to_cpu(wrap->len);
@@ -623,21 +741,30 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
623 case PDR_RSSI_LINEAR_APPROXIMATION: 741 case PDR_RSSI_LINEAR_APPROXIMATION:
624 case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: 742 case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
625 case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: 743 case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
626 p54_parse_rssical(dev, entry->data, data_len, 744 err = p54_parse_rssical(dev, entry->data, data_len,
627 le16_to_cpu(entry->code)); 745 le16_to_cpu(entry->code));
746 if (err)
747 goto err;
628 break; 748 break;
629 case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: { 749 case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2: {
630 __le16 *src = (void *) entry->data; 750 struct pda_custom_wrapper *pda = (void *) entry->data;
631 s16 *dst = (void *) &priv->rssical_db; 751 __le16 *src;
752 u16 *dst;
632 int i; 753 int i;
633 754
634 if (data_len != sizeof(priv->rssical_db)) { 755 if (priv->rssi_db || data_len < sizeof(*pda))
635 err = -EINVAL; 756 break;
636 goto err; 757
637 } 758 priv->rssi_db = p54_convert_db(pda, data_len);
638 for (i = 0; i < sizeof(priv->rssical_db) / 759 if (!priv->rssi_db)
639 sizeof(*src); i++) 760 break;
761
762 src = (void *) priv->rssi_db->data;
763 dst = (void *) priv->rssi_db->data;
764
765 for (i = 0; i < priv->rssi_db->entries; i++)
640 *(dst++) = (s16) le16_to_cpu(*(src++)); 766 *(dst++) = (s16) le16_to_cpu(*(src++));
767
641 } 768 }
642 break; 769 break;
643 case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: { 770 case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
@@ -655,16 +782,29 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
655 } 782 }
656 break; 783 break;
657 case PDR_END: 784 case PDR_END:
658 /* make it overrun */ 785 crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry));
659 entry_len = len; 786 if (crc16 != le16_to_cpup((__le16 *)entry->data)) {
787 wiphy_err(dev->wiphy, "eeprom failed checksum "
788 "test!\n");
789 err = -ENOMSG;
790 goto err;
791 } else {
792 goto good_eeprom;
793 }
660 break; 794 break;
661 default: 795 default:
662 break; 796 break;
663 } 797 }
664 798
665 entry = (void *)entry + (entry_len + 1)*2; 799 crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2);
800 entry = (void *)entry + (entry_len + 1) * 2;
666 } 801 }
667 802
803 wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n");
804 err = -ENODATA;
805 goto err;
806
807good_eeprom:
668 if (!synth || !priv->iq_autocal || !priv->output_limit || 808 if (!synth || !priv->iq_autocal || !priv->output_limit ||
669 !priv->curve_data) { 809 !priv->curve_data) {
670 wiphy_err(dev->wiphy, 810 wiphy_err(dev->wiphy,
@@ -700,6 +840,8 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
700 SET_IEEE80211_PERM_ADDR(dev, perm_addr); 840 SET_IEEE80211_PERM_ADDR(dev, perm_addr);
701 } 841 }
702 842
843 priv->cur_rssi = &p54_rssi_default;
844
703 wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n", 845 wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n",
704 dev->wiphy->perm_addr, priv->version, 846 dev->wiphy->perm_addr, priv->version,
705 p54_rf_chips[priv->rxhw]); 847 p54_rf_chips[priv->rxhw]);
@@ -710,9 +852,11 @@ err:
710 kfree(priv->iq_autocal); 852 kfree(priv->iq_autocal);
711 kfree(priv->output_limit); 853 kfree(priv->output_limit);
712 kfree(priv->curve_data); 854 kfree(priv->curve_data);
855 kfree(priv->rssi_db);
713 priv->iq_autocal = NULL; 856 priv->iq_autocal = NULL;
714 priv->output_limit = NULL; 857 priv->output_limit = NULL;
715 priv->curve_data = NULL; 858 priv->curve_data = NULL;
859 priv->rssi_db = NULL;
716 860
717 wiphy_err(dev->wiphy, "eeprom parse failed!\n"); 861 wiphy_err(dev->wiphy, "eeprom parse failed!\n");
718 return err; 862 return err;