aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/p54/eeprom.c
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@googlemail.com>2011-02-12 16:32:49 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-02-14 15:52:10 -0500
commit7a047f4f2f3a812f09f42aa784499a54dc4afcf2 (patch)
tree4396f0fbc6d4cf296994fef8b9a5a92a86a0b576 /drivers/net/wireless/p54/eeprom.c
parenta3162eed04ae76be710d895978478aa6d849de41 (diff)
p54: enhance rssi->dBm database import
This patch fixes several shortcomings of the previous implementation. Features of the rewrite include: * handles undocumented "0x0000" word at the start of the frequency table. (Affected some early? DELL 1450 USB devices and my Symbol 5GHz miniPCI card.) * supports more than just one reference point per band. (Also needed for the Symbol card.) * ships with default values in case the eeprom data is damaged, absent or unsupported. Signed-off-by: Christian Lamparter <chunkeey@googlemail.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54/eeprom.c')
-rw-r--r--drivers/net/wireless/p54/eeprom.c183
1 files changed, 153 insertions, 30 deletions
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 360bc7810f93..f54e15fcd623 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -55,6 +55,17 @@ static struct ieee80211_rate p54_arates[] = {
55 { .bitrate = 540, .hw_value = 11, }, 55 { .bitrate = 540, .hw_value = 11, },
56}; 56};
57 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
58#define CHAN_HAS_CAL BIT(0) 69#define CHAN_HAS_CAL BIT(0)
59#define CHAN_HAS_LIMIT BIT(1) 70#define CHAN_HAS_LIMIT BIT(1)
60#define CHAN_HAS_CURVE BIT(2) 71#define CHAN_HAS_CURVE BIT(2)
@@ -87,6 +98,11 @@ static int p54_get_band_from_freq(u16 freq)
87 return -1; 98 return -1;
88} 99}
89 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
90static int p54_compare_channels(const void *_a, 106static int p54_compare_channels(const void *_a,
91 const void *_b) 107 const void *_b)
92{ 108{
@@ -96,6 +112,15 @@ static int p54_compare_channels(const void *_a,
96 return a->freq - b->freq; 112 return a->freq - b->freq;
97} 113}
98 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;
122}
123
99static int p54_fill_band_bitrates(struct ieee80211_hw *dev, 124static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
100 struct ieee80211_supported_band *band_entry, 125 struct ieee80211_supported_band *band_entry,
101 enum ieee80211_band band) 126 enum ieee80211_band band)
@@ -411,33 +436,118 @@ static int p54_convert_rev1(struct ieee80211_hw *dev,
411static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2", 436static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
412 "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" }; 437 "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
413 438
414static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, 439static int p54_parse_rssical(struct ieee80211_hw *dev,
415 u16 type) 440 u8 *data, int len, u16 type)
416{ 441{
417 struct p54_common *priv = dev->priv; 442 struct p54_common *priv = dev->priv;
418 int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; 443 struct p54_rssi_db_entry *entry;
419 int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; 444 size_t db_len, entries;
420 int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; 445 int offset = 0, i;
421 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;
422 460
423 if (len != (entry_size * num_entries)) { 461 entries = (len - offset) /
424 wiphy_err(dev->wiphy, 462 sizeof(struct pda_rssi_cal_ext_entry);
425 "unknown rssi calibration data packing type:(%x) len:%d.\n",
426 type, len);
427 463
428 print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, 464 if ((len - offset) % sizeof(struct pda_rssi_cal_ext_entry) ||
429 data, len); 465 entries <= 0) {
466 wiphy_err(dev->wiphy, "invalid rssi database.\n");
467 goto err_data;
468 }
469 }
430 470
431 wiphy_err(dev->wiphy, "please report this issue.\n"); 471 db_len = sizeof(*entry) * entries;
432 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;
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 }
433 } 508 }
434 509
435 for (i = 0; i < num_entries; i++) { 510 /* sort the list by channel frequency */
436 struct pda_rssi_cal_entry *cal = data + 511 sort(entry, entries, sizeof(*entry), p54_compare_rssichan, NULL);
437 (offset + i * entry_size); 512 return 0;
438 priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); 513
439 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 = (void *)(priv->rssi_db->data +
528 priv->rssi_db->offset);
529 int i, found = -1;
530
531 for (i = 0; i < priv->rssi_db->entries; i++) {
532 if (!same_band(freq, entry[i].freq))
533 continue;
534
535 if (found == -1) {
536 found = i;
537 continue;
538 }
539
540 /* nearest match */
541 if (abs(freq - entry[i].freq) <
542 abs(freq - entry[found].freq)) {
543 found = i;
544 continue;
545 } else {
546 break;
547 }
440 } 548 }
549
550 return found < 0 ? &p54_rssi_default : &entry[found];
441} 551}
442 552
443static void p54_parse_default_country(struct ieee80211_hw *dev, 553static void p54_parse_default_country(struct ieee80211_hw *dev,
@@ -628,21 +738,30 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
628 case PDR_RSSI_LINEAR_APPROXIMATION: 738 case PDR_RSSI_LINEAR_APPROXIMATION:
629 case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: 739 case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
630 case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: 740 case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
631 p54_parse_rssical(dev, entry->data, data_len, 741 err = p54_parse_rssical(dev, entry->data, data_len,
632 le16_to_cpu(entry->code)); 742 le16_to_cpu(entry->code));
743 if (err)
744 goto err;
633 break; 745 break;
634 case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: { 746 case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2: {
635 __le16 *src = (void *) entry->data; 747 struct pda_custom_wrapper *pda = (void *) entry->data;
636 s16 *dst = (void *) &priv->rssical_db; 748 __le16 *src;
749 u16 *dst;
637 int i; 750 int i;
638 751
639 if (data_len != sizeof(priv->rssical_db)) { 752 if (priv->rssi_db || data_len < sizeof(*pda))
640 err = -EINVAL; 753 break;
641 goto err; 754
642 } 755 priv->rssi_db = p54_convert_db(pda, data_len);
643 for (i = 0; i < sizeof(priv->rssical_db) / 756 if (!priv->rssi_db)
644 sizeof(*src); i++) 757 break;
758
759 src = (void *) priv->rssi_db->data;
760 dst = (void *) priv->rssi_db->data;
761
762 for (i = 0; i < priv->rssi_db->entries; i++)
645 *(dst++) = (s16) le16_to_cpu(*(src++)); 763 *(dst++) = (s16) le16_to_cpu(*(src++));
764
646 } 765 }
647 break; 766 break;
648 case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: { 767 case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
@@ -718,6 +837,8 @@ good_eeprom:
718 SET_IEEE80211_PERM_ADDR(dev, perm_addr); 837 SET_IEEE80211_PERM_ADDR(dev, perm_addr);
719 } 838 }
720 839
840 priv->cur_rssi = &p54_rssi_default;
841
721 wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n", 842 wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n",
722 dev->wiphy->perm_addr, priv->version, 843 dev->wiphy->perm_addr, priv->version,
723 p54_rf_chips[priv->rxhw]); 844 p54_rf_chips[priv->rxhw]);
@@ -728,9 +849,11 @@ err:
728 kfree(priv->iq_autocal); 849 kfree(priv->iq_autocal);
729 kfree(priv->output_limit); 850 kfree(priv->output_limit);
730 kfree(priv->curve_data); 851 kfree(priv->curve_data);
852 kfree(priv->rssi_db);
731 priv->iq_autocal = NULL; 853 priv->iq_autocal = NULL;
732 priv->output_limit = NULL; 854 priv->output_limit = NULL;
733 priv->curve_data = NULL; 855 priv->curve_data = NULL;
856 priv->rssi_db = NULL;
734 857
735 wiphy_err(dev->wiphy, "eeprom parse failed!\n"); 858 wiphy_err(dev->wiphy, "eeprom parse failed!\n");
736 return err; 859 return err;