diff options
author | Christian Lamparter <chunkeey@web.de> | 2009-01-10 19:10:33 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:00:22 -0500 |
commit | 83cf1b6edba6bde87c8cf852b182d44b12ae7f88 (patch) | |
tree | f90010ab7a686fe59f04e4b5f268253cb6f7ed52 /drivers/net/wireless/p54/p54common.c | |
parent | b6ea03562f04382776ad825624daefe27f5d3f9c (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.c | 188 |
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 | ||
421 | static 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 | |||
459 | static 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 | |||
409 | static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) | 486 | static 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); |