linux/drivers/net/wireless/p54/eeprom.c
<<
>>
Prefs
   1/*
   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
  19#include <linux/init.h>
  20#include <linux/firmware.h>
  21#include <linux/etherdevice.h>
  22#include <linux/sort.h>
  23
  24#include <net/mac80211.h>
  25
  26#include "p54.h"
  27#include "eeprom.h"
  28#include "lmac.h"
  29
  30static struct ieee80211_rate p54_bgrates[] = {
  31        { .bitrate = 10, .hw_value = 0, },
  32        { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
  33        { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
  34        { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
  35        { .bitrate = 60, .hw_value = 4, },
  36        { .bitrate = 90, .hw_value = 5, },
  37        { .bitrate = 120, .hw_value = 6, },
  38        { .bitrate = 180, .hw_value = 7, },
  39        { .bitrate = 240, .hw_value = 8, },
  40        { .bitrate = 360, .hw_value = 9, },
  41        { .bitrate = 480, .hw_value = 10, },
  42        { .bitrate = 540, .hw_value = 11, },
  43};
  44
  45static struct ieee80211_rate p54_arates[] = {
  46        { .bitrate = 60, .hw_value = 4, },
  47        { .bitrate = 90, .hw_value = 5, },
  48        { .bitrate = 120, .hw_value = 6, },
  49        { .bitrate = 180, .hw_value = 7, },
  50        { .bitrate = 240, .hw_value = 8, },
  51        { .bitrate = 360, .hw_value = 9, },
  52        { .bitrate = 480, .hw_value = 10, },
  53        { .bitrate = 540, .hw_value = 11, },
  54};
  55
  56#define CHAN_HAS_CAL            BIT(0)
  57#define CHAN_HAS_LIMIT          BIT(1)
  58#define CHAN_HAS_CURVE          BIT(2)
  59#define CHAN_HAS_ALL            (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
  60
  61struct p54_channel_entry {
  62        u16 freq;
  63        u16 data;
  64        int index;
  65        enum ieee80211_band band;
  66};
  67
  68struct p54_channel_list {
  69        struct p54_channel_entry *channels;
  70        size_t entries;
  71        size_t max_entries;
  72        size_t band_channel_num[IEEE80211_NUM_BANDS];
  73};
  74
  75static int p54_get_band_from_freq(u16 freq)
  76{
  77        /* FIXME: sync these values with the 802.11 spec */
  78
  79        if ((freq >= 2412) && (freq <= 2484))
  80                return IEEE80211_BAND_2GHZ;
  81
  82        if ((freq >= 4920) && (freq <= 5825))
  83                return IEEE80211_BAND_5GHZ;
  84
  85        return -1;
  86}
  87
  88static int p54_compare_channels(const void *_a,
  89                                const void *_b)
  90{
  91        const struct p54_channel_entry *a = _a;
  92        const struct p54_channel_entry *b = _b;
  93
  94        return a->index - b->index;
  95}
  96
  97static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
  98                                  struct ieee80211_supported_band *band_entry,
  99                                  enum ieee80211_band band)
 100{
 101        /* TODO: generate rate array dynamically */
 102
 103        switch (band) {
 104        case IEEE80211_BAND_2GHZ:
 105                band_entry->bitrates = p54_bgrates;
 106                band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
 107                break;
 108        case IEEE80211_BAND_5GHZ:
 109                band_entry->bitrates = p54_arates;
 110                band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
 111                break;
 112        default:
 113                return -EINVAL;
 114        }
 115
 116        return 0;
 117}
 118
 119static int p54_generate_band(struct ieee80211_hw *dev,
 120                             struct p54_channel_list *list,
 121                             enum ieee80211_band band)
 122{
 123        struct p54_common *priv = dev->priv;
 124        struct ieee80211_supported_band *tmp, *old;
 125        unsigned int i, j;
 126        int ret = -ENOMEM;
 127
 128        if ((!list->entries) || (!list->band_channel_num[band]))
 129                return 0;
 130
 131        tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
 132        if (!tmp)
 133                goto err_out;
 134
 135        tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
 136                                list->band_channel_num[band], GFP_KERNEL);
 137        if (!tmp->channels)
 138                goto err_out;
 139
 140        ret = p54_fill_band_bitrates(dev, tmp, band);
 141        if (ret)
 142                goto err_out;
 143
 144        for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
 145                           (i < list->entries); i++) {
 146
 147                if (list->channels[i].band != band)
 148                        continue;
 149
 150                if (list->channels[i].data != CHAN_HAS_ALL) {
 151                        printk(KERN_ERR "%s:%s%s%s is/are missing for "
 152                                        "channel:%d [%d MHz].\n",
 153                               wiphy_name(dev->wiphy),
 154                               (list->channels[i].data & CHAN_HAS_CAL ? "" :
 155                                " [iqauto calibration data]"),
 156                               (list->channels[i].data & CHAN_HAS_LIMIT ? "" :
 157                                " [output power limits]"),
 158                               (list->channels[i].data & CHAN_HAS_CURVE ? "" :
 159                                " [curve data]"),
 160                               list->channels[i].index, list->channels[i].freq);
 161                }
 162
 163                tmp->channels[j].band = list->channels[i].band;
 164                tmp->channels[j].center_freq = list->channels[i].freq;
 165                j++;
 166        }
 167
 168        tmp->n_channels = list->band_channel_num[band];
 169        old = priv->band_table[band];
 170        priv->band_table[band] = tmp;
 171        if (old) {
 172                kfree(old->channels);
 173                kfree(old);
 174        }
 175
 176        return 0;
 177
 178err_out:
 179        if (tmp) {
 180                kfree(tmp->channels);
 181                kfree(tmp);
 182        }
 183
 184        return ret;
 185}
 186
 187static void p54_update_channel_param(struct p54_channel_list *list,
 188                                     u16 freq, u16 data)
 189{
 190        int band, i;
 191
 192        /*
 193         * usually all lists in the eeprom are mostly sorted.
 194         * so it's very likely that the entry we are looking for
 195         * is right at the end of the list
 196         */
 197        for (i = list->entries; i >= 0; i--) {
 198                if (freq == list->channels[i].freq) {
 199                        list->channels[i].data |= data;
 200                        break;
 201                }
 202        }
 203
 204        if ((i < 0) && (list->entries < list->max_entries)) {
 205                /* entry does not exist yet. Initialize a new one. */
 206                band = p54_get_band_from_freq(freq);
 207
 208                /*
 209                 * filter out frequencies which don't belong into
 210                 * any supported band.
 211                 */
 212                if (band < 0)
 213                        return ;
 214
 215                i = list->entries++;
 216                list->band_channel_num[band]++;
 217
 218                list->channels[i].freq = freq;
 219                list->channels[i].data = data;
 220                list->channels[i].band = band;
 221                list->channels[i].index = ieee80211_frequency_to_channel(freq);
 222                /* TODO: parse output_limit and fill max_power */
 223        }
 224}
 225
 226static int p54_generate_channel_lists(struct ieee80211_hw *dev)
 227{
 228        struct p54_common *priv = dev->priv;
 229        struct p54_channel_list *list;
 230        unsigned int i, j, max_channel_num;
 231        int ret = -ENOMEM;
 232        u16 freq;
 233
 234        if ((priv->iq_autocal_len != priv->curve_data->entries) ||
 235            (priv->iq_autocal_len != priv->output_limit->entries))
 236                printk(KERN_ERR "%s: EEPROM is damaged... you may not be able"
 237                                "to use all channels with this device.\n",
 238                                wiphy_name(dev->wiphy));
 239
 240        max_channel_num = max_t(unsigned int, priv->output_limit->entries,
 241                                priv->iq_autocal_len);
 242        max_channel_num = max_t(unsigned int, max_channel_num,
 243                                priv->curve_data->entries);
 244
 245        list = kzalloc(sizeof(*list), GFP_KERNEL);
 246        if (!list)
 247                goto free;
 248
 249        list->max_entries = max_channel_num;
 250        list->channels = kzalloc(sizeof(struct p54_channel_entry) *
 251                                 max_channel_num, GFP_KERNEL);
 252        if (!list->channels)
 253                goto free;
 254
 255        for (i = 0; i < max_channel_num; i++) {
 256                if (i < priv->iq_autocal_len) {
 257                        freq = le16_to_cpu(priv->iq_autocal[i].freq);
 258                        p54_update_channel_param(list, freq, CHAN_HAS_CAL);
 259                }
 260
 261                if (i < priv->output_limit->entries) {
 262                        freq = le16_to_cpup((__le16 *) (i *
 263                                            priv->output_limit->entry_size +
 264                                            priv->output_limit->offset +
 265                                            priv->output_limit->data));
 266
 267                        p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
 268                }
 269
 270                if (i < priv->curve_data->entries) {
 271                        freq = le16_to_cpup((__le16 *) (i *
 272                                            priv->curve_data->entry_size +
 273                                            priv->curve_data->offset +
 274                                            priv->curve_data->data));
 275
 276                        p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
 277                }
 278        }
 279
 280        /* sort the list by the channel index */
 281        sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
 282             p54_compare_channels, NULL);
 283
 284        for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
 285                if (list->band_channel_num[i]) {
 286                        ret = p54_generate_band(dev, list, i);
 287                        if (ret)
 288                                goto free;
 289
 290                        j++;
 291                }
 292        }
 293        if (j == 0) {
 294                /* no useable band available. */
 295                ret = -EINVAL;
 296        }
 297
 298free:
 299        if (list) {
 300                kfree(list->channels);
 301                kfree(list);
 302        }
 303
 304        return ret;
 305}
 306
 307static int p54_convert_rev0(struct ieee80211_hw *dev,
 308                            struct pda_pa_curve_data *curve_data)
 309{
 310        struct p54_common *priv = dev->priv;
 311        struct p54_pa_curve_data_sample *dst;
 312        struct pda_pa_curve_data_sample_rev0 *src;
 313        size_t cd_len = sizeof(*curve_data) +
 314                (curve_data->points_per_channel*sizeof(*dst) + 2) *
 315                 curve_data->channels;
 316        unsigned int i, j;
 317        void *source, *target;
 318
 319        priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
 320                                   GFP_KERNEL);
 321        if (!priv->curve_data)
 322                return -ENOMEM;
 323
 324        priv->curve_data->entries = curve_data->channels;
 325        priv->curve_data->entry_size = sizeof(__le16) +
 326                sizeof(*dst) * curve_data->points_per_channel;
 327        priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
 328        priv->curve_data->len = cd_len;
 329        memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
 330        source = curve_data->data;
 331        target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
 332        for (i = 0; i < curve_data->channels; i++) {
 333                __le16 *freq = source;
 334                source += sizeof(__le16);
 335                *((__le16 *)target) = *freq;
 336                target += sizeof(__le16);
 337                for (j = 0; j < curve_data->points_per_channel; j++) {
 338                        dst = target;
 339                        src = source;
 340
 341                        dst->rf_power = src->rf_power;
 342                        dst->pa_detector = src->pa_detector;
 343                        dst->data_64qam = src->pcv;
 344                        /* "invent" the points for the other modulations */
 345#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
 346                        dst->data_16qam = SUB(src->pcv, 12);
 347                        dst->data_qpsk = SUB(dst->data_16qam, 12);
 348                        dst->data_bpsk = SUB(dst->data_qpsk, 12);
 349                        dst->data_barker = SUB(dst->data_bpsk, 14);
 350#undef SUB
 351                        target += sizeof(*dst);
 352                        source += sizeof(*src);
 353                }
 354        }
 355
 356        return 0;
 357}
 358
 359static int p54_convert_rev1(struct ieee80211_hw *dev,
 360                            struct pda_pa_curve_data *curve_data)
 361{
 362        struct p54_common *priv = dev->priv;
 363        struct p54_pa_curve_data_sample *dst;
 364        struct pda_pa_curve_data_sample_rev1 *src;
 365        size_t cd_len = sizeof(*curve_data) +
 366                (curve_data->points_per_channel*sizeof(*dst) + 2) *
 367                 curve_data->channels;
 368        unsigned int i, j;
 369        void *source, *target;
 370
 371        priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
 372                                   GFP_KERNEL);
 373        if (!priv->curve_data)
 374                return -ENOMEM;
 375
 376        priv->curve_data->entries = curve_data->channels;
 377        priv->curve_data->entry_size = sizeof(__le16) +
 378                sizeof(*dst) * curve_data->points_per_channel;
 379        priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
 380        priv->curve_data->len = cd_len;
 381        memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
 382        source = curve_data->data;
 383        target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
 384        for (i = 0; i < curve_data->channels; i++) {
 385                __le16 *freq = source;
 386                source += sizeof(__le16);
 387                *((__le16 *)target) = *freq;
 388                target += sizeof(__le16);
 389                for (j = 0; j < curve_data->points_per_channel; j++) {
 390                        memcpy(target, source, sizeof(*src));
 391
 392                        target += sizeof(*dst);
 393                        source += sizeof(*src);
 394                }
 395                source++;
 396        }
 397
 398        return 0;
 399}
 400
 401static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
 402        "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
 403
 404static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len,
 405                             u16 type)
 406{
 407        struct p54_common *priv = dev->priv;
 408        int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0;
 409        int entry_size = sizeof(struct pda_rssi_cal_entry) + offset;
 410        int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
 411        int i;
 412
 413        if (len != (entry_size * num_entries)) {
 414                printk(KERN_ERR "%s: unknown rssi calibration data packing "
 415                                 " type:(%x) len:%d.\n",
 416                       wiphy_name(dev->wiphy), type, len);
 417
 418                print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE,
 419                                     data, len);
 420
 421                printk(KERN_ERR "%s: please report this issue.\n",
 422                        wiphy_name(dev->wiphy));
 423                return;
 424        }
 425
 426        for (i = 0; i < num_entries; i++) {
 427                struct pda_rssi_cal_entry *cal = data +
 428                                                 (offset + i * entry_size);
 429                priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul);
 430                priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add);
 431        }
 432}
 433
 434static void p54_parse_default_country(struct ieee80211_hw *dev,
 435                                      void *data, int len)
 436{
 437        struct pda_country *country;
 438
 439        if (len != sizeof(*country)) {
 440                printk(KERN_ERR "%s: found possible invalid default country "
 441                                "eeprom entry. (entry size: %d)\n",
 442                       wiphy_name(dev->wiphy), len);
 443
 444                print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
 445                                     data, len);
 446
 447                printk(KERN_ERR "%s: please report this issue.\n",
 448                        wiphy_name(dev->wiphy));
 449                return;
 450        }
 451
 452        country = (struct pda_country *) data;
 453        if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
 454                regulatory_hint(dev->wiphy, country->alpha2);
 455        else {
 456                /* TODO:
 457                 * write a shared/common function that converts
 458                 * "Regulatory domain codes" (802.11-2007 14.8.2.2)
 459                 * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
 460                 */
 461        }
 462}
 463
 464static int p54_convert_output_limits(struct ieee80211_hw *dev,
 465                                     u8 *data, size_t len)
 466{
 467        struct p54_common *priv = dev->priv;
 468
 469        if (len < 2)
 470                return -EINVAL;
 471
 472        if (data[0] != 0) {
 473                printk(KERN_ERR "%s: unknown output power db revision:%x\n",
 474                       wiphy_name(dev->wiphy), data[0]);
 475                return -EINVAL;
 476        }
 477
 478        if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
 479                return -EINVAL;
 480
 481        priv->output_limit = kmalloc(data[1] *
 482                sizeof(struct pda_channel_output_limit) +
 483                sizeof(*priv->output_limit), GFP_KERNEL);
 484
 485        if (!priv->output_limit)
 486                return -ENOMEM;
 487
 488        priv->output_limit->offset = 0;
 489        priv->output_limit->entries = data[1];
 490        priv->output_limit->entry_size =
 491                sizeof(struct pda_channel_output_limit);
 492        priv->output_limit->len = priv->output_limit->entry_size *
 493                                  priv->output_limit->entries +
 494                                  priv->output_limit->offset;
 495
 496        memcpy(priv->output_limit->data, &data[2],
 497               data[1] * sizeof(struct pda_channel_output_limit));
 498
 499        return 0;
 500}
 501
 502static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
 503                                               size_t total_len)
 504{
 505        struct p54_cal_database *dst;
 506        size_t payload_len, entries, entry_size, offset;
 507
 508        payload_len = le16_to_cpu(src->len);
 509        entries = le16_to_cpu(src->entries);
 510        entry_size = le16_to_cpu(src->entry_size);
 511        offset = le16_to_cpu(src->offset);
 512        if (((entries * entry_size + offset) != payload_len) ||
 513             (payload_len + sizeof(*src) != total_len))
 514                return NULL;
 515
 516        dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
 517        if (!dst)
 518                return NULL;
 519
 520        dst->entries = entries;
 521        dst->entry_size = entry_size;
 522        dst->offset = offset;
 523        dst->len = payload_len;
 524
 525        memcpy(dst->data, src->data, payload_len);
 526        return dst;
 527}
 528
 529int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
 530{
 531        struct p54_common *priv = dev->priv;
 532        struct eeprom_pda_wrap *wrap;
 533        struct pda_entry *entry;
 534        unsigned int data_len, entry_len;
 535        void *tmp;
 536        int err;
 537        u8 *end = (u8 *)eeprom + len;
 538        u16 synth = 0;
 539
 540        wrap = (struct eeprom_pda_wrap *) eeprom;
 541        entry = (void *)wrap->data + le16_to_cpu(wrap->len);
 542
 543        /* verify that at least the entry length/code fits */
 544        while ((u8 *)entry <= end - sizeof(*entry)) {
 545                entry_len = le16_to_cpu(entry->len);
 546                data_len = ((entry_len - 1) << 1);
 547
 548                /* abort if entry exceeds whole structure */
 549                if ((u8 *)entry + sizeof(*entry) + data_len > end)
 550                        break;
 551
 552                switch (le16_to_cpu(entry->code)) {
 553                case PDR_MAC_ADDRESS:
 554                        if (data_len != ETH_ALEN)
 555                                break;
 556                        SET_IEEE80211_PERM_ADDR(dev, entry->data);
 557                        break;
 558                case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
 559                        if (priv->output_limit)
 560                                break;
 561                        err = p54_convert_output_limits(dev, entry->data,
 562                                                        data_len);
 563                        if (err)
 564                                goto err;
 565                        break;
 566                case PDR_PRISM_PA_CAL_CURVE_DATA: {
 567                        struct pda_pa_curve_data *curve_data =
 568                                (struct pda_pa_curve_data *)entry->data;
 569                        if (data_len < sizeof(*curve_data)) {
 570                                err = -EINVAL;
 571                                goto err;
 572                        }
 573
 574                        switch (curve_data->cal_method_rev) {
 575                        case 0:
 576                                err = p54_convert_rev0(dev, curve_data);
 577                                break;
 578                        case 1:
 579                                err = p54_convert_rev1(dev, curve_data);
 580                                break;
 581                        default:
 582                                printk(KERN_ERR "%s: unknown curve data "
 583                                                "revision %d\n",
 584                                                wiphy_name(dev->wiphy),
 585                                                curve_data->cal_method_rev);
 586                                err = -ENODEV;
 587                                break;
 588                        }
 589                        if (err)
 590                                goto err;
 591                        }
 592                        break;
 593                case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
 594                        priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
 595                        if (!priv->iq_autocal) {
 596                                err = -ENOMEM;
 597                                goto err;
 598                        }
 599
 600                        memcpy(priv->iq_autocal, entry->data, data_len);
 601                        priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
 602                        break;
 603                case PDR_DEFAULT_COUNTRY:
 604                        p54_parse_default_country(dev, entry->data, data_len);
 605                        break;
 606                case PDR_INTERFACE_LIST:
 607                        tmp = entry->data;
 608                        while ((u8 *)tmp < entry->data + data_len) {
 609                                struct exp_if *exp_if = tmp;
 610                                if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
 611                                        synth = le16_to_cpu(exp_if->variant);
 612                                tmp += sizeof(*exp_if);
 613                        }
 614                        break;
 615                case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
 616                        if (data_len < 2)
 617                                break;
 618                        priv->version = *(u8 *)(entry->data + 1);
 619                        break;
 620                case PDR_RSSI_LINEAR_APPROXIMATION:
 621                case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
 622                case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
 623                        p54_parse_rssical(dev, entry->data, data_len,
 624                                          le16_to_cpu(entry->code));
 625                        break;
 626                case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM: {
 627                        __le16 *src = (void *) entry->data;
 628                        s16 *dst = (void *) &priv->rssical_db;
 629                        int i;
 630
 631                        if (data_len != sizeof(priv->rssical_db)) {
 632                                err = -EINVAL;
 633                                goto err;
 634                        }
 635                        for (i = 0; i < sizeof(priv->rssical_db) /
 636                                        sizeof(*src); i++)
 637                                *(dst++) = (s16) le16_to_cpu(*(src++));
 638                        }
 639                        break;
 640                case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
 641                        struct pda_custom_wrapper *pda = (void *) entry->data;
 642                        if (priv->output_limit || data_len < sizeof(*pda))
 643                                break;
 644                        priv->output_limit = p54_convert_db(pda, data_len);
 645                        }
 646                        break;
 647                case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
 648                        struct pda_custom_wrapper *pda = (void *) entry->data;
 649                        if (priv->curve_data || data_len < sizeof(*pda))
 650                                break;
 651                        priv->curve_data = p54_convert_db(pda, data_len);
 652                        }
 653                        break;
 654                case PDR_END:
 655                        /* make it overrun */
 656                        entry_len = len;
 657                        break;
 658                default:
 659                        break;
 660                }
 661
 662                entry = (void *)entry + (entry_len + 1)*2;
 663        }
 664
 665        if (!synth || !priv->iq_autocal || !priv->output_limit ||
 666            !priv->curve_data) {
 667                printk(KERN_ERR "%s: not all required entries found in eeprom!\n",
 668                        wiphy_name(dev->wiphy));
 669                err = -EINVAL;
 670                goto err;
 671        }
 672
 673        err = p54_generate_channel_lists(dev);
 674        if (err)
 675                goto err;
 676
 677        priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
 678        if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
 679                p54_init_xbow_synth(priv);
 680        if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
 681                dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
 682                        priv->band_table[IEEE80211_BAND_2GHZ];
 683        if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
 684                dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
 685                        priv->band_table[IEEE80211_BAND_5GHZ];
 686        if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
 687                priv->rx_diversity_mask = 3;
 688        if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
 689                priv->tx_diversity_mask = 3;
 690
 691        if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
 692                u8 perm_addr[ETH_ALEN];
 693
 694                printk(KERN_WARNING "%s: Invalid hwaddr! Using randomly generated MAC addr\n",
 695                        wiphy_name(dev->wiphy));
 696                random_ether_addr(perm_addr);
 697                SET_IEEE80211_PERM_ADDR(dev, perm_addr);
 698        }
 699
 700        printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n",
 701                wiphy_name(dev->wiphy), dev->wiphy->perm_addr, priv->version,
 702                p54_rf_chips[priv->rxhw]);
 703
 704        return 0;
 705
 706err:
 707        kfree(priv->iq_autocal);
 708        kfree(priv->output_limit);
 709        kfree(priv->curve_data);
 710        priv->iq_autocal = NULL;
 711        priv->output_limit = NULL;
 712        priv->curve_data = NULL;
 713
 714        printk(KERN_ERR "%s: eeprom parse failed!\n",
 715                wiphy_name(dev->wiphy));
 716        return err;
 717}
 718EXPORT_SYMBOL_GPL(p54_parse_eeprom);
 719
 720int p54_read_eeprom(struct ieee80211_hw *dev)
 721{
 722        struct p54_common *priv = dev->priv;
 723        size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
 724        int ret = -ENOMEM;
 725        void *eeprom;
 726
 727        maxblocksize = EEPROM_READBACK_LEN;
 728        if (priv->fw_var >= 0x509)
 729                maxblocksize -= 0xc;
 730        else
 731                maxblocksize -= 0x4;
 732
 733        eeprom = kzalloc(eeprom_size, GFP_KERNEL);
 734        if (unlikely(!eeprom))
 735                goto free;
 736
 737        while (eeprom_size) {
 738                blocksize = min(eeprom_size, maxblocksize);
 739                ret = p54_download_eeprom(priv, (void *) (eeprom + offset),
 740                                          offset, blocksize);
 741                if (unlikely(ret))
 742                        goto free;
 743
 744                offset += blocksize;
 745                eeprom_size -= blocksize;
 746        }
 747
 748        ret = p54_parse_eeprom(dev, eeprom, offset);
 749free:
 750        kfree(eeprom);
 751        return ret;
 752}
 753EXPORT_SYMBOL_GPL(p54_read_eeprom);
 754