aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/p54/p54common.c
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@web.de>2009-01-10 19:10:33 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-01-29 16:00:22 -0500
commit83cf1b6edba6bde87c8cf852b182d44b12ae7f88 (patch)
treef90010ab7a686fe59f04e4b5f268253cb6f7ed52 /drivers/net/wireless/p54/p54common.c
parentb6ea03562f04382776ad825624daefe27f5d3f9c (diff)
p54: prepare the eeprom parser routines for longbow
This patch adds support to upload pre-calculated calibration data to the firmware. Signed-off-by: Christian Lamparter <chunkeey@web.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54/p54common.c')
-rw-r--r--drivers/net/wireless/p54/p54common.c188
1 files changed, 143 insertions, 45 deletions
diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c
index 85aff1685a10..ec0d109c0095 100644
--- a/drivers/net/wireless/p54/p54common.c
+++ b/drivers/net/wireless/p54/p54common.c
@@ -272,13 +272,19 @@ static int p54_convert_rev0(struct ieee80211_hw *dev,
272 unsigned int i, j; 272 unsigned int i, j;
273 void *source, *target; 273 void *source, *target;
274 274
275 priv->curve_data = kmalloc(cd_len, GFP_KERNEL); 275 priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
276 GFP_KERNEL);
276 if (!priv->curve_data) 277 if (!priv->curve_data)
277 return -ENOMEM; 278 return -ENOMEM;
278 279
279 memcpy(priv->curve_data, curve_data, sizeof(*curve_data)); 280 priv->curve_data->entries = curve_data->channels;
281 priv->curve_data->entry_size = sizeof(__le16) +
282 sizeof(*dst) * curve_data->points_per_channel;
283 priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
284 priv->curve_data->len = cd_len;
285 memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
280 source = curve_data->data; 286 source = curve_data->data;
281 target = priv->curve_data->data; 287 target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
282 for (i = 0; i < curve_data->channels; i++) { 288 for (i = 0; i < curve_data->channels; i++) {
283 __le16 *freq = source; 289 __le16 *freq = source;
284 source += sizeof(__le16); 290 source += sizeof(__le16);
@@ -318,13 +324,19 @@ static int p54_convert_rev1(struct ieee80211_hw *dev,
318 unsigned int i, j; 324 unsigned int i, j;
319 void *source, *target; 325 void *source, *target;
320 326
321 priv->curve_data = kmalloc(cd_len, GFP_KERNEL); 327 priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
328 GFP_KERNEL);
322 if (!priv->curve_data) 329 if (!priv->curve_data)
323 return -ENOMEM; 330 return -ENOMEM;
324 331
325 memcpy(priv->curve_data, curve_data, sizeof(*curve_data)); 332 priv->curve_data->entries = curve_data->channels;
333 priv->curve_data->entry_size = sizeof(__le16) +
334 sizeof(*dst) * curve_data->points_per_channel;
335 priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
336 priv->curve_data->len = cd_len;
337 memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
326 source = curve_data->data; 338 source = curve_data->data;
327 target = priv->curve_data->data; 339 target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
328 for (i = 0; i < curve_data->channels; i++) { 340 for (i = 0; i < curve_data->channels; i++) {
329 __le16 *freq = source; 341 __le16 *freq = source;
330 source += sizeof(__le16); 342 source += sizeof(__le16);
@@ -406,6 +418,71 @@ static void p54_parse_default_country(struct ieee80211_hw *dev,
406 } 418 }
407} 419}
408 420
421static int p54_convert_output_limits(struct ieee80211_hw *dev,
422 u8 *data, size_t len)
423{
424 struct p54_common *priv = dev->priv;
425
426 if (len < 2)
427 return -EINVAL;
428
429 if (data[0] != 0) {
430 printk(KERN_ERR "%s: unknown output power db revision:%x\n",
431 wiphy_name(dev->wiphy), data[0]);
432 return -EINVAL;
433 }
434
435 if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
436 return -EINVAL;
437
438 priv->output_limit = kmalloc(data[1] *
439 sizeof(struct pda_channel_output_limit) +
440 sizeof(*priv->output_limit), GFP_KERNEL);
441
442 if (!priv->output_limit)
443 return -ENOMEM;
444
445 priv->output_limit->offset = 0;
446 priv->output_limit->entries = data[1];
447 priv->output_limit->entry_size =
448 sizeof(struct pda_channel_output_limit);
449 priv->output_limit->len = priv->output_limit->entry_size *
450 priv->output_limit->entries +
451 priv->output_limit->offset;
452
453 memcpy(priv->output_limit->data, &data[2],
454 data[1] * sizeof(struct pda_channel_output_limit));
455
456 return 0;
457}
458
459static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
460 size_t total_len)
461{
462 struct p54_cal_database *dst;
463 size_t payload_len, entries, entry_size, offset;
464
465 payload_len = le16_to_cpu(src->len);
466 entries = le16_to_cpu(src->entries);
467 entry_size = le16_to_cpu(src->entry_size);
468 offset = le16_to_cpu(src->offset);
469 if (((entries * entry_size + offset) != payload_len) ||
470 (payload_len + sizeof(*src) != total_len))
471 return NULL;
472
473 dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
474 if (!dst)
475 return NULL;
476
477 dst->entries = entries;
478 dst->entry_size = entry_size;
479 dst->offset = offset;
480 dst->len = payload_len;
481
482 memcpy(dst->data, src->data, payload_len);
483 return dst;
484}
485
409static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) 486static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
410{ 487{
411 struct p54_common *priv = dev->priv; 488 struct p54_common *priv = dev->priv;
@@ -431,30 +508,17 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
431 508
432 switch (le16_to_cpu(entry->code)) { 509 switch (le16_to_cpu(entry->code)) {
433 case PDR_MAC_ADDRESS: 510 case PDR_MAC_ADDRESS:
511 if (data_len != ETH_ALEN)
512 break;
434 SET_IEEE80211_PERM_ADDR(dev, entry->data); 513 SET_IEEE80211_PERM_ADDR(dev, entry->data);
435 break; 514 break;
436 case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS: 515 case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
437 if (data_len < 2) { 516 if (priv->output_limit)
438 err = -EINVAL; 517 break;
439 goto err; 518 err = p54_convert_output_limits(dev, entry->data,
440 } 519 data_len);
441 520 if (err)
442 if (2 + entry->data[1]*sizeof(*priv->output_limit) > data_len) {
443 err = -EINVAL;
444 goto err;
445 }
446
447 priv->output_limit = kmalloc(entry->data[1] *
448 sizeof(*priv->output_limit), GFP_KERNEL);
449
450 if (!priv->output_limit) {
451 err = -ENOMEM;
452 goto err; 521 goto err;
453 }
454
455 memcpy(priv->output_limit, &entry->data[2],
456 entry->data[1]*sizeof(*priv->output_limit));
457 priv->output_limit_len = entry->data[1];
458 break; 522 break;
459 case PDR_PRISM_PA_CAL_CURVE_DATA: { 523 case PDR_PRISM_PA_CAL_CURVE_DATA: {
460 struct pda_pa_curve_data *curve_data = 524 struct pda_pa_curve_data *curve_data =
@@ -506,6 +570,8 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
506 } 570 }
507 break; 571 break;
508 case PDR_HARDWARE_PLATFORM_COMPONENT_ID: 572 case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
573 if (data_len < 2)
574 break;
509 priv->version = *(u8 *)(entry->data + 1); 575 priv->version = *(u8 *)(entry->data + 1);
510 break; 576 break;
511 case PDR_RSSI_LINEAR_APPROXIMATION: 577 case PDR_RSSI_LINEAR_APPROXIMATION:
@@ -514,6 +580,34 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
514 p54_parse_rssical(dev, entry->data, data_len, 580 p54_parse_rssical(dev, entry->data, data_len,
515 le16_to_cpu(entry->code)); 581 le16_to_cpu(entry->code));
516 break; 582 break;
583 case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
584 __le16 *src = (void *) entry->data;
585 s16 *dst = (void *) &priv->rssical_db;
586 int i;
587
588 if (data_len != sizeof(priv->rssical_db)) {
589 err = -EINVAL;
590 goto err;
591 }
592 for (i = 0; i < sizeof(priv->rssical_db) /
593 sizeof(*src); i++)
594 *(dst++) = (s16) le16_to_cpu(*(src++));
595 }
596 break;
597 case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
598 struct pda_custom_wrapper *pda = (void *) entry->data;
599 if (priv->output_limit || data_len < sizeof(*pda))
600 break;
601 priv->output_limit = p54_convert_db(pda, data_len);
602 }
603 break;
604 case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
605 struct pda_custom_wrapper *pda = (void *) entry->data;
606 if (priv->curve_data || data_len < sizeof(*pda))
607 break;
608 priv->curve_data = p54_convert_db(pda, data_len);
609 }
610 break;
517 case PDR_END: 611 case PDR_END:
518 /* make it overrun */ 612 /* make it overrun */
519 entry_len = len; 613 entry_len = len;
@@ -1624,8 +1718,8 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
1624 struct p54_scan *chan; 1718 struct p54_scan *chan;
1625 unsigned int i; 1719 unsigned int i;
1626 void *entry; 1720 void *entry;
1627 __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
1628 int band = dev->conf.channel->band; 1721 int band = dev->conf.channel->band;
1722 __le16 freq = cpu_to_le16(dev->conf.channel->center_freq);
1629 1723
1630 skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan), 1724 skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan),
1631 P54_CONTROL_TYPE_SCAN, GFP_ATOMIC); 1725 P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
@@ -1633,7 +1727,7 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
1633 return -ENOMEM; 1727 return -ENOMEM;
1634 1728
1635 chan = (struct p54_scan *) skb_put(skb, sizeof(*chan)); 1729 chan = (struct p54_scan *) skb_put(skb, sizeof(*chan));
1636 memset(chan->padding1, 0, sizeof(chan->padding1)); 1730 memset(chan->scan_params, 0, sizeof(chan->scan_params));
1637 chan->mode = cpu_to_le16(mode); 1731 chan->mode = cpu_to_le16(mode);
1638 chan->dwell = cpu_to_le16(dwell); 1732 chan->dwell = cpu_to_le16(dwell);
1639 1733
@@ -1648,41 +1742,45 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
1648 if (i == priv->iq_autocal_len) 1742 if (i == priv->iq_autocal_len)
1649 goto err; 1743 goto err;
1650 1744
1651 for (i = 0; i < priv->output_limit_len; i++) { 1745 for (i = 0; i < priv->output_limit->entries; i++) {
1652 if (priv->output_limit[i].freq != freq) 1746 struct pda_channel_output_limit *limits;
1747 __le16 *entry_freq = (void *) (priv->output_limit->data +
1748 priv->output_limit->entry_size * i);
1749
1750 if (*entry_freq != freq)
1653 continue; 1751 continue;
1654 1752
1753 limits = (void *) entry_freq;
1655 chan->val_barker = 0x38; 1754 chan->val_barker = 0x38;
1656 chan->val_bpsk = chan->dup_bpsk = 1755 chan->val_bpsk = chan->dup_bpsk = limits->val_bpsk;
1657 priv->output_limit[i].val_bpsk; 1756 chan->val_qpsk = chan->dup_qpsk = limits->val_qpsk;
1658 chan->val_qpsk = chan->dup_qpsk = 1757 chan->val_16qam = chan->dup_16qam = limits->val_16qam;
1659 priv->output_limit[i].val_qpsk; 1758 chan->val_64qam = chan->dup_64qam = limits->val_64qam;
1660 chan->val_16qam = chan->dup_16qam =
1661 priv->output_limit[i].val_16qam;
1662 chan->val_64qam = chan->dup_64qam =
1663 priv->output_limit[i].val_64qam;
1664 break; 1759 break;
1665 } 1760 }
1666 if (i == priv->output_limit_len) 1761 if (i == priv->output_limit->entries)
1667 goto err; 1762 goto err;
1668 1763
1669 entry = priv->curve_data->data; 1764 entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
1670 for (i = 0; i < priv->curve_data->channels; i++) { 1765 for (i = 0; i < priv->curve_data->entries; i++) {
1766 struct pda_pa_curve_data *curve_data;
1671 if (*((__le16 *)entry) != freq) { 1767 if (*((__le16 *)entry) != freq) {
1672 entry += sizeof(__le16); 1768 entry += priv->curve_data->entry_size;
1673 entry += sizeof(struct p54_pa_curve_data_sample) *
1674 priv->curve_data->points_per_channel;
1675 continue; 1769 continue;
1676 } 1770 }
1677 1771
1678 entry += sizeof(__le16); 1772 entry += sizeof(__le16);
1679 chan->pa_points_per_curve = 8; 1773 chan->pa_points_per_curve = 8;
1680 memset(chan->curve_data, 0, sizeof(*chan->curve_data)); 1774 memset(chan->curve_data, 0, sizeof(*chan->curve_data));
1775 curve_data = (void *) priv->curve_data->data;
1776
1681 memcpy(chan->curve_data, entry, 1777 memcpy(chan->curve_data, entry,
1682 sizeof(struct p54_pa_curve_data_sample) * 1778 sizeof(struct p54_pa_curve_data_sample) *
1683 min((u8)8, priv->curve_data->points_per_channel)); 1779 min_t(u8, 8, curve_data->points_per_channel));
1684 break; 1780 break;
1685 } 1781 }
1782 if (i == priv->curve_data->entries)
1783 goto err;
1686 1784
1687 if (priv->fw_var < 0x500) { 1785 if (priv->fw_var < 0x500) {
1688 chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul); 1786 chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul);