p54: move under intersil vendor directory
authorKalle Valo <kvalo@codeaurora.org>
Wed, 18 Nov 2015 07:49:59 +0000 (09:49 +0200)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 18 Nov 2015 12:28:31 +0000 (14:28 +0200)
Part of reorganising wireless drivers directory and Kconfig.

Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
39 files changed:
MAINTAINERS
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/intersil/Kconfig
drivers/net/wireless/intersil/Makefile
drivers/net/wireless/intersil/p54/Kconfig [new file with mode: 0644]
drivers/net/wireless/intersil/p54/Makefile [new file with mode: 0644]
drivers/net/wireless/intersil/p54/eeprom.c [new file with mode: 0644]
drivers/net/wireless/intersil/p54/eeprom.h [new file with mode: 0644]
drivers/net/wireless/intersil/p54/fwio.c [new file with mode: 0644]
drivers/net/wireless/intersil/p54/led.c [new file with mode: 0644]
drivers/net/wireless/intersil/p54/lmac.h [new file with mode: 0644]
drivers/net/wireless/intersil/p54/main.c [new file with mode: 0644]
drivers/net/wireless/intersil/p54/p54.h [new file with mode: 0644]
drivers/net/wireless/intersil/p54/p54pci.c [new file with mode: 0644]
drivers/net/wireless/intersil/p54/p54pci.h [new file with mode: 0644]
drivers/net/wireless/intersil/p54/p54spi.c [new file with mode: 0644]
drivers/net/wireless/intersil/p54/p54spi.h [new file with mode: 0644]
drivers/net/wireless/intersil/p54/p54spi_eeprom.h [new file with mode: 0644]
drivers/net/wireless/intersil/p54/p54usb.c [new file with mode: 0644]
drivers/net/wireless/intersil/p54/p54usb.h [new file with mode: 0644]
drivers/net/wireless/intersil/p54/txrx.c [new file with mode: 0644]
drivers/net/wireless/p54/Kconfig [deleted file]
drivers/net/wireless/p54/Makefile [deleted file]
drivers/net/wireless/p54/eeprom.c [deleted file]
drivers/net/wireless/p54/eeprom.h [deleted file]
drivers/net/wireless/p54/fwio.c [deleted file]
drivers/net/wireless/p54/led.c [deleted file]
drivers/net/wireless/p54/lmac.h [deleted file]
drivers/net/wireless/p54/main.c [deleted file]
drivers/net/wireless/p54/p54.h [deleted file]
drivers/net/wireless/p54/p54pci.c [deleted file]
drivers/net/wireless/p54/p54pci.h [deleted file]
drivers/net/wireless/p54/p54spi.c [deleted file]
drivers/net/wireless/p54/p54spi.h [deleted file]
drivers/net/wireless/p54/p54spi_eeprom.h [deleted file]
drivers/net/wireless/p54/p54usb.c [deleted file]
drivers/net/wireless/p54/p54usb.h [deleted file]
drivers/net/wireless/p54/txrx.c [deleted file]

index 63c601b..818899a 100644 (file)
@@ -7956,7 +7956,7 @@ M:        Christian Lamparter <chunkeey@googlemail.com>
 L:     linux-wireless@vger.kernel.org
 W:     http://wireless.kernel.org/en/users/Drivers/p54
 S:     Maintained
-F:     drivers/net/wireless/p54/
+F:     drivers/net/wireless/intersil/p54/
 
 PA SEMI ETHERNET DRIVER
 M:     Olof Johansson <olof@lixom.net>
index da10b00..bea2fbb 100644 (file)
@@ -118,7 +118,6 @@ config MAC80211_HWSIM
 
 source "drivers/net/wireless/ath/Kconfig"
 source "drivers/net/wireless/orinoco/Kconfig"
-source "drivers/net/wireless/p54/Kconfig"
 source "drivers/net/wireless/rt2x00/Kconfig"
 source "drivers/net/wireless/mediatek/Kconfig"
 source "drivers/net/wireless/realtek/rtlwifi/Kconfig"
index a60c5e5..046963f 100644 (file)
@@ -28,8 +28,6 @@ obj-$(CONFIG_RT2X00)  += rt2x00/
 
 obj-$(CONFIG_WL_MEDIATEK)      += mediatek/
 
-obj-$(CONFIG_P54_COMMON)       += p54/
-
 obj-$(CONFIG_ATH_CARDS)                += ath/
 
 obj-$(CONFIG_MAC80211_HWSIM)   += mac80211_hwsim.o
index ec80b91..4bc3688 100644 (file)
@@ -12,5 +12,6 @@ config WLAN_VENDOR_INTERSIL
 if WLAN_VENDOR_INTERSIL
 
 source "drivers/net/wireless/intersil/hostap/Kconfig"
+source "drivers/net/wireless/intersil/p54/Kconfig"
 
 endif # WLAN_VENDOR_INTERSIL
index 4890ef7..90a7283 100644 (file)
@@ -1 +1,2 @@
 obj-$(CONFIG_HOSTAP)           += hostap/
+obj-$(CONFIG_P54_COMMON)       += p54/
diff --git a/drivers/net/wireless/intersil/p54/Kconfig b/drivers/net/wireless/intersil/p54/Kconfig
new file mode 100644 (file)
index 0000000..cdafb8c
--- /dev/null
@@ -0,0 +1,71 @@
+config P54_COMMON
+       tristate "Softmac Prism54 support"
+       depends on MAC80211
+       select FW_LOADER
+       select CRC_CCITT
+       ---help---
+         This is common code for isl38xx/stlc45xx based modules.
+         This module does nothing by itself - the USB/PCI/SPI front-ends
+         also need to be enabled in order to support any devices.
+
+         These devices require softmac firmware which can be found at
+         <http://wireless.kernel.org/en/users/Drivers/p54>
+
+         If you choose to build a module, it'll be called p54common.
+
+config P54_USB
+       tristate "Prism54 USB support"
+       depends on P54_COMMON && USB
+       select CRC32
+       ---help---
+         This driver is for USB isl38xx based wireless cards.
+
+         These devices require softmac firmware which can be found at
+         <http://wireless.kernel.org/en/users/Drivers/p54>
+
+         If you choose to build a module, it'll be called p54usb.
+
+config P54_PCI
+       tristate "Prism54 PCI support"
+       depends on P54_COMMON && PCI
+       ---help---
+         This driver is for PCI isl38xx based wireless cards.
+         This driver supports most devices that are supported by the
+         fullmac prism54 driver plus many devices which are not
+         supported by the fullmac driver/firmware.
+
+         This driver requires softmac firmware which can be found at
+         <http://wireless.kernel.org/en/users/Drivers/p54>
+
+         If you choose to build a module, it'll be called p54pci.
+
+config P54_SPI
+       tristate "Prism54 SPI (stlc45xx) support"
+       depends on P54_COMMON && SPI_MASTER
+       ---help---
+         This driver is for stlc4550 or stlc4560 based wireless chips
+         such as Nokia's N800/N810 Portable Internet Tablet.
+
+         If you choose to build a module, it'll be called p54spi.
+
+config P54_SPI_DEFAULT_EEPROM
+       bool "Include fallback EEPROM blob"
+       depends on P54_SPI
+       default n
+       ---help---
+        Unlike the PCI or USB devices, the SPI variants don't have
+        a dedicated EEPROM chip to store all device specific values
+        for calibration, country and interface settings.
+
+        The driver will try to load the image "3826.eeprom", if the
+        file is put at the right place. (usually /lib/firmware.)
+
+        Only if this request fails, this option will provide a
+        backup set of generic values to get the device working.
+
+        Enabling this option adds about 4k to p54spi.
+
+config P54_LEDS
+       bool
+       depends on P54_COMMON && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = P54_COMMON)
+       default y
diff --git a/drivers/net/wireless/intersil/p54/Makefile b/drivers/net/wireless/intersil/p54/Makefile
new file mode 100644 (file)
index 0000000..b542e68
--- /dev/null
@@ -0,0 +1,7 @@
+p54common-objs                 := eeprom.o fwio.o txrx.o main.o
+p54common-$(CONFIG_P54_LEDS)   += led.o
+
+obj-$(CONFIG_P54_COMMON)       += p54common.o
+obj-$(CONFIG_P54_USB)          += p54usb.o
+obj-$(CONFIG_P54_PCI)          += p54pci.o
+obj-$(CONFIG_P54_SPI)          += p54spi.o
diff --git a/drivers/net/wireless/intersil/p54/eeprom.c b/drivers/net/wireless/intersil/p54/eeprom.c
new file mode 100644 (file)
index 0000000..2fe713e
--- /dev/null
@@ -0,0 +1,982 @@
+/*
+ * EEPROM parser code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/sort.h>
+#include <linux/slab.h>
+
+#include <net/mac80211.h>
+#include <linux/crc-ccitt.h>
+#include <linux/export.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+static struct ieee80211_rate p54_bgrates[] = {
+       { .bitrate = 10, .hw_value = 0, },
+       { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
+       { .bitrate = 60, .hw_value = 4, },
+       { .bitrate = 90, .hw_value = 5, },
+       { .bitrate = 120, .hw_value = 6, },
+       { .bitrate = 180, .hw_value = 7, },
+       { .bitrate = 240, .hw_value = 8, },
+       { .bitrate = 360, .hw_value = 9, },
+       { .bitrate = 480, .hw_value = 10, },
+       { .bitrate = 540, .hw_value = 11, },
+};
+
+static struct ieee80211_rate p54_arates[] = {
+       { .bitrate = 60, .hw_value = 4, },
+       { .bitrate = 90, .hw_value = 5, },
+       { .bitrate = 120, .hw_value = 6, },
+       { .bitrate = 180, .hw_value = 7, },
+       { .bitrate = 240, .hw_value = 8, },
+       { .bitrate = 360, .hw_value = 9, },
+       { .bitrate = 480, .hw_value = 10, },
+       { .bitrate = 540, .hw_value = 11, },
+};
+
+static struct p54_rssi_db_entry p54_rssi_default = {
+       /*
+        * The defaults are taken from usb-logs of the
+        * vendor driver. So, they should be safe to
+        * use in case we can't get a match from the
+        * rssi <-> dBm conversion database.
+        */
+       .mul = 130,
+       .add = -398,
+};
+
+#define CHAN_HAS_CAL           BIT(0)
+#define CHAN_HAS_LIMIT         BIT(1)
+#define CHAN_HAS_CURVE         BIT(2)
+#define CHAN_HAS_ALL           (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
+
+struct p54_channel_entry {
+       u16 freq;
+       u16 data;
+       int index;
+       int max_power;
+       enum ieee80211_band band;
+};
+
+struct p54_channel_list {
+       struct p54_channel_entry *channels;
+       size_t entries;
+       size_t max_entries;
+       size_t band_channel_num[IEEE80211_NUM_BANDS];
+};
+
+static int p54_get_band_from_freq(u16 freq)
+{
+       /* FIXME: sync these values with the 802.11 spec */
+
+       if ((freq >= 2412) && (freq <= 2484))
+               return IEEE80211_BAND_2GHZ;
+
+       if ((freq >= 4920) && (freq <= 5825))
+               return IEEE80211_BAND_5GHZ;
+
+       return -1;
+}
+
+static int same_band(u16 freq, u16 freq2)
+{
+       return p54_get_band_from_freq(freq) == p54_get_band_from_freq(freq2);
+}
+
+static int p54_compare_channels(const void *_a,
+                               const void *_b)
+{
+       const struct p54_channel_entry *a = _a;
+       const struct p54_channel_entry *b = _b;
+
+       return a->freq - b->freq;
+}
+
+static int p54_compare_rssichan(const void *_a,
+                               const void *_b)
+{
+       const struct p54_rssi_db_entry *a = _a;
+       const struct p54_rssi_db_entry *b = _b;
+
+       return a->freq - b->freq;
+}
+
+static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
+                                 struct ieee80211_supported_band *band_entry,
+                                 enum ieee80211_band band)
+{
+       /* TODO: generate rate array dynamically */
+
+       switch (band) {
+       case IEEE80211_BAND_2GHZ:
+               band_entry->bitrates = p54_bgrates;
+               band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
+               break;
+       case IEEE80211_BAND_5GHZ:
+               band_entry->bitrates = p54_arates;
+               band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int p54_generate_band(struct ieee80211_hw *dev,
+                            struct p54_channel_list *list,
+                            unsigned int *chan_num,
+                            enum ieee80211_band band)
+{
+       struct p54_common *priv = dev->priv;
+       struct ieee80211_supported_band *tmp, *old;
+       unsigned int i, j;
+       int ret = -ENOMEM;
+
+       if ((!list->entries) || (!list->band_channel_num[band]))
+               return -EINVAL;
+
+       tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
+       if (!tmp)
+               goto err_out;
+
+       tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
+                               list->band_channel_num[band], GFP_KERNEL);
+       if (!tmp->channels)
+               goto err_out;
+
+       ret = p54_fill_band_bitrates(dev, tmp, band);
+       if (ret)
+               goto err_out;
+
+       for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
+                          (i < list->entries); i++) {
+               struct p54_channel_entry *chan = &list->channels[i];
+               struct ieee80211_channel *dest = &tmp->channels[j];
+
+               if (chan->band != band)
+                       continue;
+
+               if (chan->data != CHAN_HAS_ALL) {
+                       wiphy_err(dev->wiphy, "%s%s%s is/are missing for "
+                                 "channel:%d [%d MHz].\n",
+                                 (chan->data & CHAN_HAS_CAL ? "" :
+                                  " [iqauto calibration data]"),
+                                 (chan->data & CHAN_HAS_LIMIT ? "" :
+                                  " [output power limits]"),
+                                 (chan->data & CHAN_HAS_CURVE ? "" :
+                                  " [curve data]"),
+                                 chan->index, chan->freq);
+                       continue;
+               }
+
+               dest->band = chan->band;
+               dest->center_freq = chan->freq;
+               dest->max_power = chan->max_power;
+               priv->survey[*chan_num].channel = &tmp->channels[j];
+               priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
+                       SURVEY_INFO_TIME |
+                       SURVEY_INFO_TIME_BUSY |
+                       SURVEY_INFO_TIME_TX;
+               dest->hw_value = (*chan_num);
+               j++;
+               (*chan_num)++;
+       }
+
+       if (j == 0) {
+               wiphy_err(dev->wiphy, "Disabling totally damaged %d GHz band\n",
+                         (band == IEEE80211_BAND_2GHZ) ? 2 : 5);
+
+               ret = -ENODATA;
+               goto err_out;
+       }
+
+       tmp->n_channels = j;
+       old = priv->band_table[band];
+       priv->band_table[band] = tmp;
+       if (old) {
+               kfree(old->channels);
+               kfree(old);
+       }
+
+       return 0;
+
+err_out:
+       if (tmp) {
+               kfree(tmp->channels);
+               kfree(tmp);
+       }
+
+       return ret;
+}
+
+static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
+                                                         u16 freq, u16 data)
+{
+       int i;
+       struct p54_channel_entry *entry = NULL;
+
+       /*
+        * usually all lists in the eeprom are mostly sorted.
+        * so it's very likely that the entry we are looking for
+        * is right at the end of the list
+        */
+       for (i = list->entries; i >= 0; i--) {
+               if (freq == list->channels[i].freq) {
+                       entry = &list->channels[i];
+                       break;
+               }
+       }
+
+       if ((i < 0) && (list->entries < list->max_entries)) {
+               /* entry does not exist yet. Initialize a new one. */
+               int band = p54_get_band_from_freq(freq);
+
+               /*
+                * filter out frequencies which don't belong into
+                * any supported band.
+                */
+               if (band >= 0) {
+                       i = list->entries++;
+                       list->band_channel_num[band]++;
+
+                       entry = &list->channels[i];
+                       entry->freq = freq;
+                       entry->band = band;
+                       entry->index = ieee80211_frequency_to_channel(freq);
+                       entry->max_power = 0;
+                       entry->data = 0;
+               }
+       }
+
+       if (entry)
+               entry->data |= data;
+
+       return entry;
+}
+
+static int p54_get_maxpower(struct p54_common *priv, void *data)
+{
+       switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) {
+       case PDR_SYNTH_FRONTEND_LONGBOW: {
+               struct pda_channel_output_limit_longbow *pda = data;
+               int j;
+               u16 rawpower = 0;
+               pda = data;
+               for (j = 0; j < ARRAY_SIZE(pda->point); j++) {
+                       struct pda_channel_output_limit_point_longbow *point =
+                               &pda->point[j];
+                       rawpower = max_t(u16,
+                               rawpower, le16_to_cpu(point->val_qpsk));
+                       rawpower = max_t(u16,
+                               rawpower, le16_to_cpu(point->val_bpsk));
+                       rawpower = max_t(u16,
+                               rawpower, le16_to_cpu(point->val_16qam));
+                       rawpower = max_t(u16,
+                               rawpower, le16_to_cpu(point->val_64qam));
+               }
+               /* longbow seems to use 1/16 dBm units */
+               return rawpower / 16;
+               }
+
+       case PDR_SYNTH_FRONTEND_DUETTE3:
+       case PDR_SYNTH_FRONTEND_DUETTE2:
+       case PDR_SYNTH_FRONTEND_FRISBEE:
+       case PDR_SYNTH_FRONTEND_XBOW: {
+               struct pda_channel_output_limit *pda = data;
+               u8 rawpower = 0;
+               rawpower = max(rawpower, pda->val_qpsk);
+               rawpower = max(rawpower, pda->val_bpsk);
+               rawpower = max(rawpower, pda->val_16qam);
+               rawpower = max(rawpower, pda->val_64qam);
+               /* raw values are in 1/4 dBm units */
+               return rawpower / 4;
+               }
+
+       default:
+               return 20;
+       }
+}
+
+static int p54_generate_channel_lists(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       struct p54_channel_list *list;
+       unsigned int i, j, k, max_channel_num;
+       int ret = 0;
+       u16 freq;
+
+       if ((priv->iq_autocal_len != priv->curve_data->entries) ||
+           (priv->iq_autocal_len != priv->output_limit->entries))
+               wiphy_err(dev->wiphy,
+                         "Unsupported or damaged EEPROM detected. "
+                         "You may not be able to use all channels.\n");
+
+       max_channel_num = max_t(unsigned int, priv->output_limit->entries,
+                               priv->iq_autocal_len);
+       max_channel_num = max_t(unsigned int, max_channel_num,
+                               priv->curve_data->entries);
+
+       list = kzalloc(sizeof(*list), GFP_KERNEL);
+       if (!list) {
+               ret = -ENOMEM;
+               goto free;
+       }
+       priv->chan_num = max_channel_num;
+       priv->survey = kzalloc(sizeof(struct survey_info) * max_channel_num,
+                              GFP_KERNEL);
+       if (!priv->survey) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       list->max_entries = max_channel_num;
+       list->channels = kzalloc(sizeof(struct p54_channel_entry) *
+                                max_channel_num, GFP_KERNEL);
+       if (!list->channels) {
+               ret = -ENOMEM;
+               goto free;
+       }
+
+       for (i = 0; i < max_channel_num; i++) {
+               if (i < priv->iq_autocal_len) {
+                       freq = le16_to_cpu(priv->iq_autocal[i].freq);
+                       p54_update_channel_param(list, freq, CHAN_HAS_CAL);
+               }
+
+               if (i < priv->output_limit->entries) {
+                       struct p54_channel_entry *tmp;
+
+                       void *data = (void *) ((unsigned long) i *
+                               priv->output_limit->entry_size +
+                               priv->output_limit->offset +
+                               priv->output_limit->data);
+
+                       freq = le16_to_cpup((__le16 *) data);
+                       tmp = p54_update_channel_param(list, freq,
+                                                      CHAN_HAS_LIMIT);
+                       if (tmp) {
+                               tmp->max_power = p54_get_maxpower(priv, data);
+                       }
+               }
+
+               if (i < priv->curve_data->entries) {
+                       freq = le16_to_cpup((__le16 *) (i *
+                                           priv->curve_data->entry_size +
+                                           priv->curve_data->offset +
+                                           priv->curve_data->data));
+
+                       p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
+               }
+       }
+
+       /* sort the channel list by frequency */
+       sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
+            p54_compare_channels, NULL);
+
+       k = 0;
+       for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
+               if (p54_generate_band(dev, list, &k, i) == 0)
+                       j++;
+       }
+       if (j == 0) {
+               /* no useable band available. */
+               ret = -EINVAL;
+       }
+
+free:
+       if (list) {
+               kfree(list->channels);
+               kfree(list);
+       }
+       if (ret) {
+               kfree(priv->survey);
+               priv->survey = NULL;
+       }
+
+       return ret;
+}
+
+static int p54_convert_rev0(struct ieee80211_hw *dev,
+                           struct pda_pa_curve_data *curve_data)
+{
+       struct p54_common *priv = dev->priv;
+       struct p54_pa_curve_data_sample *dst;
+       struct pda_pa_curve_data_sample_rev0 *src;
+       size_t cd_len = sizeof(*curve_data) +
+               (curve_data->points_per_channel*sizeof(*dst) + 2) *
+                curve_data->channels;
+       unsigned int i, j;
+       void *source, *target;
+
+       priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
+                                  GFP_KERNEL);
+       if (!priv->curve_data)
+               return -ENOMEM;
+
+       priv->curve_data->entries = curve_data->channels;
+       priv->curve_data->entry_size = sizeof(__le16) +
+               sizeof(*dst) * curve_data->points_per_channel;
+       priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+       priv->curve_data->len = cd_len;
+       memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+       source = curve_data->data;
+       target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+       for (i = 0; i < curve_data->channels; i++) {
+               __le16 *freq = source;
+               source += sizeof(__le16);
+               *((__le16 *)target) = *freq;
+               target += sizeof(__le16);
+               for (j = 0; j < curve_data->points_per_channel; j++) {
+                       dst = target;
+                       src = source;
+
+                       dst->rf_power = src->rf_power;
+                       dst->pa_detector = src->pa_detector;
+                       dst->data_64qam = src->pcv;
+                       /* "invent" the points for the other modulations */
+#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
+                       dst->data_16qam = SUB(src->pcv, 12);
+                       dst->data_qpsk = SUB(dst->data_16qam, 12);
+                       dst->data_bpsk = SUB(dst->data_qpsk, 12);
+                       dst->data_barker = SUB(dst->data_bpsk, 14);
+#undef SUB
+                       target += sizeof(*dst);
+                       source += sizeof(*src);
+               }
+       }
+
+       return 0;
+}
+
+static int p54_convert_rev1(struct ieee80211_hw *dev,
+                           struct pda_pa_curve_data *curve_data)
+{
+       struct p54_common *priv = dev->priv;
+       struct p54_pa_curve_data_sample *dst;
+       struct pda_pa_curve_data_sample_rev1 *src;
+       size_t cd_len = sizeof(*curve_data) +
+               (curve_data->points_per_channel*sizeof(*dst) + 2) *
+                curve_data->channels;
+       unsigned int i, j;
+       void *source, *target;
+
+       priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
+                                  GFP_KERNEL);
+       if (!priv->curve_data)
+               return -ENOMEM;
+
+       priv->curve_data->entries = curve_data->channels;
+       priv->curve_data->entry_size = sizeof(__le16) +
+               sizeof(*dst) * curve_data->points_per_channel;
+       priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
+       priv->curve_data->len = cd_len;
+       memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
+       source = curve_data->data;
+       target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
+       for (i = 0; i < curve_data->channels; i++) {
+               __le16 *freq = source;
+               source += sizeof(__le16);
+               *((__le16 *)target) = *freq;
+               target += sizeof(__le16);
+               for (j = 0; j < curve_data->points_per_channel; j++) {
+                       memcpy(target, source, sizeof(*src));
+
+                       target += sizeof(*dst);
+                       source += sizeof(*src);
+               }
+               source++;
+       }
+
+       return 0;
+}
+
+static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
+       "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
+
+static int p54_parse_rssical(struct ieee80211_hw *dev,
+                            u8 *data, int len, u16 type)
+{
+       struct p54_common *priv = dev->priv;
+       struct p54_rssi_db_entry *entry;
+       size_t db_len, entries;
+       int offset = 0, i;
+
+       if (type != PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
+               entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
+               if (len != sizeof(struct pda_rssi_cal_entry) * entries) {
+                       wiphy_err(dev->wiphy, "rssical size mismatch.\n");
+                       goto err_data;
+               }
+       } else {
+               /*
+                * Some devices (Dell 1450 USB, Xbow 5GHz card, etc...)
+                * have an empty two byte header.
+                */
+               if (*((__le16 *)&data[offset]) == cpu_to_le16(0))
+                       offset += 2;
+
+               entries = (len - offset) /
+                       sizeof(struct pda_rssi_cal_ext_entry);
+
+               if (len < offset ||
+                   (len - offset) % sizeof(struct pda_rssi_cal_ext_entry) ||
+                   entries == 0) {
+                       wiphy_err(dev->wiphy, "invalid rssi database.\n");
+                       goto err_data;
+               }
+       }
+
+       db_len = sizeof(*entry) * entries;
+       priv->rssi_db = kzalloc(db_len + sizeof(*priv->rssi_db), GFP_KERNEL);
+       if (!priv->rssi_db)
+               return -ENOMEM;
+
+       priv->rssi_db->offset = 0;
+       priv->rssi_db->entries = entries;
+       priv->rssi_db->entry_size = sizeof(*entry);
+       priv->rssi_db->len = db_len;
+
+       entry = (void *)((unsigned long)priv->rssi_db->data + priv->rssi_db->offset);
+       if (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
+               struct pda_rssi_cal_ext_entry *cal = (void *) &data[offset];
+
+               for (i = 0; i < entries; i++) {
+                       entry[i].freq = le16_to_cpu(cal[i].freq);
+                       entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
+                       entry[i].add = (s16) le16_to_cpu(cal[i].add);
+               }
+       } else {
+               struct pda_rssi_cal_entry *cal = (void *) &data[offset];
+
+               for (i = 0; i < entries; i++) {
+                       u16 freq = 0;
+                       switch (i) {
+                       case IEEE80211_BAND_2GHZ:
+                               freq = 2437;
+                               break;
+                       case IEEE80211_BAND_5GHZ:
+                               freq = 5240;
+                               break;
+                       }
+
+                       entry[i].freq = freq;
+                       entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
+                       entry[i].add = (s16) le16_to_cpu(cal[i].add);
+               }
+       }
+
+       /* sort the list by channel frequency */
+       sort(entry, entries, sizeof(*entry), p54_compare_rssichan, NULL);
+       return 0;
+
+err_data:
+       wiphy_err(dev->wiphy,
+                 "rssi calibration data packing type:(%x) len:%d.\n",
+                 type, len);
+
+       print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, data, len);
+
+       wiphy_err(dev->wiphy, "please report this issue.\n");
+       return -EINVAL;
+}
+
+struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *priv, const u16 freq)
+{
+       struct p54_rssi_db_entry *entry;
+       int i, found = -1;
+
+       if (!priv->rssi_db)
+               return &p54_rssi_default;
+
+       entry = (void *)(priv->rssi_db->data + priv->rssi_db->offset);
+       for (i = 0; i < priv->rssi_db->entries; i++) {
+               if (!same_band(freq, entry[i].freq))
+                       continue;
+
+               if (found == -1) {
+                       found = i;
+                       continue;
+               }
+
+               /* nearest match */
+               if (abs(freq - entry[i].freq) <
+                   abs(freq - entry[found].freq)) {
+                       found = i;
+                       continue;
+               } else {
+                       break;
+               }
+       }
+
+       return found < 0 ? &p54_rssi_default : &entry[found];
+}
+
+static void p54_parse_default_country(struct ieee80211_hw *dev,
+                                     void *data, int len)
+{
+       struct pda_country *country;
+
+       if (len != sizeof(*country)) {
+               wiphy_err(dev->wiphy,
+                         "found possible invalid default country eeprom entry. (entry size: %d)\n",
+                         len);
+
+               print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
+                                    data, len);
+
+               wiphy_err(dev->wiphy, "please report this issue.\n");
+               return;
+       }
+
+       country = (struct pda_country *) data;
+       if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
+               regulatory_hint(dev->wiphy, country->alpha2);
+       else {
+               /* TODO:
+                * write a shared/common function that converts
+                * "Regulatory domain codes" (802.11-2007 14.8.2.2)
+                * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
+                */
+       }
+}
+
+static int p54_convert_output_limits(struct ieee80211_hw *dev,
+                                    u8 *data, size_t len)
+{
+       struct p54_common *priv = dev->priv;
+
+       if (len < 2)
+               return -EINVAL;
+
+       if (data[0] != 0) {
+               wiphy_err(dev->wiphy, "unknown output power db revision:%x\n",
+                         data[0]);
+               return -EINVAL;
+       }
+
+       if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
+               return -EINVAL;
+
+       priv->output_limit = kmalloc(data[1] *
+               sizeof(struct pda_channel_output_limit) +
+               sizeof(*priv->output_limit), GFP_KERNEL);
+
+       if (!priv->output_limit)
+               return -ENOMEM;
+
+       priv->output_limit->offset = 0;
+       priv->output_limit->entries = data[1];
+       priv->output_limit->entry_size =
+               sizeof(struct pda_channel_output_limit);
+       priv->output_limit->len = priv->output_limit->entry_size *
+                                 priv->output_limit->entries +
+                                 priv->output_limit->offset;
+
+       memcpy(priv->output_limit->data, &data[2],
+              data[1] * sizeof(struct pda_channel_output_limit));
+
+       return 0;
+}
+
+static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
+                                              size_t total_len)
+{
+       struct p54_cal_database *dst;
+       size_t payload_len, entries, entry_size, offset;
+
+       payload_len = le16_to_cpu(src->len);
+       entries = le16_to_cpu(src->entries);
+       entry_size = le16_to_cpu(src->entry_size);
+       offset = le16_to_cpu(src->offset);
+       if (((entries * entry_size + offset) != payload_len) ||
+            (payload_len + sizeof(*src) != total_len))
+               return NULL;
+
+       dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
+       if (!dst)
+               return NULL;
+
+       dst->entries = entries;
+       dst->entry_size = entry_size;
+       dst->offset = offset;
+       dst->len = payload_len;
+
+       memcpy(dst->data, src->data, payload_len);
+       return dst;
+}
+
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
+{
+       struct p54_common *priv = dev->priv;
+       struct eeprom_pda_wrap *wrap;
+       struct pda_entry *entry;
+       unsigned int data_len, entry_len;
+       void *tmp;
+       int err;
+       u8 *end = (u8 *)eeprom + len;
+       u16 synth = 0;
+       u16 crc16 = ~0;
+
+       wrap = (struct eeprom_pda_wrap *) eeprom;
+       entry = (void *)wrap->data + le16_to_cpu(wrap->len);
+
+       /* verify that at least the entry length/code fits */
+       while ((u8 *)entry <= end - sizeof(*entry)) {
+               entry_len = le16_to_cpu(entry->len);
+               data_len = ((entry_len - 1) << 1);
+
+               /* abort if entry exceeds whole structure */
+               if ((u8 *)entry + sizeof(*entry) + data_len > end)
+                       break;
+
+               switch (le16_to_cpu(entry->code)) {
+               case PDR_MAC_ADDRESS:
+                       if (data_len != ETH_ALEN)
+                               break;
+                       SET_IEEE80211_PERM_ADDR(dev, entry->data);
+                       break;
+               case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
+                       if (priv->output_limit)
+                               break;
+                       err = p54_convert_output_limits(dev, entry->data,
+                                                       data_len);
+                       if (err)
+                               goto err;
+                       break;
+               case PDR_PRISM_PA_CAL_CURVE_DATA: {
+                       struct pda_pa_curve_data *curve_data =
+                               (struct pda_pa_curve_data *)entry->data;
+                       if (data_len < sizeof(*curve_data)) {
+                               err = -EINVAL;
+                               goto err;
+                       }
+
+                       switch (curve_data->cal_method_rev) {
+                       case 0:
+                               err = p54_convert_rev0(dev, curve_data);
+                               break;
+                       case 1:
+                               err = p54_convert_rev1(dev, curve_data);
+                               break;
+                       default:
+                               wiphy_err(dev->wiphy,
+                                         "unknown curve data revision %d\n",
+                                         curve_data->cal_method_rev);
+                               err = -ENODEV;
+                               break;
+                       }
+                       if (err)
+                               goto err;
+                       }
+                       break;
+               case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
+                       priv->iq_autocal = kmemdup(entry->data, data_len,
+                                                  GFP_KERNEL);
+                       if (!priv->iq_autocal) {
+                               err = -ENOMEM;
+                               goto err;
+                       }
+
+                       priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
+                       break;
+               case PDR_DEFAULT_COUNTRY:
+                       p54_parse_default_country(dev, entry->data, data_len);
+                       break;
+               case PDR_INTERFACE_LIST:
+                       tmp = entry->data;
+                       while ((u8 *)tmp < entry->data + data_len) {
+                               struct exp_if *exp_if = tmp;
+                               if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
+                                       synth = le16_to_cpu(exp_if->variant);
+                               tmp += sizeof(*exp_if);
+                       }
+                       break;
+               case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
+                       if (data_len < 2)
+                               break;
+                       priv->version = *(u8 *)(entry->data + 1);
+                       break;
+               case PDR_RSSI_LINEAR_APPROXIMATION:
+               case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
+               case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
+                       err = p54_parse_rssical(dev, entry->data, data_len,
+                                               le16_to_cpu(entry->code));
+                       if (err)
+                               goto err;
+                       break;
+               case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2: {
+                       struct pda_custom_wrapper *pda = (void *) entry->data;
+                       __le16 *src;
+                       u16 *dst;
+                       int i;
+
+                       if (priv->rssi_db || data_len < sizeof(*pda))
+                               break;
+
+                       priv->rssi_db = p54_convert_db(pda, data_len);
+                       if (!priv->rssi_db)
+                               break;
+
+                       src = (void *) priv->rssi_db->data;
+                       dst = (void *) priv->rssi_db->data;
+
+                       for (i = 0; i < priv->rssi_db->entries; i++)
+                               *(dst++) = (s16) le16_to_cpu(*(src++));
+
+                       }
+                       break;
+               case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
+                       struct pda_custom_wrapper *pda = (void *) entry->data;
+                       if (priv->output_limit || data_len < sizeof(*pda))
+                               break;
+                       priv->output_limit = p54_convert_db(pda, data_len);
+                       }
+                       break;
+               case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
+                       struct pda_custom_wrapper *pda = (void *) entry->data;
+                       if (priv->curve_data || data_len < sizeof(*pda))
+                               break;
+                       priv->curve_data = p54_convert_db(pda, data_len);
+                       }
+                       break;
+               case PDR_END:
+                       crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry));
+                       if (crc16 != le16_to_cpup((__le16 *)entry->data)) {
+                               wiphy_err(dev->wiphy, "eeprom failed checksum "
+                                        "test!\n");
+                               err = -ENOMSG;
+                               goto err;
+                       } else {
+                               goto good_eeprom;
+                       }
+                       break;
+               default:
+                       break;
+               }
+
+               crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2);
+               entry = (void *)entry + (entry_len + 1) * 2;
+       }
+
+       wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n");
+       err = -ENODATA;
+       goto err;
+
+good_eeprom:
+       if (!synth || !priv->iq_autocal || !priv->output_limit ||
+           !priv->curve_data) {
+               wiphy_err(dev->wiphy,
+                         "not all required entries found in eeprom!\n");
+               err = -EINVAL;
+               goto err;
+       }
+
+       priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
+
+       err = p54_generate_channel_lists(dev);
+       if (err)
+               goto err;
+
+       if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
+               p54_init_xbow_synth(priv);
+       if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
+               dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       priv->band_table[IEEE80211_BAND_2GHZ];
+       if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
+               dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       priv->band_table[IEEE80211_BAND_5GHZ];
+       if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
+               priv->rx_diversity_mask = 3;
+       if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
+               priv->tx_diversity_mask = 3;
+
+       if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
+               u8 perm_addr[ETH_ALEN];
+
+               wiphy_warn(dev->wiphy,
+                          "Invalid hwaddr! Using randomly generated MAC addr\n");
+               eth_random_addr(perm_addr);
+               SET_IEEE80211_PERM_ADDR(dev, perm_addr);
+       }
+
+       priv->cur_rssi = &p54_rssi_default;
+
+       wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n",
+                  dev->wiphy->perm_addr, priv->version,
+                  p54_rf_chips[priv->rxhw]);
+
+       return 0;
+
+err:
+       kfree(priv->iq_autocal);
+       kfree(priv->output_limit);
+       kfree(priv->curve_data);
+       kfree(priv->rssi_db);
+       kfree(priv->survey);
+       priv->iq_autocal = NULL;
+       priv->output_limit = NULL;
+       priv->curve_data = NULL;
+       priv->rssi_db = NULL;
+       priv->survey = NULL;
+
+       wiphy_err(dev->wiphy, "eeprom parse failed!\n");
+       return err;
+}
+EXPORT_SYMBOL_GPL(p54_parse_eeprom);
+
+int p54_read_eeprom(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
+       int ret = -ENOMEM;
+       void *eeprom;
+
+       maxblocksize = EEPROM_READBACK_LEN;
+       if (priv->fw_var >= 0x509)
+               maxblocksize -= 0xc;
+       else
+               maxblocksize -= 0x4;
+
+       eeprom = kzalloc(eeprom_size, GFP_KERNEL);
+       if (unlikely(!eeprom))
+               goto free;
+
+       while (eeprom_size) {
+               blocksize = min(eeprom_size, maxblocksize);
+               ret = p54_download_eeprom(priv, eeprom + offset,
+                                         offset, blocksize);
+               if (unlikely(ret))
+                       goto free;
+
+               offset += blocksize;
+               eeprom_size -= blocksize;
+       }
+
+       ret = p54_parse_eeprom(dev, eeprom, offset);
+free:
+       kfree(eeprom);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(p54_read_eeprom);
diff --git a/drivers/net/wireless/intersil/p54/eeprom.h b/drivers/net/wireless/intersil/p54/eeprom.h
new file mode 100644 (file)
index 0000000..20ebe39
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * eeprom specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ *   Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * - islmvc driver
+ *   Copyright (C) 2001 Intersil Americas Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef EEPROM_H
+#define EEPROM_H
+
+/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
+
+struct pda_entry {
+       __le16 len;     /* includes both code and data */
+       __le16 code;
+       u8 data[0];
+} __packed;
+
+struct eeprom_pda_wrap {
+       __le32 magic;
+       __le16 pad;
+       __le16 len;
+       __le32 arm_opcode;
+       u8 data[0];
+} __packed;
+
+struct p54_iq_autocal_entry {
+       __le16 iq_param[4];
+} __packed;
+
+struct pda_iq_autocal_entry {
+       __le16 freq;
+       struct p54_iq_autocal_entry params;
+} __packed;
+
+struct pda_channel_output_limit {
+       __le16 freq;
+       u8 val_bpsk;
+       u8 val_qpsk;
+       u8 val_16qam;
+       u8 val_64qam;
+       u8 rate_set_mask;
+       u8 rate_set_size;
+} __packed;
+
+struct pda_channel_output_limit_point_longbow {
+       __le16 val_bpsk;
+       __le16 val_qpsk;
+       __le16 val_16qam;
+       __le16 val_64qam;
+} __packed;
+
+struct pda_channel_output_limit_longbow {
+       __le16 freq;
+       struct pda_channel_output_limit_point_longbow point[3];
+} __packed;
+
+struct pda_pa_curve_data_sample_rev0 {
+       u8 rf_power;
+       u8 pa_detector;
+       u8 pcv;
+} __packed;
+
+struct pda_pa_curve_data_sample_rev1 {
+       u8 rf_power;
+       u8 pa_detector;
+       u8 data_barker;
+       u8 data_bpsk;
+       u8 data_qpsk;
+       u8 data_16qam;
+       u8 data_64qam;
+} __packed;
+
+struct pda_pa_curve_data {
+       u8 cal_method_rev;
+       u8 channels;
+       u8 points_per_channel;
+       u8 padding;
+       u8 data[0];
+} __packed;
+
+struct pda_rssi_cal_ext_entry {
+       __le16 freq;
+       __le16 mul;
+       __le16 add;
+} __packed;
+
+struct pda_rssi_cal_entry {
+       __le16 mul;
+       __le16 add;
+} __packed;
+
+struct pda_country {
+       u8 regdomain;
+       u8 alpha2[2];
+       u8 flags;
+} __packed;
+
+struct pda_antenna_gain {
+       struct {
+               u8 gain_5GHz;   /* 0.25 dBi units */
+               u8 gain_2GHz;   /* 0.25 dBi units */
+       } __packed antenna[0];
+} __packed;
+
+struct pda_custom_wrapper {
+       __le16 entries;
+       __le16 entry_size;
+       __le16 offset;
+       __le16 len;
+       u8 data[0];
+} __packed;
+
+/*
+ * this defines the PDR codes used to build PDAs as defined in document
+ * number 553155. The current implementation mirrors version 1.1 of the
+ * document and lists only PDRs supported by the ARM platform.
+ */
+
+/* common and choice range (0x0000 - 0x0fff) */
+#define PDR_END                                        0x0000
+#define PDR_MANUFACTURING_PART_NUMBER          0x0001
+#define PDR_PDA_VERSION                                0x0002
+#define PDR_NIC_SERIAL_NUMBER                  0x0003
+#define PDR_NIC_RAM_SIZE                       0x0005
+#define PDR_RFMODEM_SUP_RANGE                  0x0006
+#define PDR_PRISM_MAC_SUP_RANGE                        0x0007
+#define PDR_NIC_ID                             0x0008
+
+#define PDR_MAC_ADDRESS                                0x0101
+#define PDR_REGULATORY_DOMAIN_LIST             0x0103 /* obsolete */
+#define PDR_ALLOWED_CHAN_SET                   0x0104
+#define PDR_DEFAULT_CHAN                       0x0105
+#define PDR_TEMPERATURE_TYPE                   0x0107
+
+#define PDR_IFR_SETTING                                0x0200
+#define PDR_RFR_SETTING                                0x0201
+#define PDR_3861_BASELINE_REG_SETTINGS         0x0202
+#define PDR_3861_SHADOW_REG_SETTINGS           0x0203
+#define PDR_3861_IFRF_REG_SETTINGS             0x0204
+
+#define PDR_3861_CHAN_CALIB_SET_POINTS         0x0300
+#define PDR_3861_CHAN_CALIB_INTEGRATOR         0x0301
+
+#define PDR_3842_PRISM_II_NIC_CONFIG           0x0400
+#define PDR_PRISM_USB_ID                       0x0401
+#define PDR_PRISM_PCI_ID                       0x0402
+#define PDR_PRISM_PCI_IF_CONFIG                        0x0403
+#define PDR_PRISM_PCI_PM_CONFIG                        0x0404
+
+#define PDR_3861_MF_TEST_CHAN_SET_POINTS       0x0900
+#define PDR_3861_MF_TEST_CHAN_INTEGRATORS      0x0901
+
+/* ARM range (0x1000 - 0x1fff) */
+#define PDR_COUNTRY_INFORMATION                        0x1000 /* obsolete */
+#define PDR_INTERFACE_LIST                     0x1001
+#define PDR_HARDWARE_PLATFORM_COMPONENT_ID     0x1002
+#define PDR_OEM_NAME                           0x1003
+#define PDR_PRODUCT_NAME                       0x1004
+#define PDR_UTF8_OEM_NAME                      0x1005
+#define PDR_UTF8_PRODUCT_NAME                  0x1006
+#define PDR_COUNTRY_LIST                       0x1007
+#define PDR_DEFAULT_COUNTRY                    0x1008
+
+#define PDR_ANTENNA_GAIN                       0x1100
+
+#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA   0x1901
+#define PDR_RSSI_LINEAR_APPROXIMATION          0x1902
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS   0x1903
+#define PDR_PRISM_PA_CAL_CURVE_DATA            0x1904
+#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND        0x1905
+#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION                0x1906
+#define PDR_REGULATORY_POWER_LIMITS            0x1907
+#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
+#define PDR_RADIATED_TRANSMISSION_CORRECTION   0x1909
+#define PDR_PRISM_TX_IQ_CALIBRATION            0x190a
+
+/* reserved range (0x2000 - 0x7fff) */
+
+/* customer range (0x8000 - 0xffff) */
+#define PDR_BASEBAND_REGISTERS                         0x8000
+#define PDR_PER_CHANNEL_BASEBAND_REGISTERS             0x8001
+
+/* used by our modificated eeprom image */
+#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM           0xDEAD
+#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2         0xCAFF
+#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM    0xBEEF
+#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM             0xB05D
+
+/* Interface Definitions */
+#define PDR_INTERFACE_ROLE_SERVER      0x0000
+#define PDR_INTERFACE_ROLE_CLIENT      0x0001
+
+/* PDR definitions for default country & country list */
+#define PDR_COUNTRY_CERT_CODE          0x80
+#define PDR_COUNTRY_CERT_CODE_REAL     0x00
+#define PDR_COUNTRY_CERT_CODE_PSEUDO   0x80
+#define PDR_COUNTRY_CERT_BAND          0x40
+#define PDR_COUNTRY_CERT_BAND_2GHZ     0x00
+#define PDR_COUNTRY_CERT_BAND_5GHZ     0x40
+#define PDR_COUNTRY_CERT_IODOOR                0x30
+#define PDR_COUNTRY_CERT_IODOOR_BOTH   0x00
+#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
+#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR        0x30
+#define PDR_COUNTRY_CERT_INDEX         0x0f
+
+/* Specific LMAC FW/HW variant definitions */
+#define PDR_SYNTH_FRONTEND_MASK                0x0007
+#define PDR_SYNTH_FRONTEND_DUETTE3     0x0001
+#define PDR_SYNTH_FRONTEND_DUETTE2     0x0002
+#define PDR_SYNTH_FRONTEND_FRISBEE     0x0003
+#define PDR_SYNTH_FRONTEND_XBOW                0x0004
+#define PDR_SYNTH_FRONTEND_LONGBOW     0x0005
+#define PDR_SYNTH_IQ_CAL_MASK          0x0018
+#define PDR_SYNTH_IQ_CAL_PA_DETECTOR   0x0000
+#define PDR_SYNTH_IQ_CAL_DISABLED      0x0008
+#define PDR_SYNTH_IQ_CAL_ZIF           0x0010
+#define PDR_SYNTH_FAA_SWITCH_MASK      0x0020
+#define PDR_SYNTH_FAA_SWITCH_ENABLED   0x0020
+#define PDR_SYNTH_24_GHZ_MASK          0x0040
+#define PDR_SYNTH_24_GHZ_DISABLED      0x0040
+#define PDR_SYNTH_5_GHZ_MASK           0x0080
+#define PDR_SYNTH_5_GHZ_DISABLED       0x0080
+#define PDR_SYNTH_RX_DIV_MASK          0x0100
+#define PDR_SYNTH_RX_DIV_SUPPORTED     0x0100
+#define PDR_SYNTH_TX_DIV_MASK          0x0200
+#define PDR_SYNTH_TX_DIV_SUPPORTED     0x0200
+#define PDR_SYNTH_ASM_MASK             0x0400
+#define PDR_SYNTH_ASM_XSWON            0x0400
+
+#endif /* EEPROM_H */
diff --git a/drivers/net/wireless/intersil/p54/fwio.c b/drivers/net/wireless/intersil/p54/fwio.c
new file mode 100644 (file)
index 0000000..257a9ea
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ * Firmware I/O code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/export.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "eeprom.h"
+#include "lmac.h"
+
+int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
+{
+       struct p54_common *priv = dev->priv;
+       struct exp_if *exp_if;
+       struct bootrec *bootrec;
+       u32 *data = (u32 *)fw->data;
+       u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
+       u8 *fw_version = NULL;
+       size_t len;
+       int i;
+       int maxlen;
+
+       if (priv->rx_start)
+               return 0;
+
+       while (data < end_data && *data)
+               data++;
+
+       while (data < end_data && !*data)
+               data++;
+
+       bootrec = (struct bootrec *) data;
+
+       while (bootrec->data <= end_data && (bootrec->data +
+              (len = le32_to_cpu(bootrec->len))) <= end_data) {
+               u32 code = le32_to_cpu(bootrec->code);
+               switch (code) {
+               case BR_CODE_COMPONENT_ID:
+                       priv->fw_interface = be32_to_cpup((__be32 *)
+                                            bootrec->data);
+                       switch (priv->fw_interface) {
+                       case FW_LM86:
+                       case FW_LM20:
+                       case FW_LM87: {
+                               char *iftype = (char *)bootrec->data;
+                               wiphy_info(priv->hw->wiphy,
+                                          "p54 detected a LM%c%c firmware\n",
+                                          iftype[2], iftype[3]);
+                               break;
+                               }
+                       case FW_FMAC:
+                       default:
+                               wiphy_err(priv->hw->wiphy,
+                                         "unsupported firmware\n");
+                               return -ENODEV;
+                       }
+                       break;
+               case BR_CODE_COMPONENT_VERSION:
+                       /* 24 bytes should be enough for all firmwares */
+                       if (strnlen((unsigned char *) bootrec->data, 24) < 24)
+                               fw_version = (unsigned char *) bootrec->data;
+                       break;
+               case BR_CODE_DESCR: {
+                       struct bootrec_desc *desc =
+                               (struct bootrec_desc *)bootrec->data;
+                       priv->rx_start = le32_to_cpu(desc->rx_start);
+                       /* FIXME add sanity checking */
+                       priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
+                       priv->headroom = desc->headroom;
+                       priv->tailroom = desc->tailroom;
+                       priv->privacy_caps = desc->privacy_caps;
+                       priv->rx_keycache_size = desc->rx_keycache_size;
+                       if (le32_to_cpu(bootrec->len) == 11)
+                               priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
+                       else
+                               priv->rx_mtu = (size_t)
+                                       0x620 - priv->tx_hdr_len;
+                       maxlen = priv->tx_hdr_len + /* USB devices */
+                                sizeof(struct p54_rx_data) +
+                                4 + /* rx alignment */
+                                IEEE80211_MAX_FRAG_THRESHOLD;
+                       if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
+                               printk(KERN_INFO "p54: rx_mtu reduced from %d "
+                                      "to %d\n", priv->rx_mtu, maxlen);
+                               priv->rx_mtu = maxlen;
+                       }
+                       break;
+                       }
+               case BR_CODE_EXPOSED_IF:
+                       exp_if = (struct exp_if *) bootrec->data;
+                       for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
+                               if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC))
+                                       priv->fw_var = le16_to_cpu(exp_if[i].variant);
+                       break;
+               case BR_CODE_DEPENDENT_IF:
+                       break;
+               case BR_CODE_END_OF_BRA:
+               case LEGACY_BR_CODE_END_OF_BRA:
+                       end_data = NULL;
+                       break;
+               default:
+                       break;
+               }
+               bootrec = (struct bootrec *)&bootrec->data[len];
+       }
+
+       if (fw_version) {
+               wiphy_info(priv->hw->wiphy,
+                          "FW rev %s - Softmac protocol %x.%x\n",
+                          fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
+               snprintf(dev->wiphy->fw_version, sizeof(dev->wiphy->fw_version),
+                               "%s - %x.%x", fw_version,
+                               priv->fw_var >> 8, priv->fw_var & 0xff);
+       }
+
+       if (priv->fw_var < 0x500)
+               wiphy_info(priv->hw->wiphy,
+                          "you are using an obsolete firmware. "
+                          "visit http://wireless.kernel.org/en/users/Drivers/p54 "
+                          "and grab one for \"kernel >= 2.6.28\"!\n");
+
+       if (priv->fw_var >= 0x300) {
+               /* Firmware supports QoS, use it! */
+
+               if (priv->fw_var >= 0x500) {
+                       priv->tx_stats[P54_QUEUE_AC_VO].limit = 16;
+                       priv->tx_stats[P54_QUEUE_AC_VI].limit = 16;
+                       priv->tx_stats[P54_QUEUE_AC_BE].limit = 16;
+                       priv->tx_stats[P54_QUEUE_AC_BK].limit = 16;
+               } else {
+                       priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
+                       priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
+                       priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
+                       priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
+               }
+               priv->hw->queues = P54_QUEUE_AC_NUM;
+       }
+
+       wiphy_info(priv->hw->wiphy,
+                  "cryptographic accelerator WEP:%s, TKIP:%s, CCMP:%s\n",
+                  (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : "no",
+                  (priv->privacy_caps &
+                   (BR_DESC_PRIV_CAP_TKIP | BR_DESC_PRIV_CAP_MICHAEL))
+                  ? "YES" : "no",
+                  (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)
+                  ? "YES" : "no");
+
+       if (priv->rx_keycache_size) {
+               /*
+                * NOTE:
+                *
+                * The firmware provides at most 255 (0 - 254) slots
+                * for keys which are then used to offload decryption.
+                * As a result the 255 entry (aka 0xff) can be used
+                * safely by the driver to mark keys that didn't fit
+                * into the full cache. This trick saves us from
+                * keeping a extra list for uploaded keys.
+                */
+
+               priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
+                       priv->rx_keycache_size), GFP_KERNEL);
+
+               if (!priv->used_rxkeys)
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(p54_parse_firmware);
+
+static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags,
+                                    u16 payload_len, u16 type, gfp_t memflags)
+{
+       struct p54_hdr *hdr;
+       struct sk_buff *skb;
+       size_t frame_len = sizeof(*hdr) + payload_len;
+
+       if (frame_len > P54_MAX_CTRL_FRAME_LEN)
+               return NULL;
+
+       if (unlikely(skb_queue_len(&priv->tx_pending) > 64))
+               return NULL;
+
+       skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
+       if (!skb)
+               return NULL;
+       skb_reserve(skb, priv->tx_hdr_len);
+
+       hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
+       hdr->flags = cpu_to_le16(hdr_flags);
+       hdr->len = cpu_to_le16(payload_len);
+       hdr->type = cpu_to_le16(type);
+       hdr->tries = hdr->rts_tries = 0;
+       return skb;
+}
+
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+                       u16 offset, u16 len)
+{
+       struct p54_eeprom_lm86 *eeprom_hdr;
+       struct sk_buff *skb;
+       size_t eeprom_hdr_size;
+       int ret = 0;
+       long timeout;
+
+       if (priv->fw_var >= 0x509)
+               eeprom_hdr_size = sizeof(*eeprom_hdr);
+       else
+               eeprom_hdr_size = 0x4;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size +
+                           len, P54_CONTROL_TYPE_EEPROM_READBACK,
+                           GFP_KERNEL);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       mutex_lock(&priv->eeprom_mutex);
+       priv->eeprom = buf;
+       eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
+               eeprom_hdr_size + len);
+
+       if (priv->fw_var < 0x509) {
+               eeprom_hdr->v1.offset = cpu_to_le16(offset);
+               eeprom_hdr->v1.len = cpu_to_le16(len);
+       } else {
+               eeprom_hdr->v2.offset = cpu_to_le32(offset);
+               eeprom_hdr->v2.len = cpu_to_le16(len);
+               eeprom_hdr->v2.magic2 = 0xf;
+               memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
+       }
+
+       p54_tx(priv, skb);
+
+       timeout = wait_for_completion_interruptible_timeout(
+                       &priv->eeprom_comp, HZ);
+       if (timeout <= 0) {
+               wiphy_err(priv->hw->wiphy,
+                       "device does not respond or signal received!\n");
+               ret = -EBUSY;
+       }
+       priv->eeprom = NULL;
+       mutex_unlock(&priv->eeprom_mutex);
+       return ret;
+}
+
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set)
+{
+       struct sk_buff *skb;
+       struct p54_tim *tim;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
+                           P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
+       tim->count = 1;
+       tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid);
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_sta_unlock(struct p54_common *priv, u8 *addr)
+{
+       struct sk_buff *skb;
+       struct p54_sta_unlock *sta;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
+                           P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
+       memcpy(sta->addr, addr, ETH_ALEN);
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id)
+{
+       struct sk_buff *skb;
+       struct p54_txcancel *cancel;
+       u32 _req_id = le32_to_cpu(req_id);
+
+       if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end))
+               return -EINVAL;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
+                           P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
+       cancel->req_id = req_id;
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_setup_mac(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_setup_mac *setup;
+       u16 mode;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
+                           P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
+       if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) {
+               switch (priv->mode) {
+               case NL80211_IFTYPE_STATION:
+                       mode = P54_FILTER_TYPE_STATION;
+                       break;
+               case NL80211_IFTYPE_AP:
+                       mode = P54_FILTER_TYPE_AP;
+                       break;
+               case NL80211_IFTYPE_ADHOC:
+               case NL80211_IFTYPE_MESH_POINT:
+                       mode = P54_FILTER_TYPE_IBSS;
+                       break;
+               case NL80211_IFTYPE_MONITOR:
+                       mode = P54_FILTER_TYPE_PROMISCUOUS;
+                       break;
+               default:
+                       mode = P54_FILTER_TYPE_HIBERNATE;
+                       break;
+               }
+
+               /*
+                * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
+                * STSW45X0C LMAC API - page 12
+                */
+               if (priv->filter_flags & FIF_OTHER_BSS &&
+                   (mode != P54_FILTER_TYPE_PROMISCUOUS))
+                       mode |= P54_FILTER_TYPE_TRANSPARENT;
+       } else {
+               mode = P54_FILTER_TYPE_HIBERNATE;
+       }
+
+       setup->mac_mode = cpu_to_le16(mode);
+       memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
+       memcpy(setup->bssid, priv->bssid, ETH_ALEN);
+       setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
+       setup->rx_align = 0;
+       if (priv->fw_var < 0x500) {
+               setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+               memset(setup->v1.rts_rates, 0, 8);
+               setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
+               setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
+               setup->v1.rxhw = cpu_to_le16(priv->rxhw);
+               setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
+               setup->v1.unalloc0 = cpu_to_le16(0);
+       } else {
+               setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
+               setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
+               setup->v2.rxhw = cpu_to_le16(priv->rxhw);
+               setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
+               setup->v2.truncate = cpu_to_le16(48896);
+               setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+               setup->v2.sbss_offset = 0;
+               setup->v2.mcast_window = 0;
+               setup->v2.rx_rssi_threshold = 0;
+               setup->v2.rx_ed_threshold = 0;
+               setup->v2.ref_clock = cpu_to_le32(644245094);
+               setup->v2.lpf_bandwidth = cpu_to_le16(65535);
+               setup->v2.osc_start_delay = cpu_to_le16(65535);
+       }
+       p54_tx(priv, skb);
+       priv->phy_idle = mode == P54_FILTER_TYPE_HIBERNATE;
+       return 0;
+}
+
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
+{
+       struct sk_buff *skb;
+       struct p54_hdr *hdr;
+       struct p54_scan_head *head;
+       struct p54_iq_autocal_entry *iq_autocal;
+       union p54_scan_body_union *body;
+       struct p54_scan_tail_rate *rate;
+       struct pda_rssi_cal_entry *rssi;
+       struct p54_rssi_db_entry *rssi_data;
+       unsigned int i;
+       void *entry;
+       __le16 freq = cpu_to_le16(priv->hw->conf.chandef.chan->center_freq);
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
+                           2 + sizeof(*iq_autocal) + sizeof(*body) +
+                           sizeof(*rate) + 2 * sizeof(*rssi),
+                           P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
+       memset(head->scan_params, 0, sizeof(head->scan_params));
+       head->mode = cpu_to_le16(mode);
+       head->dwell = cpu_to_le16(dwell);
+       head->freq = freq;
+
+       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+               __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
+               *pa_power_points = cpu_to_le16(0x0c);
+       }
+
+       iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
+       for (i = 0; i < priv->iq_autocal_len; i++) {
+               if (priv->iq_autocal[i].freq != freq)
+                       continue;
+
+               memcpy(iq_autocal, &priv->iq_autocal[i].params,
+                      sizeof(struct p54_iq_autocal_entry));
+               break;
+       }
+       if (i == priv->iq_autocal_len)
+               goto err;
+
+       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
+               body = (void *) skb_put(skb, sizeof(body->longbow));
+       else
+               body = (void *) skb_put(skb, sizeof(body->normal));
+
+       for (i = 0; i < priv->output_limit->entries; i++) {
+               __le16 *entry_freq = (void *) (priv->output_limit->data +
+                                    priv->output_limit->entry_size * i);
+
+               if (*entry_freq != freq)
+                       continue;
+
+               if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+                       memcpy(&body->longbow.power_limits,
+                              (void *) entry_freq + sizeof(__le16),
+                              priv->output_limit->entry_size);
+               } else {
+                       struct pda_channel_output_limit *limits =
+                              (void *) entry_freq;
+
+                       body->normal.val_barker = 0x38;
+                       body->normal.val_bpsk = body->normal.dup_bpsk =
+                               limits->val_bpsk;
+                       body->normal.val_qpsk = body->normal.dup_qpsk =
+                               limits->val_qpsk;
+                       body->normal.val_16qam = body->normal.dup_16qam =
+                               limits->val_16qam;
+                       body->normal.val_64qam = body->normal.dup_64qam =
+                               limits->val_64qam;
+               }
+               break;
+       }
+       if (i == priv->output_limit->entries)
+               goto err;
+
+       entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
+       for (i = 0; i < priv->curve_data->entries; i++) {
+               if (*((__le16 *)entry) != freq) {
+                       entry += priv->curve_data->entry_size;
+                       continue;
+               }
+
+               if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+                       memcpy(&body->longbow.curve_data,
+                               entry + sizeof(__le16),
+                               priv->curve_data->entry_size);
+               } else {
+                       struct p54_scan_body *chan = &body->normal;
+                       struct pda_pa_curve_data *curve_data =
+                               (void *) priv->curve_data->data;
+
+                       entry += sizeof(__le16);
+                       chan->pa_points_per_curve = 8;
+                       memset(chan->curve_data, 0, sizeof(*chan->curve_data));
+                       memcpy(chan->curve_data, entry,
+                              sizeof(struct p54_pa_curve_data_sample) *
+                              min((u8)8, curve_data->points_per_channel));
+               }
+               break;
+       }
+       if (i == priv->curve_data->entries)
+               goto err;
+
+       if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
+               rate = (void *) skb_put(skb, sizeof(*rate));
+               rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+               for (i = 0; i < sizeof(rate->rts_rates); i++)
+                       rate->rts_rates[i] = i;
+       }
+
+       rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
+       rssi_data = p54_rssi_find(priv, le16_to_cpu(freq));
+       rssi->mul = cpu_to_le16(rssi_data->mul);
+       rssi->add = cpu_to_le16(rssi_data->add);
+       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
+               /* Longbow frontend needs ever more */
+               rssi = (void *) skb_put(skb, sizeof(*rssi));
+               rssi->mul = cpu_to_le16(rssi_data->longbow_unkn);
+               rssi->add = cpu_to_le16(rssi_data->longbow_unk2);
+       }
+
+       if (priv->fw_var >= 0x509) {
+               rate = (void *) skb_put(skb, sizeof(*rate));
+               rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
+               for (i = 0; i < sizeof(rate->rts_rates); i++)
+                       rate->rts_rates[i] = i;
+       }
+
+       hdr = (struct p54_hdr *) skb->data;
+       hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
+
+       p54_tx(priv, skb);
+       priv->cur_rssi = rssi_data;
+       return 0;
+
+err:
+       wiphy_err(priv->hw->wiphy, "frequency change to channel %d failed.\n",
+                 ieee80211_frequency_to_channel(
+                         priv->hw->conf.chandef.chan->center_freq));
+
+       dev_kfree_skb_any(skb);
+       return -EINVAL;
+}
+
+int p54_set_leds(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_led *led;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
+                           P54_CONTROL_TYPE_LED, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       led = (struct p54_led *) skb_put(skb, sizeof(*led));
+       led->flags = cpu_to_le16(0x0003);
+       led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
+       led->delay[0] = cpu_to_le16(1);
+       led->delay[1] = cpu_to_le16(0);
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_set_edcf(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_edcf *edcf;
+       u8 rtd;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
+                           P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
+       if (priv->use_short_slot) {
+               edcf->slottime = 9;
+               edcf->sifs = 0x10;
+               edcf->eofpad = 0x00;
+       } else {
+               edcf->slottime = 20;
+               edcf->sifs = 0x0a;
+               edcf->eofpad = 0x06;
+       }
+       /*
+        * calculate the extra round trip delay according to the
+        * formula from 802.11-2007 17.3.8.6.
+        */
+       rtd = 3 * priv->coverage_class;
+       edcf->slottime += rtd;
+       edcf->round_trip_delay = cpu_to_le16(rtd);
+       /* (see prism54/isl_oid.h for further details) */
+       edcf->frameburst = cpu_to_le16(0);
+       edcf->flags = 0;
+       memset(edcf->mapping, 0, sizeof(edcf->mapping));
+       memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_set_ps(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_psm *psm;
+       unsigned int i;
+       u16 mode;
+
+       if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
+           !priv->powersave_override)
+               mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
+                      P54_PSM_CHECKSUM | P54_PSM_MCBC;
+       else
+               mode = P54_PSM_CAM;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
+                           P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
+       psm->mode = cpu_to_le16(mode);
+       psm->aid = cpu_to_le16(priv->aid);
+       for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
+               psm->intervals[i].interval =
+                       cpu_to_le16(priv->hw->conf.listen_interval);
+               psm->intervals[i].periods = cpu_to_le16(1);
+       }
+
+       psm->beacon_rssi_skip_max = 200;
+       psm->rssi_delta_threshold = 0;
+       psm->nr = 1;
+       psm->exclude[0] = WLAN_EID_TIM;
+
+       p54_tx(priv, skb);
+       priv->phy_ps = mode != P54_PSM_CAM;
+       return 0;
+}
+
+int p54_init_xbow_synth(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       struct p54_xbow_synth *xbow;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
+                           P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
+       xbow->magic1 = cpu_to_le16(0x1);
+       xbow->magic2 = cpu_to_le16(0x2);
+       xbow->freq = cpu_to_le16(5390);
+       memset(xbow->padding, 0, sizeof(xbow->padding));
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
+                  u8 *addr, u8* key)
+{
+       struct sk_buff *skb;
+       struct p54_keycache *rxkey;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
+                           P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
+       if (unlikely(!skb))
+               return -ENOMEM;
+
+       rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
+       rxkey->entry = slot;
+       rxkey->key_id = idx;
+       rxkey->key_type = algo;
+       if (addr)
+               memcpy(rxkey->mac, addr, ETH_ALEN);
+       else
+               eth_broadcast_addr(rxkey->mac);
+
+       switch (algo) {
+       case P54_CRYPTO_WEP:
+       case P54_CRYPTO_AESCCMP:
+               rxkey->key_len = min_t(u8, 16, len);
+               memcpy(rxkey->key, key, rxkey->key_len);
+               break;
+
+       case P54_CRYPTO_TKIPMICHAEL:
+               rxkey->key_len = 24;
+               memcpy(rxkey->key, key, 16);
+               memcpy(&(rxkey->key[16]), &(key
+                       [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
+               break;
+
+       case P54_CRYPTO_NONE:
+               rxkey->key_len = 0;
+               memset(rxkey->key, 0, sizeof(rxkey->key));
+               break;
+
+       default:
+               wiphy_err(priv->hw->wiphy,
+                         "invalid cryptographic algorithm: %d\n", algo);
+               dev_kfree_skb(skb);
+               return -EINVAL;
+       }
+
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_fetch_statistics(struct p54_common *priv)
+{
+       struct ieee80211_tx_info *txinfo;
+       struct p54_tx_info *p54info;
+       struct sk_buff *skb;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
+                           sizeof(struct p54_statistics),
+                           P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       /*
+        * The statistic feedback causes some extra headaches here, if it
+        * is not to crash/corrupt the firmware data structures.
+        *
+        * Unlike all other Control Get OIDs we can not use helpers like
+        * skb_put to reserve the space for the data we're requesting.
+        * Instead the extra frame length -which will hold the results later-
+        * will only be told to the p54_assign_address, so that following
+        * frames won't be placed into the  allegedly empty area.
+        */
+       txinfo = IEEE80211_SKB_CB(skb);
+       p54info = (void *) txinfo->rate_driver_data;
+       p54info->extra_len = sizeof(struct p54_statistics);
+
+       p54_tx(priv, skb);
+       return 0;
+}
+
+int p54_set_groupfilter(struct p54_common *priv)
+{
+       struct p54_group_address_table *grp;
+       struct sk_buff *skb;
+       bool on = false;
+
+       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp),
+                           P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp));
+
+       on = !(priv->filter_flags & FIF_ALLMULTI) &&
+            (priv->mc_maclist_num > 0 &&
+             priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM);
+
+       if (on) {
+               grp->filter_enable = cpu_to_le16(1);
+               grp->num_address = cpu_to_le16(priv->mc_maclist_num);
+               memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list));
+       } else {
+               grp->filter_enable = cpu_to_le16(0);
+               grp->num_address = cpu_to_le16(0);
+               memset(grp->mac_list, 0, sizeof(grp->mac_list));
+       }
+
+       p54_tx(priv, skb);
+       return 0;
+}
diff --git a/drivers/net/wireless/intersil/p54/led.c b/drivers/net/wireless/intersil/p54/led.c
new file mode 100644 (file)
index 0000000..9a8fedd
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+
+#include <net/mac80211.h>
+#ifdef CONFIG_P54_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_P54_LEDS */
+
+#include "p54.h"
+#include "lmac.h"
+
+static void p54_update_leds(struct work_struct *work)
+{
+       struct p54_common *priv = container_of(work, struct p54_common,
+                                              led_work.work);
+       int err, i, tmp, blink_delay = 400;
+       bool rerun = false;
+
+       /* Don't toggle the LED, when the device is down. */
+       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+               return ;
+
+       for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
+               if (priv->leds[i].toggled) {
+                       priv->softled_state |= BIT(i);
+
+                       tmp = 70 + 200 / (priv->leds[i].toggled);
+                       if (tmp < blink_delay)
+                               blink_delay = tmp;
+
+                       if (priv->leds[i].led_dev.brightness == LED_OFF)
+                               rerun = true;
+
+                       priv->leds[i].toggled =
+                               !!priv->leds[i].led_dev.brightness;
+               } else
+                       priv->softled_state &= ~BIT(i);
+
+       err = p54_set_leds(priv);
+       if (err && net_ratelimit())
+               wiphy_err(priv->hw->wiphy,
+                         "failed to update LEDs (%d).\n", err);
+
+       if (rerun)
+               ieee80211_queue_delayed_work(priv->hw, &priv->led_work,
+                       msecs_to_jiffies(blink_delay));
+}
+
+static void p54_led_brightness_set(struct led_classdev *led_dev,
+                                  enum led_brightness brightness)
+{
+       struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
+                                              led_dev);
+       struct ieee80211_hw *dev = led->hw_dev;
+       struct p54_common *priv = dev->priv;
+
+       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+               return ;
+
+       if ((brightness) && (led->registered)) {
+               led->toggled++;
+               ieee80211_queue_delayed_work(priv->hw, &priv->led_work, HZ/10);
+       }
+}
+
+static int p54_register_led(struct p54_common *priv,
+                           unsigned int led_index,
+                           char *name, const char *trigger)
+{
+       struct p54_led_dev *led = &priv->leds[led_index];
+       int err;
+
+       if (led->registered)
+               return -EEXIST;
+
+       snprintf(led->name, sizeof(led->name), "p54-%s::%s",
+                wiphy_name(priv->hw->wiphy), name);
+       led->hw_dev = priv->hw;
+       led->index = led_index;
+       led->led_dev.name = led->name;
+       led->led_dev.default_trigger = trigger;
+       led->led_dev.brightness_set = p54_led_brightness_set;
+
+       err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev);
+       if (err)
+               wiphy_err(priv->hw->wiphy,
+                         "Failed to register %s LED.\n", name);
+       else
+               led->registered = 1;
+
+       return err;
+}
+
+int p54_init_leds(struct p54_common *priv)
+{
+       int err;
+
+       /*
+        * TODO:
+        * Figure out if the EEPROM contains some hints about the number
+        * of available/programmable LEDs of the device.
+        */
+
+       INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
+
+       err = p54_register_led(priv, 0, "assoc",
+                              ieee80211_get_assoc_led_name(priv->hw));
+       if (err)
+               return err;
+
+       err = p54_register_led(priv, 1, "tx",
+                              ieee80211_get_tx_led_name(priv->hw));
+       if (err)
+               return err;
+
+       err = p54_register_led(priv, 2, "rx",
+                              ieee80211_get_rx_led_name(priv->hw));
+       if (err)
+               return err;
+
+       err = p54_register_led(priv, 3, "radio",
+                              ieee80211_get_radio_led_name(priv->hw));
+       if (err)
+               return err;
+
+       err = p54_set_leds(priv);
+       return err;
+}
+
+void p54_unregister_leds(struct p54_common *priv)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(priv->leds); i++) {
+               if (priv->leds[i].registered) {
+                       priv->leds[i].registered = false;
+                       priv->leds[i].toggled = 0;
+                       led_classdev_unregister(&priv->leds[i].led_dev);
+               }
+       }
+
+       cancel_delayed_work_sync(&priv->led_work);
+}
diff --git a/drivers/net/wireless/intersil/p54/lmac.h b/drivers/net/wireless/intersil/p54/lmac.h
new file mode 100644 (file)
index 0000000..de1d46b
--- /dev/null
@@ -0,0 +1,562 @@
+/*
+ * LMAC Interface specific definitions for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007 - 2009, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
+ *   Copyright (C) 2007 Conexant Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef LMAC_H
+#define LMAC_H
+
+enum p54_control_frame_types {
+       P54_CONTROL_TYPE_SETUP = 0,
+       P54_CONTROL_TYPE_SCAN,
+       P54_CONTROL_TYPE_TRAP,
+       P54_CONTROL_TYPE_DCFINIT,
+       P54_CONTROL_TYPE_RX_KEYCACHE,
+       P54_CONTROL_TYPE_TIM,
+       P54_CONTROL_TYPE_PSM,
+       P54_CONTROL_TYPE_TXCANCEL,
+       P54_CONTROL_TYPE_TXDONE,
+       P54_CONTROL_TYPE_BURST,
+       P54_CONTROL_TYPE_STAT_READBACK,
+       P54_CONTROL_TYPE_BBP,
+       P54_CONTROL_TYPE_EEPROM_READBACK,
+       P54_CONTROL_TYPE_LED,
+       P54_CONTROL_TYPE_GPIO,
+       P54_CONTROL_TYPE_TIMER,
+       P54_CONTROL_TYPE_MODULATION,
+       P54_CONTROL_TYPE_SYNTH_CONFIG,
+       P54_CONTROL_TYPE_DETECTOR_VALUE,
+       P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
+       P54_CONTROL_TYPE_CCE_QUIET,
+       P54_CONTROL_TYPE_PSM_STA_UNLOCK,
+       P54_CONTROL_TYPE_PCS,
+       P54_CONTROL_TYPE_BT_BALANCER = 28,
+       P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
+       P54_CONTROL_TYPE_ARPTABLE = 31,
+       P54_CONTROL_TYPE_BT_OPTIONS = 35,
+};
+
+#define P54_HDR_FLAG_CONTROL           BIT(15)
+#define P54_HDR_FLAG_CONTROL_OPSET     (BIT(15) + BIT(0))
+#define P54_HDR_FLAG_DATA_ALIGN                BIT(14)
+
+#define P54_HDR_FLAG_DATA_OUT_PROMISC          BIT(0)
+#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP                BIT(1)
+#define P54_HDR_FLAG_DATA_OUT_SEQNR            BIT(2)
+#define P54_HDR_FLAG_DATA_OUT_BIT3             BIT(3)
+#define P54_HDR_FLAG_DATA_OUT_BURST            BIT(4)
+#define P54_HDR_FLAG_DATA_OUT_NOCANCEL         BIT(5)
+#define P54_HDR_FLAG_DATA_OUT_CLEARTIM         BIT(6)
+#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE                BIT(7)
+#define P54_HDR_FLAG_DATA_OUT_COMPRESS         BIT(8)
+#define P54_HDR_FLAG_DATA_OUT_CONCAT           BIT(9)
+#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT       BIT(10)
+#define P54_HDR_FLAG_DATA_OUT_WAITEOSP         BIT(11)
+
+#define P54_HDR_FLAG_DATA_IN_FCS_GOOD          BIT(0)
+#define P54_HDR_FLAG_DATA_IN_MATCH_MAC         BIT(1)
+#define P54_HDR_FLAG_DATA_IN_MCBC              BIT(2)
+#define P54_HDR_FLAG_DATA_IN_BEACON            BIT(3)
+#define P54_HDR_FLAG_DATA_IN_MATCH_BSS         BIT(4)
+#define P54_HDR_FLAG_DATA_IN_BCAST_BSS         BIT(5)
+#define P54_HDR_FLAG_DATA_IN_DATA              BIT(6)
+#define P54_HDR_FLAG_DATA_IN_TRUNCATED         BIT(7)
+#define P54_HDR_FLAG_DATA_IN_BIT8              BIT(8)
+#define P54_HDR_FLAG_DATA_IN_TRANSPARENT       BIT(9)
+
+struct p54_hdr {
+       __le16 flags;
+       __le16 len;
+       __le32 req_id;
+       __le16 type;    /* enum p54_control_frame_types */
+       u8 rts_tries;
+       u8 tries;
+       u8 data[0];
+} __packed;
+
+#define GET_REQ_ID(skb)                                                        \
+       (((struct p54_hdr *) ((struct sk_buff *) skb)->data)->req_id)   \
+
+#define FREE_AFTER_TX(skb)                                             \
+       ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->         \
+       flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
+
+#define IS_DATA_FRAME(skb)                                             \
+       (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->       \
+       flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL)))
+
+#define GET_HW_QUEUE(skb)                                              \
+       (((struct p54_tx_data *)((struct p54_hdr *)                     \
+       skb->data)->data)->hw_queue)
+
+/*
+ * shared interface ID definitions
+ * The interface ID is a unique identification of a specific interface.
+ * The following values are reserved: 0x0000, 0x0002, 0x0012, 0x0014, 0x0015
+ */
+#define IF_ID_ISL36356A                        0x0001  /* ISL36356A <-> Firmware */
+#define IF_ID_MVC                      0x0003  /* MAC Virtual Coprocessor */
+#define IF_ID_DEBUG                    0x0008  /* PolDebug Interface */
+#define IF_ID_PRODUCT                  0x0009
+#define IF_ID_OEM                      0x000a
+#define IF_ID_PCI3877                  0x000b  /* 3877 <-> Host PCI */
+#define IF_ID_ISL37704C                        0x000c  /* ISL37704C <-> Fw */
+#define IF_ID_ISL39000                 0x000f  /* ISL39000 <-> Fw */
+#define IF_ID_ISL39300A                        0x0010  /* ISL39300A <-> Fw */
+#define IF_ID_ISL37700_UAP             0x0016  /* ISL37700 uAP Fw <-> Fw */
+#define IF_ID_ISL39000_UAP             0x0017  /* ISL39000 uAP Fw <-> Fw */
+#define IF_ID_LMAC                     0x001a  /* Interface exposed by LMAC */
+
+struct exp_if {
+       __le16 role;
+       __le16 if_id;
+       __le16 variant;
+       __le16 btm_compat;
+       __le16 top_compat;
+} __packed;
+
+struct dep_if {
+       __le16 role;
+       __le16 if_id;
+       __le16 variant;
+} __packed;
+
+/* driver <-> lmac definitions */
+struct p54_eeprom_lm86 {
+       union {
+               struct {
+                       __le16 offset;
+                       __le16 len;
+                       u8 data[0];
+               } __packed v1;
+               struct {
+                       __le32 offset;
+                       __le16 len;
+                       u8 magic2;
+                       u8 pad;
+                       u8 magic[4];
+                       u8 data[0];
+               } __packed v2;
+       }  __packed;
+} __packed;
+
+enum p54_rx_decrypt_status {
+       P54_DECRYPT_NONE = 0,
+       P54_DECRYPT_OK,
+       P54_DECRYPT_NOKEY,
+       P54_DECRYPT_NOMICHAEL,
+       P54_DECRYPT_NOCKIPMIC,
+       P54_DECRYPT_FAIL_WEP,
+       P54_DECRYPT_FAIL_TKIP,
+       P54_DECRYPT_FAIL_MICHAEL,
+       P54_DECRYPT_FAIL_CKIPKP,
+       P54_DECRYPT_FAIL_CKIPMIC,
+       P54_DECRYPT_FAIL_AESCCMP
+};
+
+struct p54_rx_data {
+       __le16 flags;
+       __le16 len;
+       __le16 freq;
+       u8 antenna;
+       u8 rate;
+       u8 rssi;
+       u8 quality;
+       u8 decrypt_status;
+       u8 rssi_raw;
+       __le32 tsf32;
+       __le32 unalloc0;
+       u8 align[0];
+} __packed;
+
+enum p54_trap_type {
+       P54_TRAP_SCAN = 0,
+       P54_TRAP_TIMER,
+       P54_TRAP_BEACON_TX,
+       P54_TRAP_FAA_RADIO_ON,
+       P54_TRAP_FAA_RADIO_OFF,
+       P54_TRAP_RADAR,
+       P54_TRAP_NO_BEACON,
+       P54_TRAP_TBTT,
+       P54_TRAP_SCO_ENTER,
+       P54_TRAP_SCO_EXIT
+};
+
+struct p54_trap {
+       __le16 event;
+       __le16 frequency;
+} __packed;
+
+enum p54_frame_sent_status {
+       P54_TX_OK = 0,
+       P54_TX_FAILED,
+       P54_TX_PSM,
+       P54_TX_PSM_CANCELLED = 4
+};
+
+struct p54_frame_sent {
+       u8 status;
+       u8 tries;
+       u8 ack_rssi;
+       u8 quality;
+       __le16 seq;
+       u8 antenna;
+       u8 padding;
+} __packed;
+
+enum p54_tx_data_crypt {
+       P54_CRYPTO_NONE = 0,
+       P54_CRYPTO_WEP,
+       P54_CRYPTO_TKIP,
+       P54_CRYPTO_TKIPMICHAEL,
+       P54_CRYPTO_CCX_WEPMIC,
+       P54_CRYPTO_CCX_KPMIC,
+       P54_CRYPTO_CCX_KP,
+       P54_CRYPTO_AESCCMP
+};
+
+enum p54_tx_data_queue {
+       P54_QUEUE_BEACON        = 0,
+       P54_QUEUE_FWSCAN        = 1,
+       P54_QUEUE_MGMT          = 2,
+       P54_QUEUE_CAB           = 3,
+       P54_QUEUE_DATA          = 4,
+
+       P54_QUEUE_AC_NUM        = 4,
+       P54_QUEUE_AC_VO         = 4,
+       P54_QUEUE_AC_VI         = 5,
+       P54_QUEUE_AC_BE         = 6,
+       P54_QUEUE_AC_BK         = 7,
+
+       /* keep last */
+       P54_QUEUE_NUM           = 8,
+};
+
+#define IS_QOS_QUEUE(n)        (n >= P54_QUEUE_DATA)
+
+struct p54_tx_data {
+       u8 rateset[8];
+       u8 rts_rate_idx;
+       u8 crypt_offset;
+       u8 key_type;
+       u8 key_len;
+       u8 key[16];
+       u8 hw_queue;
+       u8 backlog;
+       __le16 durations[4];
+       u8 tx_antenna;
+       union {
+               struct {
+                       u8 cts_rate;
+                       __le16 output_power;
+               } __packed longbow;
+               struct {
+                       u8 output_power;
+                       u8 cts_rate;
+                       u8 unalloc;
+               } __packed normal;
+       } __packed;
+       u8 unalloc2[2];
+       u8 align[0];
+} __packed;
+
+/* unit is ms */
+#define P54_TX_FRAME_LIFETIME 2000
+#define P54_TX_TIMEOUT 4000
+#define P54_STATISTICS_UPDATE 5000
+
+#define P54_FILTER_TYPE_NONE           0
+#define P54_FILTER_TYPE_STATION                BIT(0)
+#define P54_FILTER_TYPE_IBSS           BIT(1)
+#define P54_FILTER_TYPE_AP             BIT(2)
+#define P54_FILTER_TYPE_TRANSPARENT    BIT(3)
+#define P54_FILTER_TYPE_PROMISCUOUS    BIT(4)
+#define P54_FILTER_TYPE_HIBERNATE      BIT(5)
+#define P54_FILTER_TYPE_NOACK          BIT(6)
+#define P54_FILTER_TYPE_RX_DISABLED    BIT(7)
+
+struct p54_setup_mac {
+       __le16 mac_mode;
+       u8 mac_addr[ETH_ALEN];
+       u8 bssid[ETH_ALEN];
+       u8 rx_antenna;
+       u8 rx_align;
+       union {
+               struct {
+                       __le32 basic_rate_mask;
+                       u8 rts_rates[8];
+                       __le32 rx_addr;
+                       __le16 max_rx;
+                       __le16 rxhw;
+                       __le16 wakeup_timer;
+                       __le16 unalloc0;
+               } __packed v1;
+               struct {
+                       __le32 rx_addr;
+                       __le16 max_rx;
+                       __le16 rxhw;
+                       __le16 timer;
+                       __le16 truncate;
+                       __le32 basic_rate_mask;
+                       u8 sbss_offset;
+                       u8 mcast_window;
+                       u8 rx_rssi_threshold;
+                       u8 rx_ed_threshold;
+                       __le32 ref_clock;
+                       __le16 lpf_bandwidth;
+                       __le16 osc_start_delay;
+               } __packed v2;
+       } __packed;
+} __packed;
+
+#define P54_SETUP_V1_LEN 40
+#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
+
+#define P54_SCAN_EXIT  BIT(0)
+#define P54_SCAN_TRAP  BIT(1)
+#define P54_SCAN_ACTIVE BIT(2)
+#define P54_SCAN_FILTER BIT(3)
+
+struct p54_scan_head {
+       __le16 mode;
+       __le16 dwell;
+       u8 scan_params[20];
+       __le16 freq;
+} __packed;
+
+struct p54_pa_curve_data_sample {
+       u8 rf_power;
+       u8 pa_detector;
+       u8 data_barker;
+       u8 data_bpsk;
+       u8 data_qpsk;
+       u8 data_16qam;
+       u8 data_64qam;
+       u8 padding;
+} __packed;
+
+struct p54_scan_body {
+       u8 pa_points_per_curve;
+       u8 val_barker;
+       u8 val_bpsk;
+       u8 val_qpsk;
+       u8 val_16qam;
+       u8 val_64qam;
+       struct p54_pa_curve_data_sample curve_data[8];
+       u8 dup_bpsk;
+       u8 dup_qpsk;
+       u8 dup_16qam;
+       u8 dup_64qam;
+} __packed;
+
+/*
+ * Warning: Longbow's structures are bogus.
+ */
+struct p54_channel_output_limit_longbow {
+       __le16 rf_power_points[12];
+} __packed;
+
+struct p54_pa_curve_data_sample_longbow {
+       __le16 rf_power;
+       __le16 pa_detector;
+       struct {
+               __le16 data[4];
+       } points[3] __packed;
+} __packed;
+
+struct p54_scan_body_longbow {
+       struct p54_channel_output_limit_longbow power_limits;
+       struct p54_pa_curve_data_sample_longbow curve_data[8];
+       __le16 unkn[6];         /* maybe more power_limits or rate_mask */
+} __packed;
+
+union p54_scan_body_union {
+       struct p54_scan_body normal;
+       struct p54_scan_body_longbow longbow;
+} __packed;
+
+struct p54_scan_tail_rate {
+       __le32 basic_rate_mask;
+       u8 rts_rates[8];
+} __packed;
+
+struct p54_led {
+       __le16 flags;
+       __le16 mask[2];
+       __le16 delay[2];
+} __packed;
+
+struct p54_edcf {
+       u8 flags;
+       u8 slottime;
+       u8 sifs;
+       u8 eofpad;
+       struct p54_edcf_queue_param queue[8];
+       u8 mapping[4];
+       __le16 frameburst;
+       __le16 round_trip_delay;
+} __packed;
+
+struct p54_statistics {
+       __le32 rx_success;
+       __le32 rx_bad_fcs;
+       __le32 rx_abort;
+       __le32 rx_abort_phy;
+       __le32 rts_success;
+       __le32 rts_fail;
+       __le32 tsf32;
+       __le32 airtime;
+       __le32 noise;
+       __le32 sample_noise[8];
+       __le32 sample_cca;
+       __le32 sample_tx;
+} __packed;
+
+struct p54_xbow_synth {
+       __le16 magic1;
+       __le16 magic2;
+       __le16 freq;
+       u32 padding[5];
+} __packed;
+
+struct p54_timer {
+       __le32 interval;
+} __packed;
+
+struct p54_keycache {
+       u8 entry;
+       u8 key_id;
+       u8 mac[ETH_ALEN];
+       u8 padding[2];
+       u8 key_type;
+       u8 key_len;
+       u8 key[24];
+} __packed;
+
+struct p54_burst {
+       u8 flags;
+       u8 queue;
+       u8 backlog;
+       u8 pad;
+       __le16 durations[32];
+} __packed;
+
+struct p54_psm_interval {
+       __le16 interval;
+       __le16 periods;
+} __packed;
+
+#define P54_PSM_CAM                    0
+#define P54_PSM                                BIT(0)
+#define P54_PSM_DTIM                   BIT(1)
+#define P54_PSM_MCBC                   BIT(2)
+#define P54_PSM_CHECKSUM               BIT(3)
+#define P54_PSM_SKIP_MORE_DATA         BIT(4)
+#define P54_PSM_BEACON_TIMEOUT         BIT(5)
+#define P54_PSM_HFOSLEEP               BIT(6)
+#define P54_PSM_AUTOSWITCH_SLEEP       BIT(7)
+#define P54_PSM_LPIT                   BIT(8)
+#define P54_PSM_BF_UCAST_SKIP          BIT(9)
+#define P54_PSM_BF_MCAST_SKIP          BIT(10)
+
+struct p54_psm {
+       __le16 mode;
+       __le16 aid;
+       struct p54_psm_interval intervals[4];
+       u8 beacon_rssi_skip_max;
+       u8 rssi_delta_threshold;
+       u8 nr;
+       u8 exclude[1];
+} __packed;
+
+#define MC_FILTER_ADDRESS_NUM 4
+
+struct p54_group_address_table {
+       __le16 filter_enable;
+       __le16 num_address;
+       u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
+} __packed;
+
+struct p54_txcancel {
+       __le32 req_id;
+} __packed;
+
+struct p54_sta_unlock {
+       u8 addr[ETH_ALEN];
+       u16 padding;
+} __packed;
+
+#define P54_TIM_CLEAR BIT(15)
+struct p54_tim {
+       u8 count;
+       u8 padding[3];
+       __le16 entry[8];
+} __packed;
+
+struct p54_cce_quiet {
+       __le32 period;
+} __packed;
+
+struct p54_bt_balancer {
+       __le16 prio_thresh;
+       __le16 acl_thresh;
+} __packed;
+
+struct p54_arp_table {
+       __le16 filter_enable;
+       u8 ipv4_addr[4];
+} __packed;
+
+/* LED control */
+int p54_set_leds(struct p54_common *priv);
+int p54_init_leds(struct p54_common *priv);
+void p54_unregister_leds(struct p54_common *priv);
+
+/* xmit functions */
+void p54_tx_80211(struct ieee80211_hw *dev,
+                 struct ieee80211_tx_control *control,
+                 struct sk_buff *skb);
+int p54_tx_cancel(struct p54_common *priv, __le32 req_id);
+void p54_tx(struct p54_common *priv, struct sk_buff *skb);
+
+/* synth/phy configuration */
+int p54_init_xbow_synth(struct p54_common *priv);
+int p54_scan(struct p54_common *priv, u16 mode, u16 dwell);
+
+/* MAC */
+int p54_sta_unlock(struct p54_common *priv, u8 *addr);
+int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);
+int p54_setup_mac(struct p54_common *priv);
+int p54_set_ps(struct p54_common *priv);
+int p54_fetch_statistics(struct p54_common *priv);
+int p54_set_groupfilter(struct p54_common *priv);
+
+/* e/v DCF setup */
+int p54_set_edcf(struct p54_common *priv);
+
+/* cryptographic engine */
+int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
+                  u8 idx, u8 len, u8 *addr, u8* key);
+
+/* eeprom */
+int p54_download_eeprom(struct p54_common *priv, void *buf,
+                       u16 offset, u16 len);
+struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *p, const u16 freq);
+
+/* utility */
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie);
+
+#endif /* LMAC_H */
diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c
new file mode 100644 (file)
index 0000000..7805864
--- /dev/null
@@ -0,0 +1,867 @@
+/*
+ * mac80211 glue code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+static bool modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Softmac Prism54 common code");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54common");
+
+static int p54_sta_add_remove(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta)
+{
+       struct p54_common *priv = hw->priv;
+
+       /*
+        * Notify the firmware that we don't want or we don't
+        * need to buffer frames for this station anymore.
+        */
+
+       p54_sta_unlock(priv, sta->addr);
+
+       return 0;
+}
+
+static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+                             enum sta_notify_cmd notify_cmd,
+                             struct ieee80211_sta *sta)
+{
+       struct p54_common *priv = dev->priv;
+
+       switch (notify_cmd) {
+       case STA_NOTIFY_AWAKE:
+               /* update the firmware's filter table */
+               p54_sta_unlock(priv, sta->addr);
+               break;
+       default:
+               break;
+       }
+}
+
+static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
+                       bool set)
+{
+       struct p54_common *priv = dev->priv;
+
+       return p54_update_beacon_tim(priv, sta->aid, set);
+}
+
+u8 *p54_find_ie(struct sk_buff *skb, u8 ie)
+{
+       struct ieee80211_mgmt *mgmt = (void *)skb->data;
+       u8 *pos, *end;
+
+       if (skb->len <= sizeof(mgmt))
+               return NULL;
+
+       pos = (u8 *)mgmt->u.beacon.variable;
+       end = skb->data + skb->len;
+       while (pos < end) {
+               if (pos + 2 + pos[1] > end)
+                       return NULL;
+
+               if (pos[0] == ie)
+                       return pos;
+
+               pos += 2 + pos[1];
+       }
+       return NULL;
+}
+
+static int p54_beacon_format_ie_tim(struct sk_buff *skb)
+{
+       /*
+        * the good excuse for this mess is ... the firmware.
+        * The dummy TIM MUST be at the end of the beacon frame,
+        * because it'll be overwritten!
+        */
+       u8 *tim;
+       u8 dtim_len;
+       u8 dtim_period;
+       u8 *next;
+
+       tim = p54_find_ie(skb, WLAN_EID_TIM);
+       if (!tim)
+               return 0;
+
+       dtim_len = tim[1];
+       dtim_period = tim[3];
+       next = tim + 2 + dtim_len;
+
+       if (dtim_len < 3)
+               return -EINVAL;
+
+       memmove(tim, next, skb_tail_pointer(skb) - next);
+       tim = skb_tail_pointer(skb) - (dtim_len + 2);
+
+       /* add the dummy at the end */
+       tim[0] = WLAN_EID_TIM;
+       tim[1] = 3;
+       tim[2] = 0;
+       tim[3] = dtim_period;
+       tim[4] = 0;
+
+       if (dtim_len > 3)
+               skb_trim(skb, skb->len - (dtim_len - 3));
+
+       return 0;
+}
+
+static int p54_beacon_update(struct p54_common *priv,
+                       struct ieee80211_vif *vif)
+{
+       struct ieee80211_tx_control control = { };
+       struct sk_buff *beacon;
+       int ret;
+
+       beacon = ieee80211_beacon_get(priv->hw, vif);
+       if (!beacon)
+               return -ENOMEM;
+       ret = p54_beacon_format_ie_tim(beacon);
+       if (ret)
+               return ret;
+
+       /*
+        * During operation, the firmware takes care of beaconing.
+        * The driver only needs to upload a new beacon template, once
+        * the template was changed by the stack or userspace.
+        *
+        * LMAC API 3.2.2 also specifies that the driver does not need
+        * to cancel the old beacon template by hand, instead the firmware
+        * will release the previous one through the feedback mechanism.
+        */
+       p54_tx_80211(priv->hw, &control, beacon);
+       priv->tsf_high32 = 0;
+       priv->tsf_low32 = 0;
+
+       return 0;
+}
+
+static int p54_start(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       int err;
+
+       mutex_lock(&priv->conf_mutex);
+       err = priv->open(dev);
+       if (err)
+               goto out;
+       P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
+       P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
+       P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
+       P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
+       err = p54_set_edcf(priv);
+       if (err)
+               goto out;
+
+       eth_broadcast_addr(priv->bssid);
+       priv->mode = NL80211_IFTYPE_MONITOR;
+       err = p54_setup_mac(priv);
+       if (err) {
+               priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+               goto out;
+       }
+
+       ieee80211_queue_delayed_work(dev, &priv->work, 0);
+
+       priv->softled_state = 0;
+       err = p54_set_leds(priv);
+
+out:
+       mutex_unlock(&priv->conf_mutex);
+       return err;
+}
+
+static void p54_stop(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       int i;
+
+       priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+       priv->softled_state = 0;
+       cancel_delayed_work_sync(&priv->work);
+       mutex_lock(&priv->conf_mutex);
+       p54_set_leds(priv);
+       priv->stop(dev);
+       skb_queue_purge(&priv->tx_pending);
+       skb_queue_purge(&priv->tx_queue);
+       for (i = 0; i < P54_QUEUE_NUM; i++) {
+               priv->tx_stats[i].count = 0;
+               priv->tx_stats[i].len = 0;
+       }
+
+       priv->beacon_req_id = cpu_to_le32(0);
+       priv->tsf_high32 = priv->tsf_low32 = 0;
+       mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_add_interface(struct ieee80211_hw *dev,
+                            struct ieee80211_vif *vif)
+{
+       struct p54_common *priv = dev->priv;
+       int err;
+
+       vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
+
+       mutex_lock(&priv->conf_mutex);
+       if (priv->mode != NL80211_IFTYPE_MONITOR) {
+               mutex_unlock(&priv->conf_mutex);
+               return -EOPNOTSUPP;
+       }
+
+       priv->vif = vif;
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_MESH_POINT:
+               priv->mode = vif->type;
+               break;
+       default:
+               mutex_unlock(&priv->conf_mutex);
+               return -EOPNOTSUPP;
+       }
+
+       memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
+       err = p54_setup_mac(priv);
+       mutex_unlock(&priv->conf_mutex);
+       return err;
+}
+
+static void p54_remove_interface(struct ieee80211_hw *dev,
+                                struct ieee80211_vif *vif)
+{
+       struct p54_common *priv = dev->priv;
+
+       mutex_lock(&priv->conf_mutex);
+       priv->vif = NULL;
+
+       /*
+        * LMAC API 3.2.2 states that any active beacon template must be
+        * canceled by the driver before attempting a mode transition.
+        */
+       if (le32_to_cpu(priv->beacon_req_id) != 0) {
+               p54_tx_cancel(priv, priv->beacon_req_id);
+               wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ);
+       }
+       priv->mode = NL80211_IFTYPE_MONITOR;
+       eth_zero_addr(priv->mac_addr);
+       eth_zero_addr(priv->bssid);
+       p54_setup_mac(priv);
+       mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_wait_for_stats(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       int ret;
+
+       priv->update_stats = true;
+       ret = p54_fetch_statistics(priv);
+       if (ret)
+               return ret;
+
+       ret = wait_for_completion_interruptible_timeout(&priv->stat_comp, HZ);
+       if (ret == 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static void p54_reset_stats(struct p54_common *priv)
+{
+       struct ieee80211_channel *chan = priv->curchan;
+
+       if (chan) {
+               struct survey_info *info = &priv->survey[chan->hw_value];
+
+               /* only reset channel statistics, don't touch .filled, etc. */
+               info->time = 0;
+               info->time_busy = 0;
+               info->time_tx = 0;
+       }
+
+       priv->update_stats = true;
+       priv->survey_raw.active = 0;
+       priv->survey_raw.cca = 0;
+       priv->survey_raw.tx = 0;
+}
+
+static int p54_config(struct ieee80211_hw *dev, u32 changed)
+{
+       int ret = 0;
+       struct p54_common *priv = dev->priv;
+       struct ieee80211_conf *conf = &dev->conf;
+
+       mutex_lock(&priv->conf_mutex);
+       if (changed & IEEE80211_CONF_CHANGE_POWER)
+               priv->output_power = conf->power_level << 2;
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+               struct ieee80211_channel *oldchan;
+               WARN_ON(p54_wait_for_stats(dev));
+               oldchan = priv->curchan;
+               priv->curchan = NULL;
+               ret = p54_scan(priv, P54_SCAN_EXIT, 0);
+               if (ret) {
+                       priv->curchan = oldchan;
+                       goto out;
+               }
+               /*
+                * TODO: Use the LM_SCAN_TRAP to determine the current
+                * operating channel.
+                */
+               priv->curchan = priv->hw->conf.chandef.chan;
+               p54_reset_stats(priv);
+               WARN_ON(p54_fetch_statistics(priv));
+       }
+       if (changed & IEEE80211_CONF_CHANGE_PS) {
+               WARN_ON(p54_wait_for_stats(dev));
+               ret = p54_set_ps(priv);
+               if (ret)
+                       goto out;
+               WARN_ON(p54_wait_for_stats(dev));
+       }
+       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+               WARN_ON(p54_wait_for_stats(dev));
+               ret = p54_setup_mac(priv);
+               if (ret)
+                       goto out;
+               WARN_ON(p54_wait_for_stats(dev));
+       }
+
+out:
+       mutex_unlock(&priv->conf_mutex);
+       return ret;
+}
+
+static u64 p54_prepare_multicast(struct ieee80211_hw *dev,
+                                struct netdev_hw_addr_list *mc_list)
+{
+       struct p54_common *priv = dev->priv;
+       struct netdev_hw_addr *ha;
+       int i;
+
+       BUILD_BUG_ON(ARRAY_SIZE(priv->mc_maclist) !=
+               ARRAY_SIZE(((struct p54_group_address_table *)NULL)->mac_list));
+       /*
+        * The first entry is reserved for the global broadcast MAC.
+        * Otherwise the firmware will drop it and ARP will no longer work.
+        */
+       i = 1;
+       priv->mc_maclist_num = netdev_hw_addr_list_count(mc_list) + i;
+       netdev_hw_addr_list_for_each(ha, mc_list) {
+               memcpy(&priv->mc_maclist[i], ha->addr, ETH_ALEN);
+               i++;
+               if (i >= ARRAY_SIZE(priv->mc_maclist))
+                       break;
+       }
+
+       return 1; /* update */
+}
+
+static void p54_configure_filter(struct ieee80211_hw *dev,
+                                unsigned int changed_flags,
+                                unsigned int *total_flags,
+                                u64 multicast)
+{
+       struct p54_common *priv = dev->priv;
+
+       *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS;
+
+       priv->filter_flags = *total_flags;
+
+       if (changed_flags & FIF_OTHER_BSS)
+               p54_setup_mac(priv);
+
+       if (changed_flags & FIF_ALLMULTI || multicast)
+               p54_set_groupfilter(priv);
+}
+
+static int p54_conf_tx(struct ieee80211_hw *dev,
+                      struct ieee80211_vif *vif, u16 queue,
+                      const struct ieee80211_tx_queue_params *params)
+{
+       struct p54_common *priv = dev->priv;
+       int ret;
+
+       mutex_lock(&priv->conf_mutex);
+       if (queue < dev->queues) {
+               P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
+                       params->cw_min, params->cw_max, params->txop);
+               ret = p54_set_edcf(priv);
+       } else
+               ret = -EINVAL;
+       mutex_unlock(&priv->conf_mutex);
+       return ret;
+}
+
+static void p54_work(struct work_struct *work)
+{
+       struct p54_common *priv = container_of(work, struct p54_common,
+                                              work.work);
+
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return ;
+
+       /*
+        * TODO: walk through tx_queue and do the following tasks
+        *      1. initiate bursts.
+        *      2. cancel stuck frames / reset the device if necessary.
+        */
+
+       mutex_lock(&priv->conf_mutex);
+       WARN_ON_ONCE(p54_fetch_statistics(priv));
+       mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_get_stats(struct ieee80211_hw *dev,
+                        struct ieee80211_low_level_stats *stats)
+{
+       struct p54_common *priv = dev->priv;
+
+       memcpy(stats, &priv->stats, sizeof(*stats));
+       return 0;
+}
+
+static void p54_bss_info_changed(struct ieee80211_hw *dev,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_bss_conf *info,
+                                u32 changed)
+{
+       struct p54_common *priv = dev->priv;
+
+       mutex_lock(&priv->conf_mutex);
+       if (changed & BSS_CHANGED_BSSID) {
+               memcpy(priv->bssid, info->bssid, ETH_ALEN);
+               p54_setup_mac(priv);
+       }
+
+       if (changed & BSS_CHANGED_BEACON) {
+               p54_scan(priv, P54_SCAN_EXIT, 0);
+               p54_setup_mac(priv);
+               p54_beacon_update(priv, vif);
+               p54_set_edcf(priv);
+       }
+
+       if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
+               priv->use_short_slot = info->use_short_slot;
+               p54_set_edcf(priv);
+       }
+       if (changed & BSS_CHANGED_BASIC_RATES) {
+               if (dev->conf.chandef.chan->band == IEEE80211_BAND_5GHZ)
+                       priv->basic_rate_mask = (info->basic_rates << 4);
+               else
+                       priv->basic_rate_mask = info->basic_rates;
+               p54_setup_mac(priv);
+               if (priv->fw_var >= 0x500)
+                       p54_scan(priv, P54_SCAN_EXIT, 0);
+       }
+       if (changed & BSS_CHANGED_ASSOC) {
+               if (info->assoc) {
+                       priv->aid = info->aid;
+                       priv->wakeup_timer = info->beacon_int *
+                                            info->dtim_period * 5;
+                       p54_setup_mac(priv);
+               } else {
+                       priv->wakeup_timer = 500;
+                       priv->aid = 0;
+               }
+       }
+
+       mutex_unlock(&priv->conf_mutex);
+}
+
+static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
+                      struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+                      struct ieee80211_key_conf *key)
+{
+       struct p54_common *priv = dev->priv;
+       int slot, ret = 0;
+       u8 algo = 0;
+       u8 *addr = NULL;
+
+       if (modparam_nohwcrypt)
+               return -EOPNOTSUPP;
+
+       if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
+               /*
+                * Unfortunately most/all firmwares are trying to decrypt
+                * incoming management frames if a suitable key can be found.
+                * However, in doing so the data in these frames gets
+                * corrupted. So, we can't have firmware supported crypto
+                * offload in this case.
+                */
+               return -EOPNOTSUPP;
+       }
+
+       mutex_lock(&priv->conf_mutex);
+       if (cmd == SET_KEY) {
+               switch (key->cipher) {
+               case WLAN_CIPHER_SUITE_TKIP:
+                       if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
+                             BR_DESC_PRIV_CAP_TKIP))) {
+                               ret = -EOPNOTSUPP;
+                               goto out_unlock;
+                       }
+                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+                       algo = P54_CRYPTO_TKIPMICHAEL;
+                       break;
+               case WLAN_CIPHER_SUITE_WEP40:
+               case WLAN_CIPHER_SUITE_WEP104:
+                       if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
+                               ret = -EOPNOTSUPP;
+                               goto out_unlock;
+                       }
+                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+                       algo = P54_CRYPTO_WEP;
+                       break;
+               case WLAN_CIPHER_SUITE_CCMP:
+                       if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
+                               ret = -EOPNOTSUPP;
+                               goto out_unlock;
+                       }
+                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+                       algo = P54_CRYPTO_AESCCMP;
+                       break;
+               default:
+                       ret = -EOPNOTSUPP;
+                       goto out_unlock;
+               }
+               slot = bitmap_find_free_region(priv->used_rxkeys,
+                                              priv->rx_keycache_size, 0);
+
+               if (slot < 0) {
+                       /*
+                        * The device supports the chosen algorithm, but the
+                        * firmware does not provide enough key slots to store
+                        * all of them.
+                        * But encryption offload for outgoing frames is always
+                        * possible, so we just pretend that the upload was
+                        * successful and do the decryption in software.
+                        */
+
+                       /* mark the key as invalid. */
+                       key->hw_key_idx = 0xff;
+                       goto out_unlock;
+               }
+
+               key->flags |= IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
+       } else {
+               slot = key->hw_key_idx;
+
+               if (slot == 0xff) {
+                       /* This key was not uploaded into the rx key cache. */
+
+                       goto out_unlock;
+               }
+
+               bitmap_release_region(priv->used_rxkeys, slot, 0);
+               algo = 0;
+       }
+
+       if (sta)
+               addr = sta->addr;
+
+       ret = p54_upload_key(priv, algo, slot, key->keyidx,
+                            key->keylen, addr, key->key);
+       if (ret) {
+               bitmap_release_region(priv->used_rxkeys, slot, 0);
+               ret = -EOPNOTSUPP;
+               goto out_unlock;
+       }
+
+       key->hw_key_idx = slot;
+
+out_unlock:
+       mutex_unlock(&priv->conf_mutex);
+       return ret;
+}
+
+static int p54_get_survey(struct ieee80211_hw *dev, int idx,
+                               struct survey_info *survey)
+{
+       struct p54_common *priv = dev->priv;
+       struct ieee80211_channel *chan;
+       int err, tries;
+       bool in_use = false;
+
+       if (idx >= priv->chan_num)
+               return -ENOENT;
+
+#define MAX_TRIES 1
+       for (tries = 0; tries < MAX_TRIES; tries++) {
+               chan = priv->curchan;
+               if (chan && chan->hw_value == idx) {
+                       mutex_lock(&priv->conf_mutex);
+                       err = p54_wait_for_stats(dev);
+                       mutex_unlock(&priv->conf_mutex);
+                       if (err)
+                               return err;
+
+                       in_use = true;
+               }
+
+               memcpy(survey, &priv->survey[idx], sizeof(*survey));
+
+               if (in_use) {
+                       /* test if the reported statistics are valid. */
+                       if  (survey->time != 0) {
+                               survey->filled |= SURVEY_INFO_IN_USE;
+                       } else {
+                               /*
+                                * hw/fw has not accumulated enough sample sets.
+                                * Wait for 100ms, this ought to be enough to
+                                * to get at least one non-null set of channel
+                                * usage statistics.
+                                */
+                               msleep(100);
+                               continue;
+                       }
+               }
+               return 0;
+       }
+       return -ETIMEDOUT;
+#undef MAX_TRIES
+}
+
+static unsigned int p54_flush_count(struct p54_common *priv)
+{
+       unsigned int total = 0, i;
+
+       BUILD_BUG_ON(P54_QUEUE_NUM > ARRAY_SIZE(priv->tx_stats));
+
+       /*
+        * Because the firmware has the sole control over any frames
+        * in the P54_QUEUE_BEACON or P54_QUEUE_SCAN queues, they
+        * don't really count as pending or active.
+        */
+       for (i = P54_QUEUE_MGMT; i < P54_QUEUE_NUM; i++)
+               total += priv->tx_stats[i].len;
+       return total;
+}
+
+static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
+                     u32 queues, bool drop)
+{
+       struct p54_common *priv = dev->priv;
+       unsigned int total, i;
+
+       /*
+        * Currently, it wouldn't really matter if we wait for one second
+        * or 15 minutes. But once someone gets around and completes the
+        * TODOs [ancel stuck frames / reset device] in p54_work, it will
+        * suddenly make sense to wait that long.
+        */
+       i = P54_STATISTICS_UPDATE * 2 / 20;
+
+       /*
+        * In this case no locking is required because as we speak the
+        * queues have already been stopped and no new frames can sneak
+        * up from behind.
+        */
+       while ((total = p54_flush_count(priv) && i--)) {
+               /* waste time */
+               msleep(20);
+       }
+
+       WARN(total, "tx flush timeout, unresponsive firmware");
+}
+
+static void p54_set_coverage_class(struct ieee80211_hw *dev,
+                                  s16 coverage_class)
+{
+       struct p54_common *priv = dev->priv;
+
+       mutex_lock(&priv->conf_mutex);
+       /* support all coverage class values as in 802.11-2007 Table 7-27 */
+       priv->coverage_class = clamp_t(u8, coverage_class, 0, 31);
+       p54_set_edcf(priv);
+       mutex_unlock(&priv->conf_mutex);
+}
+
+static const struct ieee80211_ops p54_ops = {
+       .tx                     = p54_tx_80211,
+       .start                  = p54_start,
+       .stop                   = p54_stop,
+       .add_interface          = p54_add_interface,
+       .remove_interface       = p54_remove_interface,
+       .set_tim                = p54_set_tim,
+       .sta_notify             = p54_sta_notify,
+       .sta_add                = p54_sta_add_remove,
+       .sta_remove             = p54_sta_add_remove,
+       .set_key                = p54_set_key,
+       .config                 = p54_config,
+       .flush                  = p54_flush,
+       .bss_info_changed       = p54_bss_info_changed,
+       .prepare_multicast      = p54_prepare_multicast,
+       .configure_filter       = p54_configure_filter,
+       .conf_tx                = p54_conf_tx,
+       .get_stats              = p54_get_stats,
+       .get_survey             = p54_get_survey,
+       .set_coverage_class     = p54_set_coverage_class,
+};
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len)
+{
+       struct ieee80211_hw *dev;
+       struct p54_common *priv;
+
+       dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
+       if (!dev)
+               return NULL;
+
+       priv = dev->priv;
+       priv->hw = dev;
+       priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+       priv->basic_rate_mask = 0x15f;
+       spin_lock_init(&priv->tx_stats_lock);
+       skb_queue_head_init(&priv->tx_queue);
+       skb_queue_head_init(&priv->tx_pending);
+       ieee80211_hw_set(dev, REPORTS_TX_ACK_STATUS);
+       ieee80211_hw_set(dev, MFP_CAPABLE);
+       ieee80211_hw_set(dev, PS_NULLFUNC_STACK);
+       ieee80211_hw_set(dev, SUPPORTS_PS);
+       ieee80211_hw_set(dev, RX_INCLUDES_FCS);
+       ieee80211_hw_set(dev, SIGNAL_DBM);
+
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                     BIT(NL80211_IFTYPE_ADHOC) |
+                                     BIT(NL80211_IFTYPE_AP) |
+                                     BIT(NL80211_IFTYPE_MESH_POINT);
+
+       priv->beacon_req_id = cpu_to_le32(0);
+       priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
+       priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
+       priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
+       priv->tx_stats[P54_QUEUE_CAB].limit = 3;
+       priv->tx_stats[P54_QUEUE_DATA].limit = 5;
+       dev->queues = 1;
+       priv->noise = -94;
+       /*
+        * We support at most 8 tries no matter which rate they're at,
+        * we cannot support max_rates * max_rate_tries as we set it
+        * here, but setting it correctly to 4/2 or so would limit us
+        * artificially if the RC algorithm wants just two rates, so
+        * let's say 4/7, we'll redistribute it at TX time, see the
+        * comments there.
+        */
+       dev->max_rates = 4;
+       dev->max_rate_tries = 7;
+       dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
+                                sizeof(struct p54_tx_data);
+
+       /*
+        * For now, disable PS by default because it affects
+        * link stability significantly.
+        */
+       dev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+       mutex_init(&priv->conf_mutex);
+       mutex_init(&priv->eeprom_mutex);
+       init_completion(&priv->stat_comp);
+       init_completion(&priv->eeprom_comp);
+       init_completion(&priv->beacon_comp);
+       INIT_DELAYED_WORK(&priv->work, p54_work);
+
+       eth_broadcast_addr(priv->mc_maclist[0]);
+       priv->curchan = NULL;
+       p54_reset_stats(priv);
+       return dev;
+}
+EXPORT_SYMBOL_GPL(p54_init_common);
+
+int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
+{
+       struct p54_common __maybe_unused *priv = dev->priv;
+       int err;
+
+       err = ieee80211_register_hw(dev);
+       if (err) {
+               dev_err(pdev, "Cannot register device (%d).\n", err);
+               return err;
+       }
+       priv->registered = true;
+
+#ifdef CONFIG_P54_LEDS
+       err = p54_init_leds(priv);
+       if (err) {
+               p54_unregister_common(dev);
+               return err;
+       }
+#endif /* CONFIG_P54_LEDS */
+
+       dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
+       return 0;
+}
+EXPORT_SYMBOL_GPL(p54_register_common);
+
+void p54_free_common(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       unsigned int i;
+
+       for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+               kfree(priv->band_table[i]);
+
+       kfree(priv->iq_autocal);
+       kfree(priv->output_limit);
+       kfree(priv->curve_data);
+       kfree(priv->rssi_db);
+       kfree(priv->used_rxkeys);
+       kfree(priv->survey);
+       priv->iq_autocal = NULL;
+       priv->output_limit = NULL;
+       priv->curve_data = NULL;
+       priv->rssi_db = NULL;
+       priv->used_rxkeys = NULL;
+       priv->survey = NULL;
+       ieee80211_free_hw(dev);
+}
+EXPORT_SYMBOL_GPL(p54_free_common);
+
+void p54_unregister_common(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+
+#ifdef CONFIG_P54_LEDS
+       p54_unregister_leds(priv);
+#endif /* CONFIG_P54_LEDS */
+
+       if (priv->registered) {
+               priv->registered = false;
+               ieee80211_unregister_hw(dev);
+       }
+
+       mutex_destroy(&priv->conf_mutex);
+       mutex_destroy(&priv->eeprom_mutex);
+}
+EXPORT_SYMBOL_GPL(p54_unregister_common);
diff --git a/drivers/net/wireless/intersil/p54/p54.h b/drivers/net/wireless/intersil/p54/p54.h
new file mode 100644 (file)
index 0000000..40b401e
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Shared defines for all mac80211 Prism54 code
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef P54_H
+#define P54_H
+
+#ifdef CONFIG_P54_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_P54_LEDS */
+
+#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
+
+#define BR_CODE_MIN                    0x80000000
+#define BR_CODE_COMPONENT_ID           0x80000001
+#define BR_CODE_COMPONENT_VERSION      0x80000002
+#define BR_CODE_DEPENDENT_IF           0x80000003
+#define BR_CODE_EXPOSED_IF             0x80000004
+#define BR_CODE_DESCR                  0x80000101
+#define BR_CODE_MAX                    0x8FFFFFFF
+#define BR_CODE_END_OF_BRA             0xFF0000FF
+#define LEGACY_BR_CODE_END_OF_BRA      0xFFFFFFFF
+
+struct bootrec {
+       __le32 code;
+       __le32 len;
+       u32 data[10];
+} __packed;
+
+/* Interface role definitions */
+#define BR_INTERFACE_ROLE_SERVER       0x0000
+#define BR_INTERFACE_ROLE_CLIENT       0x8000
+
+#define BR_DESC_PRIV_CAP_WEP           BIT(0)
+#define BR_DESC_PRIV_CAP_TKIP          BIT(1)
+#define BR_DESC_PRIV_CAP_MICHAEL       BIT(2)
+#define BR_DESC_PRIV_CAP_CCX_CP                BIT(3)
+#define BR_DESC_PRIV_CAP_CCX_MIC       BIT(4)
+#define BR_DESC_PRIV_CAP_AESCCMP       BIT(5)
+
+struct bootrec_desc {
+       __le16 modes;
+       __le16 flags;
+       __le32 rx_start;
+       __le32 rx_end;
+       u8 headroom;
+       u8 tailroom;
+       u8 tx_queues;
+       u8 tx_depth;
+       u8 privacy_caps;
+       u8 rx_keycache_size;
+       u8 time_size;
+       u8 padding;
+       u8 rates[16];
+       u8 padding2[4];
+       __le16 rx_mtu;
+} __packed;
+
+#define FW_FMAC 0x464d4143
+#define FW_LM86 0x4c4d3836
+#define FW_LM87 0x4c4d3837
+#define FW_LM20 0x4c4d3230
+
+struct bootrec_comp_id {
+       __le32 fw_variant;
+} __packed;
+
+struct bootrec_comp_ver {
+       char fw_version[24];
+} __packed;
+
+struct bootrec_end {
+       __le16 crc;
+       u8 padding[2];
+       u8 md5[16];
+} __packed;
+
+/* provide 16 bytes for the transport back-end */
+#define P54_TX_INFO_DATA_SIZE          16
+
+/* stored in ieee80211_tx_info's rate_driver_data */
+struct p54_tx_info {
+       u32 start_addr;
+       u32 end_addr;
+       union {
+               void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
+               struct {
+                       u32 extra_len;
+               };
+       };
+};
+
+#define P54_MAX_CTRL_FRAME_LEN         0x1000
+
+#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop)     \
+do {                                                           \
+       queue.aifs = cpu_to_le16(ai_fs);                        \
+       queue.cwmin = cpu_to_le16(cw_min);                      \
+       queue.cwmax = cpu_to_le16(cw_max);                      \
+       queue.txop = cpu_to_le16(_txop);                        \
+} while (0)
+
+struct p54_edcf_queue_param {
+       __le16 aifs;
+       __le16 cwmin;
+       __le16 cwmax;
+       __le16 txop;
+} __packed;
+
+struct p54_rssi_db_entry {
+       u16 freq;
+       s16 mul;
+       s16 add;
+       s16 longbow_unkn;
+       s16 longbow_unk2;
+};
+
+struct p54_cal_database {
+       size_t entries;
+       size_t entry_size;
+       size_t offset;
+       size_t len;
+       u8 data[0];
+};
+
+#define EEPROM_READBACK_LEN 0x3fc
+
+enum fw_state {
+       FW_STATE_OFF,
+       FW_STATE_BOOTING,
+       FW_STATE_READY,
+       FW_STATE_RESET,
+       FW_STATE_RESETTING,
+};
+
+#ifdef CONFIG_P54_LEDS
+
+#define P54_LED_MAX_NAME_LEN 31
+
+struct p54_led_dev {
+       struct ieee80211_hw *hw_dev;
+       struct led_classdev led_dev;
+       char name[P54_LED_MAX_NAME_LEN + 1];
+
+       unsigned int toggled;
+       unsigned int index;
+       unsigned int registered;
+};
+
+#endif /* CONFIG_P54_LEDS */
+
+struct p54_tx_queue_stats {
+       unsigned int len;
+       unsigned int limit;
+       unsigned int count;
+};
+
+struct p54_common {
+       struct ieee80211_hw *hw;
+       struct ieee80211_vif *vif;
+       void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
+       int (*open)(struct ieee80211_hw *dev);
+       void (*stop)(struct ieee80211_hw *dev);
+       struct sk_buff_head tx_pending;
+       struct sk_buff_head tx_queue;
+       struct mutex conf_mutex;
+       bool registered;
+
+       /* memory management (as seen by the firmware) */
+       u32 rx_start;
+       u32 rx_end;
+       u16 rx_mtu;
+       u8 headroom;
+       u8 tailroom;
+
+       /* firmware/hardware info */
+       unsigned int tx_hdr_len;
+       unsigned int fw_var;
+       unsigned int fw_interface;
+       u8 version;
+
+       /* (e)DCF / QOS state */
+       bool use_short_slot;
+       spinlock_t tx_stats_lock;
+       struct p54_tx_queue_stats tx_stats[8];
+       struct p54_edcf_queue_param qos_params[8];
+
+       /* Radio data */
+       u16 rxhw;
+       u8 rx_diversity_mask;
+       u8 tx_diversity_mask;
+       unsigned int output_power;
+       struct p54_rssi_db_entry *cur_rssi;
+       struct ieee80211_channel *curchan;
+       struct survey_info *survey;
+       unsigned int chan_num;
+       struct completion stat_comp;
+       bool update_stats;
+       struct {
+               unsigned int timestamp;
+               unsigned int cached_cca;
+               unsigned int cached_tx;
+               unsigned int cached_rssi;
+               u64 active;
+               u64 cca;
+               u64 tx;
+               u64 rssi;
+       } survey_raw;
+
+       int noise;
+       /* calibration, output power limit and rssi<->dBm conversation data */
+       struct pda_iq_autocal_entry *iq_autocal;
+       unsigned int iq_autocal_len;
+       struct p54_cal_database *curve_data;
+       struct p54_cal_database *output_limit;
+       struct p54_cal_database *rssi_db;
+       struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];
+
+       /* BBP/MAC state */
+       u8 mac_addr[ETH_ALEN];
+       u8 bssid[ETH_ALEN];
+       u8 mc_maclist[4][ETH_ALEN];
+       u16 wakeup_timer;
+       unsigned int filter_flags;
+       int mc_maclist_num;
+       int mode;
+       u32 tsf_low32, tsf_high32;
+       u32 basic_rate_mask;
+       u16 aid;
+       u8 coverage_class;
+       bool phy_idle;
+       bool phy_ps;
+       bool powersave_override;
+       __le32 beacon_req_id;
+       struct completion beacon_comp;
+
+       /* cryptographic engine information */
+       u8 privacy_caps;
+       u8 rx_keycache_size;
+       unsigned long *used_rxkeys;
+
+       /* LED management */
+#ifdef CONFIG_P54_LEDS
+       struct p54_led_dev leds[4];
+       struct delayed_work led_work;
+#endif /* CONFIG_P54_LEDS */
+       u16 softled_state;              /* bit field of glowing LEDs */
+
+       /* statistics */
+       struct ieee80211_low_level_stats stats;
+       struct delayed_work work;
+
+       /* eeprom handling */
+       void *eeprom;
+       struct completion eeprom_comp;
+       struct mutex eeprom_mutex;
+};
+
+/* interfaces for the drivers */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
+int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
+int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
+int p54_read_eeprom(struct ieee80211_hw *dev);
+
+struct ieee80211_hw *p54_init_common(size_t priv_data_len);
+int p54_register_common(struct ieee80211_hw *dev, struct device *pdev);
+void p54_free_common(struct ieee80211_hw *dev);
+
+void p54_unregister_common(struct ieee80211_hw *dev);
+
+#endif /* P54_H */
diff --git a/drivers/net/wireless/intersil/p54/p54pci.c b/drivers/net/wireless/intersil/p54/p54pci.c
new file mode 100644 (file)
index 0000000..27a4906
--- /dev/null
@@ -0,0 +1,703 @@
+
+/*
+ * Linux device driver for PCI based Prism54
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2008, Christian Lamparter <chunkeey@web.de>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/module.h>
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+#include "p54pci.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Prism54 PCI wireless driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54pci");
+MODULE_FIRMWARE("isl3886pci");
+
+static const struct pci_device_id p54p_table[] = {
+       /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
+       { PCI_DEVICE(0x1260, 0x3890) },
+       /* 3COM 3CRWE154G72 Wireless LAN adapter */
+       { PCI_DEVICE(0x10b7, 0x6001) },
+       /* Intersil PRISM Indigo Wireless LAN adapter */
+       { PCI_DEVICE(0x1260, 0x3877) },
+       /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */
+       { PCI_DEVICE(0x1260, 0x3886) },
+       /* Intersil PRISM Xbow Wireless LAN adapter (Symbol AP-300) */
+       { PCI_DEVICE(0x1260, 0xffff) },
+       { },
+};
+
+MODULE_DEVICE_TABLE(pci, p54p_table);
+
+static int p54p_upload_firmware(struct ieee80211_hw *dev)
+{
+       struct p54p_priv *priv = dev->priv;
+       __le32 reg;
+       int err;
+       __le32 *data;
+       u32 remains, left, device_addr;
+
+       P54P_WRITE(int_enable, cpu_to_le32(0));
+       P54P_READ(int_enable);
+       udelay(10);
+
+       reg = P54P_READ(ctrl_stat);
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
+       P54P_WRITE(ctrl_stat, reg);
+       P54P_READ(ctrl_stat);
+       udelay(10);
+
+       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+       P54P_WRITE(ctrl_stat, reg);
+       wmb();
+       udelay(10);
+
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+       P54P_WRITE(ctrl_stat, reg);
+       wmb();
+
+       /* wait for the firmware to reset properly */
+       mdelay(10);
+
+       err = p54_parse_firmware(dev, priv->firmware);
+       if (err)
+               return err;
+
+       if (priv->common.fw_interface != FW_LM86) {
+               dev_err(&priv->pdev->dev, "wrong firmware, "
+                       "please get a LM86(PCI) firmware a try again.\n");
+               return -EINVAL;
+       }
+
+       data = (__le32 *) priv->firmware->data;
+       remains = priv->firmware->size;
+       device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
+       while (remains) {
+               u32 i = 0;
+               left = min((u32)0x1000, remains);
+               P54P_WRITE(direct_mem_base, cpu_to_le32(device_addr));
+               P54P_READ(int_enable);
+
+               device_addr += 0x1000;
+               while (i < left) {
+                       P54P_WRITE(direct_mem_win[i], *data++);
+                       i += sizeof(u32);
+               }
+
+               remains -= left;
+               P54P_READ(int_enable);
+       }
+
+       reg = P54P_READ(ctrl_stat);
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
+       P54P_WRITE(ctrl_stat, reg);
+       P54P_READ(ctrl_stat);
+       udelay(10);
+
+       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+       P54P_WRITE(ctrl_stat, reg);
+       wmb();
+       udelay(10);
+
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+       P54P_WRITE(ctrl_stat, reg);
+       wmb();
+       udelay(10);
+
+       /* wait for the firmware to boot properly */
+       mdelay(100);
+
+       return 0;
+}
+
+static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
+       int ring_index, struct p54p_desc *ring, u32 ring_limit,
+       struct sk_buff **rx_buf, u32 index)
+{
+       struct p54p_priv *priv = dev->priv;
+       struct p54p_ring_control *ring_control = priv->ring_control;
+       u32 limit, idx, i;
+
+       idx = le32_to_cpu(ring_control->host_idx[ring_index]);
+       limit = idx;
+       limit -= index;
+       limit = ring_limit - limit;
+
+       i = idx % ring_limit;
+       while (limit-- > 1) {
+               struct p54p_desc *desc = &ring[i];
+
+               if (!desc->host_addr) {
+                       struct sk_buff *skb;
+                       dma_addr_t mapping;
+                       skb = dev_alloc_skb(priv->common.rx_mtu + 32);
+                       if (!skb)
+                               break;
+
+                       mapping = pci_map_single(priv->pdev,
+                                                skb_tail_pointer(skb),
+                                                priv->common.rx_mtu + 32,
+                                                PCI_DMA_FROMDEVICE);
+
+                       if (pci_dma_mapping_error(priv->pdev, mapping)) {
+                               dev_kfree_skb_any(skb);
+                               dev_err(&priv->pdev->dev,
+                                       "RX DMA Mapping error\n");
+                               break;
+                       }
+
+                       desc->host_addr = cpu_to_le32(mapping);
+                       desc->device_addr = 0;  // FIXME: necessary?
+                       desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
+                       desc->flags = 0;
+                       rx_buf[i] = skb;
+               }
+
+               i++;
+               idx++;
+               i %= ring_limit;
+       }
+
+       wmb();
+       ring_control->host_idx[ring_index] = cpu_to_le32(idx);
+}
+
+static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
+       int ring_index, struct p54p_desc *ring, u32 ring_limit,
+       struct sk_buff **rx_buf)
+{
+       struct p54p_priv *priv = dev->priv;
+       struct p54p_ring_control *ring_control = priv->ring_control;
+       struct p54p_desc *desc;
+       u32 idx, i;
+
+       i = (*index) % ring_limit;
+       (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
+       idx %= ring_limit;
+       while (i != idx) {
+               u16 len;
+               struct sk_buff *skb;
+               dma_addr_t dma_addr;
+               desc = &ring[i];
+               len = le16_to_cpu(desc->len);
+               skb = rx_buf[i];
+
+               if (!skb) {
+                       i++;
+                       i %= ring_limit;
+                       continue;
+               }
+
+               if (unlikely(len > priv->common.rx_mtu)) {
+                       if (net_ratelimit())
+                               dev_err(&priv->pdev->dev, "rx'd frame size "
+                                       "exceeds length threshold.\n");
+
+                       len = priv->common.rx_mtu;
+               }
+               dma_addr = le32_to_cpu(desc->host_addr);
+               pci_dma_sync_single_for_cpu(priv->pdev, dma_addr,
+                       priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
+               skb_put(skb, len);
+
+               if (p54_rx(dev, skb)) {
+                       pci_unmap_single(priv->pdev, dma_addr,
+                               priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
+                       rx_buf[i] = NULL;
+                       desc->host_addr = cpu_to_le32(0);
+               } else {
+                       skb_trim(skb, 0);
+                       pci_dma_sync_single_for_device(priv->pdev, dma_addr,
+                               priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
+                       desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
+               }
+
+               i++;
+               i %= ring_limit;
+       }
+
+       p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf, *index);
+}
+
+static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
+       int ring_index, struct p54p_desc *ring, u32 ring_limit,
+       struct sk_buff **tx_buf)
+{
+       struct p54p_priv *priv = dev->priv;
+       struct p54p_ring_control *ring_control = priv->ring_control;
+       struct p54p_desc *desc;
+       struct sk_buff *skb;
+       u32 idx, i;
+
+       i = (*index) % ring_limit;
+       (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
+       idx %= ring_limit;
+
+       while (i != idx) {
+               desc = &ring[i];
+
+               skb = tx_buf[i];
+               tx_buf[i] = NULL;
+
+               pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
+                                le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
+
+               desc->host_addr = 0;
+               desc->device_addr = 0;
+               desc->len = 0;
+               desc->flags = 0;
+
+               if (skb && FREE_AFTER_TX(skb))
+                       p54_free_skb(dev, skb);
+
+               i++;
+               i %= ring_limit;
+       }
+}
+
+static void p54p_tasklet(unsigned long dev_id)
+{
+       struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id;
+       struct p54p_priv *priv = dev->priv;
+       struct p54p_ring_control *ring_control = priv->ring_control;
+
+       p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt,
+                          ARRAY_SIZE(ring_control->tx_mgmt),
+                          priv->tx_buf_mgmt);
+
+       p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data,
+                          ARRAY_SIZE(ring_control->tx_data),
+                          priv->tx_buf_data);
+
+       p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt,
+               ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt);
+
+       p54p_check_rx_ring(dev, &priv->rx_idx_data, 0, ring_control->rx_data,
+               ARRAY_SIZE(ring_control->rx_data), priv->rx_buf_data);
+
+       wmb();
+       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+}
+
+static irqreturn_t p54p_interrupt(int irq, void *dev_id)
+{
+       struct ieee80211_hw *dev = dev_id;
+       struct p54p_priv *priv = dev->priv;
+       __le32 reg;
+
+       reg = P54P_READ(int_ident);
+       if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) {
+               goto out;
+       }
+       P54P_WRITE(int_ack, reg);
+
+       reg &= P54P_READ(int_enable);
+
+       if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE))
+               tasklet_schedule(&priv->tasklet);
+       else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
+               complete(&priv->boot_comp);
+
+out:
+       return reg ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       unsigned long flags;
+       struct p54p_priv *priv = dev->priv;
+       struct p54p_ring_control *ring_control = priv->ring_control;
+       struct p54p_desc *desc;
+       dma_addr_t mapping;
+       u32 idx, i;
+
+       spin_lock_irqsave(&priv->lock, flags);
+       idx = le32_to_cpu(ring_control->host_idx[1]);
+       i = idx % ARRAY_SIZE(ring_control->tx_data);
+
+       mapping = pci_map_single(priv->pdev, skb->data, skb->len,
+                                PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(priv->pdev, mapping)) {
+               spin_unlock_irqrestore(&priv->lock, flags);
+               p54_free_skb(dev, skb);
+               dev_err(&priv->pdev->dev, "TX DMA mapping error\n");
+               return ;
+       }
+       priv->tx_buf_data[i] = skb;
+
+       desc = &ring_control->tx_data[i];
+       desc->host_addr = cpu_to_le32(mapping);
+       desc->device_addr = ((struct p54_hdr *)skb->data)->req_id;
+       desc->len = cpu_to_le16(skb->len);
+       desc->flags = 0;
+
+       wmb();
+       ring_control->host_idx[1] = cpu_to_le32(idx + 1);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+       P54P_READ(dev_int);
+}
+
+static void p54p_stop(struct ieee80211_hw *dev)
+{
+       struct p54p_priv *priv = dev->priv;
+       struct p54p_ring_control *ring_control = priv->ring_control;
+       unsigned int i;
+       struct p54p_desc *desc;
+
+       P54P_WRITE(int_enable, cpu_to_le32(0));
+       P54P_READ(int_enable);
+       udelay(10);
+
+       free_irq(priv->pdev->irq, dev);
+
+       tasklet_kill(&priv->tasklet);
+
+       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+       for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) {
+               desc = &ring_control->rx_data[i];
+               if (desc->host_addr)
+                       pci_unmap_single(priv->pdev,
+                                        le32_to_cpu(desc->host_addr),
+                                        priv->common.rx_mtu + 32,
+                                        PCI_DMA_FROMDEVICE);
+               kfree_skb(priv->rx_buf_data[i]);
+               priv->rx_buf_data[i] = NULL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) {
+               desc = &ring_control->rx_mgmt[i];
+               if (desc->host_addr)
+                       pci_unmap_single(priv->pdev,
+                                        le32_to_cpu(desc->host_addr),
+                                        priv->common.rx_mtu + 32,
+                                        PCI_DMA_FROMDEVICE);
+               kfree_skb(priv->rx_buf_mgmt[i]);
+               priv->rx_buf_mgmt[i] = NULL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) {
+               desc = &ring_control->tx_data[i];
+               if (desc->host_addr)
+                       pci_unmap_single(priv->pdev,
+                                        le32_to_cpu(desc->host_addr),
+                                        le16_to_cpu(desc->len),
+                                        PCI_DMA_TODEVICE);
+
+               p54_free_skb(dev, priv->tx_buf_data[i]);
+               priv->tx_buf_data[i] = NULL;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) {
+               desc = &ring_control->tx_mgmt[i];
+               if (desc->host_addr)
+                       pci_unmap_single(priv->pdev,
+                                        le32_to_cpu(desc->host_addr),
+                                        le16_to_cpu(desc->len),
+                                        PCI_DMA_TODEVICE);
+
+               p54_free_skb(dev, priv->tx_buf_mgmt[i]);
+               priv->tx_buf_mgmt[i] = NULL;
+       }
+
+       memset(ring_control, 0, sizeof(*ring_control));
+}
+
+static int p54p_open(struct ieee80211_hw *dev)
+{
+       struct p54p_priv *priv = dev->priv;
+       int err;
+       long timeout;
+
+       init_completion(&priv->boot_comp);
+       err = request_irq(priv->pdev->irq, p54p_interrupt,
+                         IRQF_SHARED, "p54pci", dev);
+       if (err) {
+               dev_err(&priv->pdev->dev, "failed to register IRQ handler\n");
+               return err;
+       }
+
+       memset(priv->ring_control, 0, sizeof(*priv->ring_control));
+       err = p54p_upload_firmware(dev);
+       if (err) {
+               free_irq(priv->pdev->irq, dev);
+               return err;
+       }
+       priv->rx_idx_data = priv->tx_idx_data = 0;
+       priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
+
+       p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data,
+               ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data, 0);
+
+       p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
+               ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt, 0);
+
+       P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
+       P54P_READ(ring_control_base);
+       wmb();
+       udelay(10);
+
+       P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+       P54P_READ(int_enable);
+       wmb();
+       udelay(10);
+
+       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
+       P54P_READ(dev_int);
+
+       timeout = wait_for_completion_interruptible_timeout(
+                       &priv->boot_comp, HZ);
+       if (timeout <= 0) {
+               wiphy_err(dev->wiphy, "Cannot boot firmware!\n");
+               p54p_stop(dev);
+               return timeout ? -ERESTARTSYS : -ETIMEDOUT;
+       }
+
+       P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
+       P54P_READ(int_enable);
+       wmb();
+       udelay(10);
+
+       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
+       P54P_READ(dev_int);
+       wmb();
+       udelay(10);
+
+       return 0;
+}
+
+static void p54p_firmware_step2(const struct firmware *fw,
+                               void *context)
+{
+       struct p54p_priv *priv = context;
+       struct ieee80211_hw *dev = priv->common.hw;
+       struct pci_dev *pdev = priv->pdev;
+       int err;
+
+       if (!fw) {
+               dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
+               err = -ENOENT;
+               goto out;
+       }
+
+       priv->firmware = fw;
+
+       err = p54p_open(dev);
+       if (err)
+               goto out;
+       err = p54_read_eeprom(dev);
+       p54p_stop(dev);
+       if (err)
+               goto out;
+
+       err = p54_register_common(dev, &pdev->dev);
+       if (err)
+               goto out;
+
+out:
+
+       complete(&priv->fw_loaded);
+
+       if (err) {
+               struct device *parent = pdev->dev.parent;
+
+               if (parent)
+                       device_lock(parent);
+
+               /*
+                * This will indirectly result in a call to p54p_remove.
+                * Hence, we don't need to bother with freeing any
+                * allocated ressources at all.
+                */
+               device_release_driver(&pdev->dev);
+
+               if (parent)
+                       device_unlock(parent);
+       }
+
+       pci_dev_put(pdev);
+}
+
+static int p54p_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *id)
+{
+       struct p54p_priv *priv;
+       struct ieee80211_hw *dev;
+       unsigned long mem_addr, mem_len;
+       int err;
+
+       pci_dev_get(pdev);
+       err = pci_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "Cannot enable new PCI device\n");
+               return err;
+       }
+
+       mem_addr = pci_resource_start(pdev, 0);
+       mem_len = pci_resource_len(pdev, 0);
+       if (mem_len < sizeof(struct p54p_csr)) {
+               dev_err(&pdev->dev, "Too short PCI resources\n");
+               err = -ENODEV;
+               goto err_disable_dev;
+       }
+
+       err = pci_request_regions(pdev, "p54pci");
+       if (err) {
+               dev_err(&pdev->dev, "Cannot obtain PCI resources\n");
+               goto err_disable_dev;
+       }
+
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (!err)
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (err) {
+               dev_err(&pdev->dev, "No suitable DMA available\n");
+               goto err_free_reg;
+       }
+
+       pci_set_master(pdev);
+       pci_try_set_mwi(pdev);
+
+       pci_write_config_byte(pdev, 0x40, 0);
+       pci_write_config_byte(pdev, 0x41, 0);
+
+       dev = p54_init_common(sizeof(*priv));
+       if (!dev) {
+               dev_err(&pdev->dev, "ieee80211 alloc failed\n");
+               err = -ENOMEM;
+               goto err_free_reg;
+       }
+
+       priv = dev->priv;
+       priv->pdev = pdev;
+
+       init_completion(&priv->fw_loaded);
+       SET_IEEE80211_DEV(dev, &pdev->dev);
+       pci_set_drvdata(pdev, dev);
+
+       priv->map = ioremap(mem_addr, mem_len);
+       if (!priv->map) {
+               dev_err(&pdev->dev, "Cannot map device memory\n");
+               err = -ENOMEM;
+               goto err_free_dev;
+       }
+
+       priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control),
+                                                 &priv->ring_control_dma);
+       if (!priv->ring_control) {
+               dev_err(&pdev->dev, "Cannot allocate rings\n");
+               err = -ENOMEM;
+               goto err_iounmap;
+       }
+       priv->common.open = p54p_open;
+       priv->common.stop = p54p_stop;
+       priv->common.tx = p54p_tx;
+
+       spin_lock_init(&priv->lock);
+       tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);
+
+       err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci",
+                                     &priv->pdev->dev, GFP_KERNEL,
+                                     priv, p54p_firmware_step2);
+       if (!err)
+               return 0;
+
+       pci_free_consistent(pdev, sizeof(*priv->ring_control),
+                           priv->ring_control, priv->ring_control_dma);
+
+ err_iounmap:
+       iounmap(priv->map);
+
+ err_free_dev:
+       p54_free_common(dev);
+
+ err_free_reg:
+       pci_release_regions(pdev);
+ err_disable_dev:
+       pci_disable_device(pdev);
+       pci_dev_put(pdev);
+       return err;
+}
+
+static void p54p_remove(struct pci_dev *pdev)
+{
+       struct ieee80211_hw *dev = pci_get_drvdata(pdev);
+       struct p54p_priv *priv;
+
+       if (!dev)
+               return;
+
+       priv = dev->priv;
+       wait_for_completion(&priv->fw_loaded);
+       p54_unregister_common(dev);
+       release_firmware(priv->firmware);
+       pci_free_consistent(pdev, sizeof(*priv->ring_control),
+                           priv->ring_control, priv->ring_control_dma);
+       iounmap(priv->map);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       p54_free_common(dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int p54p_suspend(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+
+       pci_save_state(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+       pci_disable_device(pdev);
+       return 0;
+}
+
+static int p54p_resume(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       int err;
+
+       err = pci_reenable_device(pdev);
+       if (err)
+               return err;
+       return pci_set_power_state(pdev, PCI_D0);
+}
+
+static SIMPLE_DEV_PM_OPS(p54pci_pm_ops, p54p_suspend, p54p_resume);
+
+#define P54P_PM_OPS (&p54pci_pm_ops)
+#else
+#define P54P_PM_OPS (NULL)
+#endif /* CONFIG_PM_SLEEP */
+
+static struct pci_driver p54p_driver = {
+       .name           = "p54pci",
+       .id_table       = p54p_table,
+       .probe          = p54p_probe,
+       .remove         = p54p_remove,
+       .driver.pm      = P54P_PM_OPS,
+};
+
+module_pci_driver(p54p_driver);
diff --git a/drivers/net/wireless/intersil/p54/p54pci.h b/drivers/net/wireless/intersil/p54/p54pci.h
new file mode 100644 (file)
index 0000000..68405c1
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef P54PCI_H
+#define P54PCI_H
+#include <linux/interrupt.h>
+
+/*
+ * Defines for PCI based mac80211 Prism54 driver
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* Device Interrupt register bits */
+#define ISL38XX_DEV_INT_RESET                   0x0001
+#define ISL38XX_DEV_INT_UPDATE                  0x0002
+#define ISL38XX_DEV_INT_WAKEUP                  0x0008
+#define ISL38XX_DEV_INT_SLEEP                   0x0010
+#define ISL38XX_DEV_INT_ABORT                   0x0020
+/* these two only used in USB */
+#define ISL38XX_DEV_INT_DATA                    0x0040
+#define ISL38XX_DEV_INT_MGMT                    0x0080
+
+#define ISL38XX_DEV_INT_PCIUART_CTS             0x4000
+#define ISL38XX_DEV_INT_PCIUART_DR              0x8000
+
+/* Interrupt Identification/Acknowledge/Enable register bits */
+#define ISL38XX_INT_IDENT_UPDATE               0x0002
+#define ISL38XX_INT_IDENT_INIT                 0x0004
+#define ISL38XX_INT_IDENT_WAKEUP               0x0008
+#define ISL38XX_INT_IDENT_SLEEP                        0x0010
+#define ISL38XX_INT_IDENT_PCIUART_CTS          0x4000
+#define ISL38XX_INT_IDENT_PCIUART_DR           0x8000
+
+/* Control/Status register bits */
+#define ISL38XX_CTRL_STAT_SLEEPMODE            0x00000200
+#define ISL38XX_CTRL_STAT_CLKRUN               0x00800000
+#define ISL38XX_CTRL_STAT_RESET                        0x10000000
+#define ISL38XX_CTRL_STAT_RAMBOOT              0x20000000
+#define ISL38XX_CTRL_STAT_STARTHALTED          0x40000000
+#define ISL38XX_CTRL_STAT_HOST_OVERRIDE                0x80000000
+
+struct p54p_csr {
+       __le32 dev_int;
+       u8 unused_1[12];
+       __le32 int_ident;
+       __le32 int_ack;
+       __le32 int_enable;
+       u8 unused_2[4];
+       union {
+               __le32 ring_control_base;
+               __le32 gen_purp_com[2];
+       };
+       u8 unused_3[8];
+       __le32 direct_mem_base;
+       u8 unused_4[44];
+       __le32 dma_addr;
+       __le32 dma_len;
+       __le32 dma_ctrl;
+       u8 unused_5[12];
+       __le32 ctrl_stat;
+       u8 unused_6[1924];
+       u8 cardbus_cis[0x800];
+       u8 direct_mem_win[0x1000];
+} __packed;
+
+/* usb backend only needs the register defines above */
+#ifndef P54USB_H
+struct p54p_desc {
+       __le32 host_addr;
+       __le32 device_addr;
+       __le16 len;
+       __le16 flags;
+} __packed;
+
+struct p54p_ring_control {
+       __le32 host_idx[4];
+       __le32 device_idx[4];
+       struct p54p_desc rx_data[8];
+       struct p54p_desc tx_data[32];
+       struct p54p_desc rx_mgmt[4];
+       struct p54p_desc tx_mgmt[4];
+} __packed;
+
+#define P54P_READ(r) (__force __le32)__raw_readl(&priv->map->r)
+#define P54P_WRITE(r, val) __raw_writel((__force u32)(__le32)(val), &priv->map->r)
+
+struct p54p_priv {
+       struct p54_common common;
+       struct pci_dev *pdev;
+       struct p54p_csr __iomem *map;
+       struct tasklet_struct tasklet;
+       const struct firmware *firmware;
+       spinlock_t lock;
+       struct p54p_ring_control *ring_control;
+       dma_addr_t ring_control_dma;
+       u32 rx_idx_data, tx_idx_data;
+       u32 rx_idx_mgmt, tx_idx_mgmt;
+       struct sk_buff *rx_buf_data[8];
+       struct sk_buff *rx_buf_mgmt[4];
+       struct sk_buff *tx_buf_data[32];
+       struct sk_buff *tx_buf_mgmt[4];
+       struct completion boot_comp;
+       struct completion fw_loaded;
+};
+
+#endif /* P54USB_H */
+#endif /* P54PCI_H */
diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c
new file mode 100644 (file)
index 0000000..7ab2f43
--- /dev/null
@@ -0,0 +1,720 @@
+/*
+ * Copyright (C) 2008 Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008       Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This driver is a port from stlc45xx:
+ *     Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/spi/spi.h>
+#include <linux/etherdevice.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include "p54spi.h"
+#include "p54.h"
+
+#include "lmac.h"
+
+#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
+#include "p54spi_eeprom.h"
+#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
+
+MODULE_FIRMWARE("3826.arm");
+
+/* gpios should be handled in board files and provided via platform data,
+ * but because it's currently impossible for p54spi to have a header file
+ * in include/linux, let's use module paramaters for now
+ */
+
+static int p54spi_gpio_power = 97;
+module_param(p54spi_gpio_power, int, 0444);
+MODULE_PARM_DESC(p54spi_gpio_power, "gpio number for power line");
+
+static int p54spi_gpio_irq = 87;
+module_param(p54spi_gpio_irq, int, 0444);
+MODULE_PARM_DESC(p54spi_gpio_irq, "gpio number for irq line");
+
+static void p54spi_spi_read(struct p54s_priv *priv, u8 address,
+                             void *buf, size_t len)
+{
+       struct spi_transfer t[2];
+       struct spi_message m;
+       __le16 addr;
+
+       /* We first push the address */
+       addr = cpu_to_le16(address << 8 | SPI_ADRS_READ_BIT_15);
+
+       spi_message_init(&m);
+       memset(t, 0, sizeof(t));
+
+       t[0].tx_buf = &addr;
+       t[0].len = sizeof(addr);
+       spi_message_add_tail(&t[0], &m);
+
+       t[1].rx_buf = buf;
+       t[1].len = len;
+       spi_message_add_tail(&t[1], &m);
+
+       spi_sync(priv->spi, &m);
+}
+
+
+static void p54spi_spi_write(struct p54s_priv *priv, u8 address,
+                            const void *buf, size_t len)
+{
+       struct spi_transfer t[3];
+       struct spi_message m;
+       __le16 addr;
+
+       /* We first push the address */
+       addr = cpu_to_le16(address << 8);
+
+       spi_message_init(&m);
+       memset(t, 0, sizeof(t));
+
+       t[0].tx_buf = &addr;
+       t[0].len = sizeof(addr);
+       spi_message_add_tail(&t[0], &m);
+
+       t[1].tx_buf = buf;
+       t[1].len = len & ~1;
+       spi_message_add_tail(&t[1], &m);
+
+       if (len % 2) {
+               __le16 last_word;
+               last_word = cpu_to_le16(((u8 *)buf)[len - 1]);
+
+               t[2].tx_buf = &last_word;
+               t[2].len = sizeof(last_word);
+               spi_message_add_tail(&t[2], &m);
+       }
+
+       spi_sync(priv->spi, &m);
+}
+
+static u32 p54spi_read32(struct p54s_priv *priv, u8 addr)
+{
+       __le32 val;
+
+       p54spi_spi_read(priv, addr, &val, sizeof(val));
+
+       return le32_to_cpu(val);
+}
+
+static inline void p54spi_write16(struct p54s_priv *priv, u8 addr, __le16 val)
+{
+       p54spi_spi_write(priv, addr, &val, sizeof(val));
+}
+
+static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val)
+{
+       p54spi_spi_write(priv, addr, &val, sizeof(val));
+}
+
+static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits)
+{
+       int i;
+
+       for (i = 0; i < 2000; i++) {
+               u32 buffer = p54spi_read32(priv, reg);
+               if ((buffer & bits) == bits)
+                       return 1;
+       }
+       return 0;
+}
+
+static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
+                               const void *buf, size_t len)
+{
+       if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) {
+               dev_err(&priv->spi->dev, "spi_write_dma not allowed "
+                       "to DMA write.\n");
+               return -EAGAIN;
+       }
+
+       p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL,
+                      cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE));
+
+       p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len));
+       p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base);
+       p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len);
+       return 0;
+}
+
+static int p54spi_request_firmware(struct ieee80211_hw *dev)
+{
+       struct p54s_priv *priv = dev->priv;
+       int ret;
+
+       /* FIXME: should driver use it's own struct device? */
+       ret = request_firmware(&priv->firmware, "3826.arm", &priv->spi->dev);
+
+       if (ret < 0) {
+               dev_err(&priv->spi->dev, "request_firmware() failed: %d", ret);
+               return ret;
+       }
+
+       ret = p54_parse_firmware(dev, priv->firmware);
+       if (ret) {
+               release_firmware(priv->firmware);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int p54spi_request_eeprom(struct ieee80211_hw *dev)
+{
+       struct p54s_priv *priv = dev->priv;
+       const struct firmware *eeprom;
+       int ret;
+
+       /* allow users to customize their eeprom.
+        */
+
+       ret = request_firmware_direct(&eeprom, "3826.eeprom", &priv->spi->dev);
+       if (ret < 0) {
+#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
+               dev_info(&priv->spi->dev, "loading default eeprom...\n");
+               ret = p54_parse_eeprom(dev, (void *) p54spi_eeprom,
+                                      sizeof(p54spi_eeprom));
+#else
+               dev_err(&priv->spi->dev, "Failed to request user eeprom\n");
+#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
+       } else {
+               dev_info(&priv->spi->dev, "loading user eeprom...\n");
+               ret = p54_parse_eeprom(dev, (void *) eeprom->data,
+                                      (int)eeprom->size);
+               release_firmware(eeprom);
+       }
+       return ret;
+}
+
+static int p54spi_upload_firmware(struct ieee80211_hw *dev)
+{
+       struct p54s_priv *priv = dev->priv;
+       unsigned long fw_len, _fw_len;
+       unsigned int offset = 0;
+       int err = 0;
+       u8 *fw;
+
+       fw_len = priv->firmware->size;
+       fw = kmemdup(priv->firmware->data, fw_len, GFP_KERNEL);
+       if (!fw)
+               return -ENOMEM;
+
+       /* stop the device */
+       p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
+                      SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET |
+                      SPI_CTRL_STAT_START_HALTED));
+
+       msleep(TARGET_BOOT_SLEEP);
+
+       p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
+                      SPI_CTRL_STAT_HOST_OVERRIDE |
+                      SPI_CTRL_STAT_START_HALTED));
+
+       msleep(TARGET_BOOT_SLEEP);
+
+       while (fw_len > 0) {
+               _fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE);
+
+               err = p54spi_spi_write_dma(priv, cpu_to_le32(
+                                          ISL38XX_DEV_FIRMWARE_ADDR + offset),
+                                          (fw + offset), _fw_len);
+               if (err < 0)
+                       goto out;
+
+               fw_len -= _fw_len;
+               offset += _fw_len;
+       }
+
+       BUG_ON(fw_len != 0);
+
+       /* enable host interrupts */
+       p54spi_write32(priv, SPI_ADRS_HOST_INT_EN,
+                      cpu_to_le32(SPI_HOST_INTS_DEFAULT));
+
+       /* boot the device */
+       p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
+                      SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET |
+                      SPI_CTRL_STAT_RAM_BOOT));
+
+       msleep(TARGET_BOOT_SLEEP);
+
+       p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
+                      SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT));
+       msleep(TARGET_BOOT_SLEEP);
+
+out:
+       kfree(fw);
+       return err;
+}
+
+static void p54spi_power_off(struct p54s_priv *priv)
+{
+       disable_irq(gpio_to_irq(p54spi_gpio_irq));
+       gpio_set_value(p54spi_gpio_power, 0);
+}
+
+static void p54spi_power_on(struct p54s_priv *priv)
+{
+       gpio_set_value(p54spi_gpio_power, 1);
+       enable_irq(gpio_to_irq(p54spi_gpio_irq));
+
+       /* need to wait a while before device can be accessed, the length
+        * is just a guess
+        */
+       msleep(10);
+}
+
+static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val)
+{
+       p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val));
+}
+
+static int p54spi_wakeup(struct p54s_priv *priv)
+{
+       /* wake the chip */
+       p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS,
+                      cpu_to_le32(SPI_TARGET_INT_WAKEUP));
+
+       /* And wait for the READY interrupt */
+       if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
+                            SPI_HOST_INT_READY)) {
+               dev_err(&priv->spi->dev, "INT_READY timeout\n");
+               return -EBUSY;
+       }
+
+       p54spi_int_ack(priv, SPI_HOST_INT_READY);
+       return 0;
+}
+
+static inline void p54spi_sleep(struct p54s_priv *priv)
+{
+       p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS,
+                      cpu_to_le32(SPI_TARGET_INT_SLEEP));
+}
+
+static void p54spi_int_ready(struct p54s_priv *priv)
+{
+       p54spi_write32(priv, SPI_ADRS_HOST_INT_EN, cpu_to_le32(
+                      SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE));
+
+       switch (priv->fw_state) {
+       case FW_STATE_BOOTING:
+               priv->fw_state = FW_STATE_READY;
+               complete(&priv->fw_comp);
+               break;
+       case FW_STATE_RESETTING:
+               priv->fw_state = FW_STATE_READY;
+               /* TODO: reinitialize state */
+               break;
+       default:
+               break;
+       }
+}
+
+static int p54spi_rx(struct p54s_priv *priv)
+{
+       struct sk_buff *skb;
+       u16 len;
+       u16 rx_head[2];
+#define READAHEAD_SZ (sizeof(rx_head)-sizeof(u16))
+
+       if (p54spi_wakeup(priv) < 0)
+               return -EBUSY;
+
+       /* Read data size and first data word in one SPI transaction
+        * This is workaround for firmware/DMA bug,
+        * when first data word gets lost under high load.
+        */
+       p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, rx_head, sizeof(rx_head));
+       len = rx_head[0];
+
+       if (len == 0) {
+               p54spi_sleep(priv);
+               dev_err(&priv->spi->dev, "rx request of zero bytes\n");
+               return 0;
+       }
+
+       /* Firmware may insert up to 4 padding bytes after the lmac header,
+        * but it does not amend the size of SPI data transfer.
+        * Such packets has correct data size in header, thus referencing
+        * past the end of allocated skb. Reserve extra 4 bytes for this case
+        */
+       skb = dev_alloc_skb(len + 4);
+       if (!skb) {
+               p54spi_sleep(priv);
+               dev_err(&priv->spi->dev, "could not alloc skb");
+               return -ENOMEM;
+       }
+
+       if (len <= READAHEAD_SZ) {
+               memcpy(skb_put(skb, len), rx_head + 1, len);
+       } else {
+               memcpy(skb_put(skb, READAHEAD_SZ), rx_head + 1, READAHEAD_SZ);
+               p54spi_spi_read(priv, SPI_ADRS_DMA_DATA,
+                               skb_put(skb, len - READAHEAD_SZ),
+                               len - READAHEAD_SZ);
+       }
+       p54spi_sleep(priv);
+       /* Put additional bytes to compensate for the possible
+        * alignment-caused truncation
+        */
+       skb_put(skb, 4);
+
+       if (p54_rx(priv->hw, skb) == 0)
+               dev_kfree_skb(skb);
+
+       return 0;
+}
+
+
+static irqreturn_t p54spi_interrupt(int irq, void *config)
+{
+       struct spi_device *spi = config;
+       struct p54s_priv *priv = spi_get_drvdata(spi);
+
+       ieee80211_queue_work(priv->hw, &priv->work);
+
+       return IRQ_HANDLED;
+}
+
+static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       int ret = 0;
+
+       if (p54spi_wakeup(priv) < 0)
+               return -EBUSY;
+
+       ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len);
+       if (ret < 0)
+               goto out;
+
+       if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
+                            SPI_HOST_INT_WR_READY)) {
+               dev_err(&priv->spi->dev, "WR_READY timeout\n");
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       p54spi_int_ack(priv, SPI_HOST_INT_WR_READY);
+
+       if (FREE_AFTER_TX(skb))
+               p54_free_skb(priv->hw, skb);
+out:
+       p54spi_sleep(priv);
+       return ret;
+}
+
+static int p54spi_wq_tx(struct p54s_priv *priv)
+{
+       struct p54s_tx_info *entry;
+       struct sk_buff *skb;
+       struct ieee80211_tx_info *info;
+       struct p54_tx_info *minfo;
+       struct p54s_tx_info *dinfo;
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&priv->tx_lock, flags);
+
+       while (!list_empty(&priv->tx_pending)) {
+               entry = list_entry(priv->tx_pending.next,
+                                  struct p54s_tx_info, tx_list);
+
+               list_del_init(&entry->tx_list);
+
+               spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+               dinfo = container_of((void *) entry, struct p54s_tx_info,
+                                    tx_list);
+               minfo = container_of((void *) dinfo, struct p54_tx_info,
+                                    data);
+               info = container_of((void *) minfo, struct ieee80211_tx_info,
+                                   rate_driver_data);
+               skb = container_of((void *) info, struct sk_buff, cb);
+
+               ret = p54spi_tx_frame(priv, skb);
+
+               if (ret < 0) {
+                       p54_free_skb(priv->hw, skb);
+                       return ret;
+               }
+
+               spin_lock_irqsave(&priv->tx_lock, flags);
+       }
+       spin_unlock_irqrestore(&priv->tx_lock, flags);
+       return ret;
+}
+
+static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       struct p54s_priv *priv = dev->priv;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct p54_tx_info *mi = (struct p54_tx_info *) info->rate_driver_data;
+       struct p54s_tx_info *di = (struct p54s_tx_info *) mi->data;
+       unsigned long flags;
+
+       BUILD_BUG_ON(sizeof(*di) > sizeof((mi->data)));
+
+       spin_lock_irqsave(&priv->tx_lock, flags);
+       list_add_tail(&di->tx_list, &priv->tx_pending);
+       spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+       ieee80211_queue_work(priv->hw, &priv->work);
+}
+
+static void p54spi_work(struct work_struct *work)
+{
+       struct p54s_priv *priv = container_of(work, struct p54s_priv, work);
+       u32 ints;
+       int ret;
+
+       mutex_lock(&priv->mutex);
+
+       if (priv->fw_state == FW_STATE_OFF)
+               goto out;
+
+       ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
+
+       if (ints & SPI_HOST_INT_READY) {
+               p54spi_int_ready(priv);
+               p54spi_int_ack(priv, SPI_HOST_INT_READY);
+       }
+
+       if (priv->fw_state != FW_STATE_READY)
+               goto out;
+
+       if (ints & SPI_HOST_INT_UPDATE) {
+               p54spi_int_ack(priv, SPI_HOST_INT_UPDATE);
+               ret = p54spi_rx(priv);
+               if (ret < 0)
+                       goto out;
+       }
+       if (ints & SPI_HOST_INT_SW_UPDATE) {
+               p54spi_int_ack(priv, SPI_HOST_INT_SW_UPDATE);
+               ret = p54spi_rx(priv);
+               if (ret < 0)
+                       goto out;
+       }
+
+       ret = p54spi_wq_tx(priv);
+out:
+       mutex_unlock(&priv->mutex);
+}
+
+static int p54spi_op_start(struct ieee80211_hw *dev)
+{
+       struct p54s_priv *priv = dev->priv;
+       unsigned long timeout;
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&priv->mutex)) {
+               ret = -EINTR;
+               goto out;
+       }
+
+       priv->fw_state = FW_STATE_BOOTING;
+
+       p54spi_power_on(priv);
+
+       ret = p54spi_upload_firmware(dev);
+       if (ret < 0) {
+               p54spi_power_off(priv);
+               goto out_unlock;
+       }
+
+       mutex_unlock(&priv->mutex);
+
+       timeout = msecs_to_jiffies(2000);
+       timeout = wait_for_completion_interruptible_timeout(&priv->fw_comp,
+                                                           timeout);
+       if (!timeout) {
+               dev_err(&priv->spi->dev, "firmware boot failed");
+               p54spi_power_off(priv);
+               ret = -1;
+               goto out;
+       }
+
+       if (mutex_lock_interruptible(&priv->mutex)) {
+               ret = -EINTR;
+               p54spi_power_off(priv);
+               goto out;
+       }
+
+       WARN_ON(priv->fw_state != FW_STATE_READY);
+
+out_unlock:
+       mutex_unlock(&priv->mutex);
+
+out:
+       return ret;
+}
+
+static void p54spi_op_stop(struct ieee80211_hw *dev)
+{
+       struct p54s_priv *priv = dev->priv;
+       unsigned long flags;
+
+       mutex_lock(&priv->mutex);
+       WARN_ON(priv->fw_state != FW_STATE_READY);
+
+       p54spi_power_off(priv);
+       spin_lock_irqsave(&priv->tx_lock, flags);
+       INIT_LIST_HEAD(&priv->tx_pending);
+       spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+       priv->fw_state = FW_STATE_OFF;
+       mutex_unlock(&priv->mutex);
+
+       cancel_work_sync(&priv->work);
+}
+
+static int p54spi_probe(struct spi_device *spi)
+{
+       struct p54s_priv *priv = NULL;
+       struct ieee80211_hw *hw;
+       int ret = -EINVAL;
+
+       hw = p54_init_common(sizeof(*priv));
+       if (!hw) {
+               dev_err(&spi->dev, "could not alloc ieee80211_hw");
+               return -ENOMEM;
+       }
+
+       priv = hw->priv;
+       priv->hw = hw;
+       spi_set_drvdata(spi, priv);
+       priv->spi = spi;
+
+       spi->bits_per_word = 16;
+       spi->max_speed_hz = 24000000;
+
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               dev_err(&priv->spi->dev, "spi_setup failed");
+               goto err_free;
+       }
+
+       ret = gpio_request(p54spi_gpio_power, "p54spi power");
+       if (ret < 0) {
+               dev_err(&priv->spi->dev, "power GPIO request failed: %d", ret);
+               goto err_free;
+       }
+
+       ret = gpio_request(p54spi_gpio_irq, "p54spi irq");
+       if (ret < 0) {
+               dev_err(&priv->spi->dev, "irq GPIO request failed: %d", ret);
+               goto err_free_gpio_power;
+       }
+
+       gpio_direction_output(p54spi_gpio_power, 0);
+       gpio_direction_input(p54spi_gpio_irq);
+
+       ret = request_irq(gpio_to_irq(p54spi_gpio_irq),
+                         p54spi_interrupt, 0, "p54spi",
+                         priv->spi);
+       if (ret < 0) {
+               dev_err(&priv->spi->dev, "request_irq() failed");
+               goto err_free_gpio_irq;
+       }
+
+       irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING);
+
+       disable_irq(gpio_to_irq(p54spi_gpio_irq));
+
+       INIT_WORK(&priv->work, p54spi_work);
+       init_completion(&priv->fw_comp);
+       INIT_LIST_HEAD(&priv->tx_pending);
+       mutex_init(&priv->mutex);
+       spin_lock_init(&priv->tx_lock);
+       SET_IEEE80211_DEV(hw, &spi->dev);
+       priv->common.open = p54spi_op_start;
+       priv->common.stop = p54spi_op_stop;
+       priv->common.tx = p54spi_op_tx;
+
+       ret = p54spi_request_firmware(hw);
+       if (ret < 0)
+               goto err_free_common;
+
+       ret = p54spi_request_eeprom(hw);
+       if (ret)
+               goto err_free_common;
+
+       ret = p54_register_common(hw, &priv->spi->dev);
+       if (ret)
+               goto err_free_common;
+
+       return 0;
+
+err_free_common:
+       free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
+err_free_gpio_irq:
+       gpio_free(p54spi_gpio_irq);
+err_free_gpio_power:
+       gpio_free(p54spi_gpio_power);
+err_free:
+       p54_free_common(priv->hw);
+       return ret;
+}
+
+static int p54spi_remove(struct spi_device *spi)
+{
+       struct p54s_priv *priv = spi_get_drvdata(spi);
+
+       p54_unregister_common(priv->hw);
+
+       free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
+
+       gpio_free(p54spi_gpio_power);
+       gpio_free(p54spi_gpio_irq);
+       release_firmware(priv->firmware);
+
+       mutex_destroy(&priv->mutex);
+
+       p54_free_common(priv->hw);
+
+       return 0;
+}
+
+
+static struct spi_driver p54spi_driver = {
+       .driver = {
+               .name           = "p54spi",
+       },
+
+       .probe          = p54spi_probe,
+       .remove         = p54spi_remove,
+};
+
+module_spi_driver(p54spi_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
+MODULE_ALIAS("spi:cx3110x");
+MODULE_ALIAS("spi:p54spi");
+MODULE_ALIAS("spi:stlc45xx");
diff --git a/drivers/net/wireless/intersil/p54/p54spi.h b/drivers/net/wireless/intersil/p54/p54spi.h
new file mode 100644 (file)
index 0000000..dfaa62a
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2008 Christian Lamparter <chunkeey@web.de>
+ *
+ * This driver is a port from stlc45xx:
+ *     Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef P54SPI_H
+#define P54SPI_H
+
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <net/mac80211.h>
+
+#include "p54.h"
+
+/* Bit 15 is read/write bit; ON = READ, OFF = WRITE */
+#define SPI_ADRS_READ_BIT_15           0x8000
+
+#define SPI_ADRS_ARM_INTERRUPTS                0x00
+#define SPI_ADRS_ARM_INT_EN            0x04
+
+#define SPI_ADRS_HOST_INTERRUPTS       0x08
+#define SPI_ADRS_HOST_INT_EN           0x0c
+#define SPI_ADRS_HOST_INT_ACK          0x10
+
+#define SPI_ADRS_GEN_PURP_1            0x14
+#define SPI_ADRS_GEN_PURP_2            0x18
+
+#define SPI_ADRS_DEV_CTRL_STAT         0x26    /* high word */
+
+#define SPI_ADRS_DMA_DATA              0x28
+
+#define SPI_ADRS_DMA_WRITE_CTRL                0x2c
+#define SPI_ADRS_DMA_WRITE_LEN         0x2e
+#define SPI_ADRS_DMA_WRITE_BASE                0x30
+
+#define SPI_ADRS_DMA_READ_CTRL         0x34
+#define SPI_ADRS_DMA_READ_LEN          0x36
+#define SPI_ADRS_DMA_READ_BASE         0x38
+
+#define SPI_CTRL_STAT_HOST_OVERRIDE    0x8000
+#define SPI_CTRL_STAT_START_HALTED     0x4000
+#define SPI_CTRL_STAT_RAM_BOOT         0x2000
+#define SPI_CTRL_STAT_HOST_RESET       0x1000
+#define SPI_CTRL_STAT_HOST_CPU_EN      0x0800
+
+#define SPI_DMA_WRITE_CTRL_ENABLE      0x0001
+#define SPI_DMA_READ_CTRL_ENABLE       0x0001
+#define HOST_ALLOWED                   (1 << 7)
+
+#define SPI_TIMEOUT                    100         /* msec */
+
+#define SPI_MAX_TX_PACKETS             32
+
+#define SPI_MAX_PACKET_SIZE            32767
+
+#define SPI_TARGET_INT_WAKEUP          0x00000001
+#define SPI_TARGET_INT_SLEEP           0x00000002
+#define SPI_TARGET_INT_RDDONE          0x00000004
+
+#define SPI_TARGET_INT_CTS             0x00004000
+#define SPI_TARGET_INT_DR              0x00008000
+
+#define SPI_HOST_INT_READY             0x00000001
+#define SPI_HOST_INT_WR_READY          0x00000002
+#define SPI_HOST_INT_SW_UPDATE         0x00000004
+#define SPI_HOST_INT_UPDATE            0x10000000
+
+/* clear to send */
+#define SPI_HOST_INT_CR                        0x00004000
+
+/* data ready */
+#define SPI_HOST_INT_DR                        0x00008000
+
+#define SPI_HOST_INTS_DEFAULT                                              \
+       (SPI_HOST_INT_READY | SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE)
+
+#define TARGET_BOOT_SLEEP 50
+
+struct p54s_dma_regs {
+       __le16 cmd;
+       __le16 len;
+       __le32 addr;
+} __packed;
+
+struct p54s_tx_info {
+       struct list_head tx_list;
+};
+
+struct p54s_priv {
+       /* p54_common has to be the first entry */
+       struct p54_common common;
+       struct ieee80211_hw *hw;
+       struct spi_device *spi;
+
+       struct work_struct work;
+
+       struct mutex mutex;
+       struct completion fw_comp;
+
+       spinlock_t tx_lock;
+
+       /* protected by tx_lock */
+       struct list_head tx_pending;
+
+       enum fw_state fw_state;
+       const struct firmware *firmware;
+};
+
+#endif /* P54SPI_H */
diff --git a/drivers/net/wireless/intersil/p54/p54spi_eeprom.h b/drivers/net/wireless/intersil/p54/p54spi_eeprom.h
new file mode 100644 (file)
index 0000000..0b7bfb0
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2003 Conexant Americas Inc. All Rights Reserved.
+ * Copyright (C) 2004, 2005, 2006 Nokia Corporation
+ * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008 Christian Lamparter <chunkeey@web.de>
+ *
+ * based on:
+ *  - cx3110x's pda.h from Nokia
+ *  - cx3110-transfer.log by Johannes Berg
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef P54SPI_EEPROM_H
+#define P54SPI_EEPROM_H
+
+static unsigned char p54spi_eeprom[] = {
+
+/* struct eeprom_pda_wrap */
+0x47, 0x4d, 0x55, 0xaa,        /* magic */
+0x00, 0x00,            /* pad */
+0x00, 0x00,            /* eeprom_pda_data_wrap length */
+0x00, 0x00, 0x00, 0x00,        /* arm opcode */
+
+/* bogus MAC address */
+0x04, 0x00, 0x01, 0x01,                /* PDR_MAC_ADDRESS */
+       0x00, 0x02, 0xee, 0xc0, 0xff, 0xee,
+
+/* struct bootrec_exp_if */
+0x06, 0x00, 0x01, 0x10,                /* PDR_INTERFACE_LIST */
+       0x00, 0x00,                     /* role */
+       0x0f, 0x00,                     /* if_id */
+       0x85, 0x00,                     /* variant = Longbow RF, 2GHz */
+       0x01, 0x00,                     /* btm_compat */
+       0x1f, 0x00,                     /* top_compat */
+
+0x03, 0x00, 0x02, 0x10,                /* PDR_HARDWARE_PLATFORM_COMPONENT_ID */
+       0x03, 0x20, 0x00, 0x43,
+
+/* struct pda_country[6] */
+0x0d, 0x00, 0x07, 0x10,                /* PDR_COUNTRY_LIST */
+       0x10, 0x00, 0x00, 0x00,
+       0x20, 0x00, 0x00, 0x00,
+       0x30, 0x00, 0x00, 0x00,
+       0x31, 0x00, 0x00, 0x00,
+       0x32, 0x00, 0x00, 0x00,
+       0x40, 0x00, 0x00, 0x00,
+
+/* struct pda_country */
+0x03, 0x00, 0x08, 0x10,                /* PDR_DEFAULT_COUNTRY */
+       0x30, 0x00, 0x00, 0x00,         /* ETSI */
+
+0x03, 0x00, 0x00, 0x11,                /* PDR_ANTENNA_GAIN */
+       0x08, 0x08, 0x08, 0x08,
+
+0x0a, 0x00, 0xff, 0xca,                /* PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2 */
+       0x01, 0x00, 0x0a, 0x00,
+       0x00, 0x00, 0x0a, 0x00,
+               0x85, 0x09, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00,
+
+/* struct pda_custom_wrapper */
+0x10, 0x06, 0x5d, 0xb0,                /* PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM */
+       0x0d, 0x00, 0xee, 0x00,         /* 13 entries, 238 bytes per entry */
+       0x00, 0x00, 0x16, 0x0c,         /* no offset, 3094 total len */
+               /* 2412 MHz */
+               0x6c, 0x09,
+                       0x10, 0x01, 0x9a, 0x84,
+                               0xaa, 0x8a, 0xaa, 0x8a, 0xaa, 0x8a, 0xaa, 0x8a,
+                               0x3c, 0xb6, 0x3c, 0xb6, 0x3c, 0xb6, 0x3c, 0xb6,
+                               0x3c, 0xb6, 0x3c, 0xb6, 0x3c, 0xb6, 0x3c, 0xb6,
+                       0xf0, 0x00, 0x94, 0x6c,
+                               0x99, 0x82, 0x99, 0x82, 0x99, 0x82, 0x99, 0x82,
+                               0x2b, 0xae, 0x2b, 0xae, 0x2b, 0xae, 0x2b, 0xae,
+                               0x2b, 0xae, 0x2b, 0xae, 0x2b, 0xae, 0x2b, 0xae,
+                       0xd0, 0x00, 0xaa, 0x5a,
+                               0x88, 0x7a, 0x88, 0x7a, 0x88, 0x7a, 0x88, 0x7a,
+                               0x1a, 0xa6, 0x1a, 0xa6, 0x1a, 0xa6, 0x1a, 0xa6,
+                               0x1a, 0xa6, 0x1a, 0xa6, 0x1a, 0xa6, 0x1a, 0xa6,
+                       0xa0, 0x00, 0xf3, 0x47,
+                               0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
+                               0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a,
+                               0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a,
+                       0x50, 0x00, 0x59, 0x36,
+                               0x43, 0x5a, 0x43, 0x5a, 0x43, 0x5a, 0x43, 0x5a,
+                               0xd5, 0x85, 0xd5, 0x85, 0xd5, 0x85, 0xd5, 0x85,
+                               0xd5, 0x85, 0xd5, 0x85, 0xd5, 0x85, 0xd5, 0x85,
+                       0x00, 0x00, 0xe4, 0x2d,
+                               0x18, 0x46, 0x18, 0x46, 0x18, 0x46, 0x18, 0x46,
+                               0xaa, 0x71, 0xaa, 0x71, 0xaa, 0x71, 0xaa, 0x71,
+                               0xaa, 0x71, 0xaa, 0x71, 0xaa, 0x71, 0xaa, 0x71,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2417 MHz */
+               0x71, 0x09,
+                       0x10, 0x01, 0xb9, 0x83,
+                               0x7d, 0x8a, 0x7d, 0x8a, 0x7d, 0x8a, 0x7d, 0x8a,
+                               0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6,
+                               0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6,
+                       0xf0, 0x00, 0x2e, 0x6c,
+                               0x68, 0x82, 0x68, 0x82, 0x68, 0x82, 0x68, 0x82,
+                               0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad,
+                               0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad,
+                       0xd0, 0x00, 0x8d, 0x5a,
+                               0x52, 0x7a, 0x52, 0x7a, 0x52, 0x7a, 0x52, 0x7a,
+                               0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5,
+                               0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5,
+                       0xa0, 0x00, 0x0a, 0x48,
+                               0x32, 0x6e, 0x32, 0x6e, 0x32, 0x6e, 0x32, 0x6e,
+                               0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99,
+                               0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99,
+                       0x50, 0x00, 0x7c, 0x36,
+                               0xfc, 0x59, 0xfc, 0x59, 0xfc, 0x59, 0xfc, 0x59,
+                               0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85,
+                               0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85,
+                       0x00, 0x00, 0xf5, 0x2d,
+                               0xc6, 0x45, 0xc6, 0x45, 0xc6, 0x45, 0xc6, 0x45,
+                               0x58, 0x71, 0x58, 0x71, 0x58, 0x71, 0x58, 0x71,
+                               0x58, 0x71, 0x58, 0x71, 0x58, 0x71, 0x58, 0x71,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2422 MHz */
+               0x76, 0x09,
+                       0x10, 0x01, 0xb9, 0x83,
+                               0x7d, 0x8a, 0x7d, 0x8a, 0x7d, 0x8a, 0x7d, 0x8a,
+                               0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6,
+                               0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6,
+                       0xf0, 0x00, 0x2e, 0x6c,
+                               0x68, 0x82, 0x68, 0x82, 0x68, 0x82, 0x68, 0x82,
+                               0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad,
+                               0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad,
+                       0xd0, 0x00, 0x8d, 0x5a,
+                               0x52, 0x7a, 0x52, 0x7a, 0x52, 0x7a, 0x52, 0x7a,
+                               0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5,
+                               0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5,
+                       0xa0, 0x00, 0x0a, 0x48,
+                               0x32, 0x6e, 0x32, 0x6e, 0x32, 0x6e, 0x32, 0x6e,
+                               0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99,
+                               0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99,
+                       0x50, 0x00, 0x7c, 0x36,
+                               0xfc, 0x59, 0xfc, 0x59, 0xfc, 0x59, 0xfc, 0x59,
+                               0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85,
+                               0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85,
+                       0x00, 0x00, 0xf5, 0x2d,
+                               0xc6, 0x45, 0xc6, 0x45, 0xc6, 0x45, 0xc6, 0x45,
+                               0x58, 0x71, 0x58, 0x71, 0x58, 0x71, 0x58, 0x71,
+                               0x58, 0x71, 0x58, 0x71, 0x58, 0x71, 0x58, 0x71,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2427 MHz */
+               0x7b, 0x09,
+                       0x10, 0x01, 0x48, 0x83,
+                               0x67, 0x8a, 0x67, 0x8a, 0x67, 0x8a, 0x67, 0x8a,
+                               0xf9, 0xb5, 0xf9, 0xb5, 0xf9, 0xb5, 0xf9, 0xb5,
+                               0xf9, 0xb5, 0xf9, 0xb5, 0xf9, 0xb5, 0xf9, 0xb5,
+                       0xf0, 0x00, 0xfb, 0x6b,
+                               0x50, 0x82, 0x50, 0x82, 0x50, 0x82, 0x50, 0x82,
+                               0xe2, 0xad, 0xe2, 0xad, 0xe2, 0xad, 0xe2, 0xad,
+                               0xe2, 0xad, 0xe2, 0xad, 0xe2, 0xad, 0xe2, 0xad,
+                       0xd0, 0x00, 0x7e, 0x5a,
+                               0x38, 0x7a, 0x38, 0x7a, 0x38, 0x7a, 0x38, 0x7a,
+                               0xca, 0xa5, 0xca, 0xa5, 0xca, 0xa5, 0xca, 0xa5,
+                               0xca, 0xa5, 0xca, 0xa5, 0xca, 0xa5, 0xca, 0xa5,
+                       0xa0, 0x00, 0x15, 0x48,
+                               0x14, 0x6e, 0x14, 0x6e, 0x14, 0x6e, 0x14, 0x6e,
+                               0xa6, 0x99, 0xa6, 0x99, 0xa6, 0x99, 0xa6, 0x99,
+                               0xa6, 0x99, 0xa6, 0x99, 0xa6, 0x99, 0xa6, 0x99,
+                       0x50, 0x00, 0x8e, 0x36,
+                               0xd9, 0x59, 0xd9, 0x59, 0xd9, 0x59, 0xd9, 0x59,
+                               0x6b, 0x85, 0x6b, 0x85, 0x6b, 0x85, 0x6b, 0x85,
+                               0x6b, 0x85, 0x6b, 0x85, 0x6b, 0x85, 0x6b, 0x85,
+                       0x00, 0x00, 0xfe, 0x2d,
+                               0x9d, 0x45, 0x9d, 0x45, 0x9d, 0x45, 0x9d, 0x45,
+                               0x2f, 0x71, 0x2f, 0x71, 0x2f, 0x71, 0x2f, 0x71,
+                               0x2f, 0x71, 0x2f, 0x71, 0x2f, 0x71, 0x2f, 0x71,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2432 MHz */
+               0x80, 0x09,
+                       0x10, 0x01, 0xd7, 0x82,
+                               0x51, 0x8a, 0x51, 0x8a, 0x51, 0x8a, 0x51, 0x8a,
+                               0xe3, 0xb5, 0xe3, 0xb5, 0xe3, 0xb5, 0xe3, 0xb5,
+                               0xe3, 0xb5, 0xe3, 0xb5, 0xe3, 0xb5, 0xe3, 0xb5,
+                       0xf0, 0x00, 0xc8, 0x6b,
+                               0x37, 0x82, 0x37, 0x82, 0x37, 0x82, 0x37, 0x82,
+                               0xc9, 0xad, 0xc9, 0xad, 0xc9, 0xad, 0xc9, 0xad,
+                               0xc9, 0xad, 0xc9, 0xad, 0xc9, 0xad, 0xc9, 0xad,
+                       0xd0, 0x00, 0x6f, 0x5a,
+                               0x1d, 0x7a, 0x1d, 0x7a, 0x1d, 0x7a, 0x1d, 0x7a,
+                               0xaf, 0xa5, 0xaf, 0xa5, 0xaf, 0xa5, 0xaf, 0xa5,
+                               0xaf, 0xa5, 0xaf, 0xa5, 0xaf, 0xa5, 0xaf, 0xa5,
+                       0xa0, 0x00, 0x20, 0x48,
+                               0xf6, 0x6d, 0xf6, 0x6d, 0xf6, 0x6d, 0xf6, 0x6d,
+                               0x88, 0x99, 0x88, 0x99, 0x88, 0x99, 0x88, 0x99,
+                               0x88, 0x99, 0x88, 0x99, 0x88, 0x99, 0x88, 0x99,
+                       0x50, 0x00, 0x9f, 0x36,
+                               0xb5, 0x59, 0xb5, 0x59, 0xb5, 0x59, 0xb5, 0x59,
+                               0x47, 0x85, 0x47, 0x85, 0x47, 0x85, 0x47, 0x85,
+                               0x47, 0x85, 0x47, 0x85, 0x47, 0x85, 0x47, 0x85,
+                       0x00, 0x00, 0x06, 0x2e,
+                               0x74, 0x45, 0x74, 0x45, 0x74, 0x45, 0x74, 0x45,
+                               0x06, 0x71, 0x06, 0x71, 0x06, 0x71, 0x06, 0x71,
+                               0x06, 0x71, 0x06, 0x71, 0x06, 0x71, 0x06, 0x71,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2437 MHz */
+               0x85, 0x09,
+                       0x10, 0x01, 0x67, 0x82,
+                               0x3a, 0x8a, 0x3a, 0x8a, 0x3a, 0x8a, 0x3a, 0x8a,
+                               0xcc, 0xb5, 0xcc, 0xb5, 0xcc, 0xb5, 0xcc, 0xb5,
+                               0xcc, 0xb5, 0xcc, 0xb5, 0xcc, 0xb5, 0xcc, 0xb5,
+                       0xf0, 0x00, 0x95, 0x6b,
+                               0x1f, 0x82, 0x1f, 0x82, 0x1f, 0x82, 0x1f, 0x82,
+                               0xb1, 0xad, 0xb1, 0xad, 0xb1, 0xad, 0xb1, 0xad,
+                               0xb1, 0xad, 0xb1, 0xad, 0xb1, 0xad, 0xb1, 0xad,
+                       0xd0, 0x00, 0x61, 0x5a,
+                               0x02, 0x7a, 0x02, 0x7a, 0x02, 0x7a, 0x02, 0x7a,
+                               0x94, 0xa5, 0x94, 0xa5, 0x94, 0xa5, 0x94, 0xa5,
+                               0x94, 0xa5, 0x94, 0xa5, 0x94, 0xa5, 0x94, 0xa5,
+                       0xa0, 0x00, 0x2c, 0x48,
+                               0xd8, 0x6d, 0xd8, 0x6d, 0xd8, 0x6d, 0xd8, 0x6d,
+                               0x6a, 0x99, 0x6a, 0x99, 0x6a, 0x99, 0x6a, 0x99,
+                               0x6a, 0x99, 0x6a, 0x99, 0x6a, 0x99, 0x6a, 0x99,
+                       0x50, 0x00, 0xb1, 0x36,
+                               0x92, 0x59, 0x92, 0x59, 0x92, 0x59, 0x92, 0x59,
+                               0x24, 0x85, 0x24, 0x85, 0x24, 0x85, 0x24, 0x85,
+                               0x24, 0x85, 0x24, 0x85, 0x24, 0x85, 0x24, 0x85,
+                       0x00, 0x00, 0x0f, 0x2e,
+                               0x4b, 0x45, 0x4b, 0x45, 0x4b, 0x45, 0x4b, 0x45,
+                               0xdd, 0x70, 0xdd, 0x70, 0xdd, 0x70, 0xdd, 0x70,
+                               0xdd, 0x70, 0xdd, 0x70, 0xdd, 0x70, 0xdd, 0x70,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2442 MHz */
+               0x8a, 0x09,
+                       0x10, 0x01, 0xf6, 0x81,
+                               0x24, 0x8a, 0x24, 0x8a, 0x24, 0x8a, 0x24, 0x8a,
+                               0xb6, 0xb5, 0xb6, 0xb5, 0xb6, 0xb5, 0xb6, 0xb5,
+                               0xb6, 0xb5, 0xb6, 0xb5, 0xb6, 0xb5, 0xb6, 0xb5,
+                       0xf0, 0x00, 0x62, 0x6b,
+                               0x06, 0x82, 0x06, 0x82, 0x06, 0x82, 0x06, 0x82,
+                               0x98, 0xad, 0x98, 0xad, 0x98, 0xad, 0x98, 0xad,
+                               0x98, 0xad, 0x98, 0xad, 0x98, 0xad, 0x98, 0xad,
+                       0xd0, 0x00, 0x52, 0x5a,
+                               0xe7, 0x79, 0xe7, 0x79, 0xe7, 0x79, 0xe7, 0x79,
+                               0x79, 0xa5, 0x79, 0xa5, 0x79, 0xa5, 0x79, 0xa5,
+                               0x79, 0xa5, 0x79, 0xa5, 0x79, 0xa5, 0x79, 0xa5,
+                       0xa0, 0x00, 0x37, 0x48,
+                               0xba, 0x6d, 0xba, 0x6d, 0xba, 0x6d, 0xba, 0x6d,
+                               0x4c, 0x99, 0x4c, 0x99, 0x4c, 0x99, 0x4c, 0x99,
+                               0x4c, 0x99, 0x4c, 0x99, 0x4c, 0x99, 0x4c, 0x99,
+                       0x50, 0x00, 0xc2, 0x36,
+                               0x6e, 0x59, 0x6e, 0x59, 0x6e, 0x59, 0x6e, 0x59,
+                               0x00, 0x85, 0x00, 0x85, 0x00, 0x85, 0x00, 0x85,
+                               0x00, 0x85, 0x00, 0x85, 0x00, 0x85, 0x00, 0x85,
+                       0x00, 0x00, 0x17, 0x2e,
+                               0x22, 0x45, 0x22, 0x45, 0x22, 0x45, 0x22, 0x45,
+                               0xb4, 0x70, 0xb4, 0x70, 0xb4, 0x70, 0xb4, 0x70,
+                               0xb4, 0x70, 0xb4, 0x70, 0xb4, 0x70, 0xb4, 0x70,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2447 MHz */
+               0x8f, 0x09,
+                       0x10, 0x01, 0x75, 0x83,
+                               0x61, 0x8a, 0x61, 0x8a, 0x61, 0x8a, 0x61, 0x8a,
+                               0xf3, 0xb5, 0xf3, 0xb5, 0xf3, 0xb5, 0xf3, 0xb5,
+                               0xf3, 0xb5, 0xf3, 0xb5, 0xf3, 0xb5, 0xf3, 0xb5,
+                       0xf0, 0x00, 0x4b, 0x6c,
+                               0x3f, 0x82, 0x3f, 0x82, 0x3f, 0x82, 0x3f, 0x82,
+                               0xd1, 0xad, 0xd1, 0xad, 0xd1, 0xad, 0xd1, 0xad,
+                               0xd1, 0xad, 0xd1, 0xad, 0xd1, 0xad, 0xd1, 0xad,
+                       0xd0, 0x00, 0xda, 0x5a,
+                               0x1c, 0x7a, 0x1c, 0x7a, 0x1c, 0x7a, 0x1c, 0x7a,
+                               0xae, 0xa5, 0xae, 0xa5, 0xae, 0xa5, 0xae, 0xa5,
+                               0xae, 0xa5, 0xae, 0xa5, 0xae, 0xa5, 0xae, 0xa5,
+                       0xa0, 0x00, 0x6d, 0x48,
+                               0xe9, 0x6d, 0xe9, 0x6d, 0xe9, 0x6d, 0xe9, 0x6d,
+                               0x7b, 0x99, 0x7b, 0x99, 0x7b, 0x99, 0x7b, 0x99,
+                               0x7b, 0x99, 0x7b, 0x99, 0x7b, 0x99, 0x7b, 0x99,
+                       0x50, 0x00, 0xc6, 0x36,
+                               0x92, 0x59, 0x92, 0x59, 0x92, 0x59, 0x92, 0x59,
+                               0x24, 0x85, 0x24, 0x85, 0x24, 0x85, 0x24, 0x85,
+                               0x24, 0x85, 0x24, 0x85, 0x24, 0x85, 0x24, 0x85,
+                       0x00, 0x00, 0x15, 0x2e,
+                               0x3c, 0x45, 0x3c, 0x45, 0x3c, 0x45, 0x3c, 0x45,
+                               0xce, 0x70, 0xce, 0x70, 0xce, 0x70, 0xce, 0x70,
+                               0xce, 0x70, 0xce, 0x70, 0xce, 0x70, 0xce, 0x70,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2452 MHz */
+               0x94, 0x09,
+                       0x10, 0x01, 0xf4, 0x84,
+                               0x9e, 0x8a, 0x9e, 0x8a, 0x9e, 0x8a, 0x9e, 0x8a,
+                               0x30, 0xb6, 0x30, 0xb6, 0x30, 0xb6, 0x30, 0xb6,
+                               0x30, 0xb6, 0x30, 0xb6, 0x30, 0xb6, 0x30, 0xb6,
+                       0xf0, 0x00, 0x34, 0x6d,
+                               0x77, 0x82, 0x77, 0x82, 0x77, 0x82, 0x77, 0x82,
+                               0x09, 0xae, 0x09, 0xae, 0x09, 0xae, 0x09, 0xae,
+                               0x09, 0xae, 0x09, 0xae, 0x09, 0xae, 0x09, 0xae,
+                       0xd0, 0x00, 0x62, 0x5b,
+                               0x50, 0x7a, 0x50, 0x7a, 0x50, 0x7a, 0x50, 0x7a,
+                               0xe2, 0xa5, 0xe2, 0xa5, 0xe2, 0xa5, 0xe2, 0xa5,
+                               0xe2, 0xa5, 0xe2, 0xa5, 0xe2, 0xa5, 0xe2, 0xa5,
+                       0xa0, 0x00, 0xa2, 0x48,
+                               0x17, 0x6e, 0x17, 0x6e, 0x17, 0x6e, 0x17, 0x6e,
+                               0xa9, 0x99, 0xa9, 0x99, 0xa9, 0x99, 0xa9, 0x99,
+                               0xa9, 0x99, 0xa9, 0x99, 0xa9, 0x99, 0xa9, 0x99,
+                       0x50, 0x00, 0xc9, 0x36,
+                               0xb7, 0x59, 0xb7, 0x59, 0xb7, 0x59, 0xb7, 0x59,
+                               0x49, 0x85, 0x49, 0x85, 0x49, 0x85, 0x49, 0x85,
+                               0x49, 0x85, 0x49, 0x85, 0x49, 0x85, 0x49, 0x85,
+                       0x00, 0x00, 0x12, 0x2e,
+                               0x57, 0x45, 0x57, 0x45, 0x57, 0x45, 0x57, 0x45,
+                               0xe9, 0x70, 0xe9, 0x70, 0xe9, 0x70, 0xe9, 0x70,
+                               0xe9, 0x70, 0xe9, 0x70, 0xe9, 0x70, 0xe9, 0x70,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2452 MHz */
+               0x99, 0x09,
+                       0x10, 0x01, 0x74, 0x86,
+                               0xdb, 0x8a, 0xdb, 0x8a, 0xdb, 0x8a, 0xdb, 0x8a,
+                               0x6d, 0xb6, 0x6d, 0xb6, 0x6d, 0xb6, 0x6d, 0xb6,
+                               0x6d, 0xb6, 0x6d, 0xb6, 0x6d, 0xb6, 0x6d, 0xb6,
+                       0xf0, 0x00, 0x1e, 0x6e,
+                               0xb0, 0x82, 0xb0, 0x82, 0xb0, 0x82, 0xb0, 0x82,
+                               0x42, 0xae, 0x42, 0xae, 0x42, 0xae, 0x42, 0xae,
+                               0x42, 0xae, 0x42, 0xae, 0x42, 0xae, 0x42, 0xae,
+                       0xd0, 0x00, 0xeb, 0x5b,
+                               0x85, 0x7a, 0x85, 0x7a, 0x85, 0x7a, 0x85, 0x7a,
+                               0x17, 0xa6, 0x17, 0xa6, 0x17, 0xa6, 0x17, 0xa6,
+                               0x17, 0xa6, 0x17, 0xa6, 0x17, 0xa6, 0x17, 0xa6,
+                       0xa0, 0x00, 0xd8, 0x48,
+                               0x46, 0x6e, 0x46, 0x6e, 0x46, 0x6e, 0x46, 0x6e,
+                               0xd8, 0x99, 0xd8, 0x99, 0xd8, 0x99, 0xd8, 0x99,
+                               0xd8, 0x99, 0xd8, 0x99, 0xd8, 0x99, 0xd8, 0x99,
+                       0x50, 0x00, 0xcd, 0x36,
+                               0xdb, 0x59, 0xdb, 0x59, 0xdb, 0x59, 0xdb, 0x59,
+                               0x6d, 0x85, 0x6d, 0x85, 0x6d, 0x85, 0x6d, 0x85,
+                               0x6d, 0x85, 0x6d, 0x85, 0x6d, 0x85, 0x6d, 0x85,
+                       0x00, 0x00, 0x10, 0x2e,
+                               0x71, 0x45, 0x71, 0x45, 0x71, 0x45, 0x71, 0x45,
+                               0x03, 0x71, 0x03, 0x71, 0x03, 0x71, 0x03, 0x71,
+                               0x03, 0x71, 0x03, 0x71, 0x03, 0x71, 0x03, 0x71,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2557 MHz */
+               0x9e, 0x09,
+                       0x10, 0x01, 0xf3, 0x87,
+                               0x17, 0x8b, 0x17, 0x8b, 0x17, 0x8b, 0x17, 0x8b,
+                               0xa9, 0xb6, 0xa9, 0xb6, 0xa9, 0xb6, 0xa9, 0xb6,
+                               0xa9, 0xb6, 0xa9, 0xb6, 0xa9, 0xb6, 0xa9, 0xb6,
+                       0xf0, 0x00, 0x07, 0x6f,
+                               0xe9, 0x82, 0xe9, 0x82, 0xe9, 0x82, 0xe9, 0x82,
+                               0x7b, 0xae, 0x7b, 0xae, 0x7b, 0xae, 0x7b, 0xae,
+                               0x7b, 0xae, 0x7b, 0xae, 0x7b, 0xae, 0x7b, 0xae,
+                       0xd0, 0x00, 0x73, 0x5c,
+                               0xba, 0x7a, 0xba, 0x7a, 0xba, 0x7a, 0xba, 0x7a,
+                               0x4c, 0xa6, 0x4c, 0xa6, 0x4c, 0xa6, 0x4c, 0xa6,
+                               0x4c, 0xa6, 0x4c, 0xa6, 0x4c, 0xa6, 0x4c, 0xa6,
+                       0xa0, 0x00, 0x0d, 0x49,
+                               0x74, 0x6e, 0x74, 0x6e, 0x74, 0x6e, 0x74, 0x6e,
+                               0x06, 0x9a, 0x06, 0x9a, 0x06, 0x9a, 0x06, 0x9a,
+                               0x06, 0x9a, 0x06, 0x9a, 0x06, 0x9a, 0x06, 0x9a,
+                       0x50, 0x00, 0xd1, 0x36,
+                               0xff, 0x59, 0xff, 0x59, 0xff, 0x59, 0xff, 0x59,
+                               0x91, 0x85, 0x91, 0x85, 0x91, 0x85, 0x91, 0x85,
+                               0x91, 0x85, 0x91, 0x85, 0x91, 0x85, 0x91, 0x85,
+                       0x00, 0x00, 0x0e, 0x2e,
+                               0x8b, 0x45, 0x8b, 0x45, 0x8b, 0x45, 0x8b, 0x45,
+                               0x1d, 0x71, 0x1d, 0x71, 0x1d, 0x71, 0x1d, 0x71,
+                               0x1d, 0x71, 0x1d, 0x71, 0x1d, 0x71, 0x1d, 0x71,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2562 MHz */
+               0xa3, 0x09,
+                       0x10, 0x01, 0x72, 0x89,
+                               0x54, 0x8b, 0x54, 0x8b, 0x54, 0x8b, 0x54, 0x8b,
+                               0xe6, 0xb6, 0xe6, 0xb6, 0xe6, 0xb6, 0xe6, 0xb6,
+                               0xe6, 0xb6, 0xe6, 0xb6, 0xe6, 0xb6, 0xe6, 0xb6,
+                       0xf0, 0x00, 0xf0, 0x6f,
+                               0x21, 0x83, 0x21, 0x83, 0x21, 0x83, 0x21, 0x83,
+                               0xb3, 0xae, 0xb3, 0xae, 0xb3, 0xae, 0xb3, 0xae,
+                               0xb3, 0xae, 0xb3, 0xae, 0xb3, 0xae, 0xb3, 0xae,
+                       0xd0, 0x00, 0xfb, 0x5c,
+                               0xee, 0x7a, 0xee, 0x7a, 0xee, 0x7a, 0xee, 0x7a,
+                               0x80, 0xa6, 0x80, 0xa6, 0x80, 0xa6, 0x80, 0xa6,
+                               0x80, 0xa6, 0x80, 0xa6, 0x80, 0xa6, 0x80, 0xa6,
+                       0xa0, 0x00, 0x43, 0x49,
+                               0xa3, 0x6e, 0xa3, 0x6e, 0xa3, 0x6e, 0xa3, 0x6e,
+                               0x35, 0x9a, 0x35, 0x9a, 0x35, 0x9a, 0x35, 0x9a,
+                               0x35, 0x9a, 0x35, 0x9a, 0x35, 0x9a, 0x35, 0x9a,
+                       0x50, 0x00, 0xd4, 0x36,
+                               0x24, 0x5a, 0x24, 0x5a, 0x24, 0x5a, 0x24, 0x5a,
+                               0xb6, 0x85, 0xb6, 0x85, 0xb6, 0x85, 0xb6, 0x85,
+                               0xb6, 0x85, 0xb6, 0x85, 0xb6, 0x85, 0xb6, 0x85,
+                       0x00, 0x00, 0x0b, 0x2e,
+                               0xa6, 0x45, 0xa6, 0x45, 0xa6, 0x45, 0xa6, 0x45,
+                               0x38, 0x71, 0x38, 0x71, 0x38, 0x71, 0x38, 0x71,
+                               0x38, 0x71, 0x38, 0x71, 0x38, 0x71, 0x38, 0x71,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+               /* 2572 MHz */
+               0xa8, 0x09,
+                       0x10, 0x01, 0xf1, 0x8a,
+                               0x91, 0x8b, 0x91, 0x8b, 0x91, 0x8b, 0x91, 0x8b,
+                               0x23, 0xb7, 0x23, 0xb7, 0x23, 0xb7, 0x23, 0xb7,
+                               0x23, 0xb7, 0x23, 0xb7, 0x23, 0xb7, 0x23, 0xb7,
+                       0xf0, 0x00, 0xd9, 0x70,
+                               0x5a, 0x83, 0x5a, 0x83, 0x5a, 0x83, 0x5a, 0x83,
+                               0xec, 0xae, 0xec, 0xae, 0xec, 0xae, 0xec, 0xae,
+                               0xec, 0xae, 0xec, 0xae, 0xec, 0xae, 0xec, 0xae,
+                       0xd0, 0x00, 0x83, 0x5d,
+                               0x23, 0x7b, 0x23, 0x7b, 0x23, 0x7b, 0x23, 0x7b,
+                               0xb5, 0xa6, 0xb5, 0xa6, 0xb5, 0xa6, 0xb5, 0xa6,
+                               0xb5, 0xa6, 0xb5, 0xa6, 0xb5, 0xa6, 0xb5, 0xa6,
+                       0xa0, 0x00, 0x78, 0x49,
+                               0xd1, 0x6e, 0xd1, 0x6e, 0xd1, 0x6e, 0xd1, 0x6e,
+                               0x63, 0x9a, 0x63, 0x9a, 0x63, 0x9a, 0x63, 0x9a,
+                               0x63, 0x9a, 0x63, 0x9a, 0x63, 0x9a, 0x63, 0x9a,
+                       0x50, 0x00, 0xd8, 0x36,
+                               0x48, 0x5a, 0x48, 0x5a, 0x48, 0x5a, 0x48, 0x5a,
+                               0xda, 0x85, 0xda, 0x85, 0xda, 0x85, 0xda, 0x85,
+                               0xda, 0x85, 0xda, 0x85, 0xda, 0x85, 0xda, 0x85,
+                       0x00, 0x00, 0x09, 0x2e,
+                               0xc0, 0x45, 0xc0, 0x45, 0xc0, 0x45, 0xc0, 0x45,
+                               0x52, 0x71, 0x52, 0x71, 0x52, 0x71, 0x52, 0x71,
+                               0x52, 0x71, 0x52, 0x71, 0x52, 0x71, 0x52, 0x71,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x80, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00,
+                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
+
+/*
+ * Not really sure if this is actually the power_limit database,
+ * it looks a bit "related" to PDR_PRISM_ZIF_TX_IQ_CALIBRATION
+ */
+/* struct pda_custom_wrapper */
+0xae, 0x00, 0xef, 0xbe,      /* PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM */
+       0x0d, 0x00, 0x1a, 0x00,         /* 13 entries, 26 bytes per entry */
+       0x00, 0x00, 0x52, 0x01,         /* no offset, 338 bytes total */
+
+               /* 2412 MHz */
+               0x6c, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2417 MHz */
+               0x71, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2422 MHz */
+               0x76, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2427 MHz */
+               0x7b, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2432 MHz */
+               0x80, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2437 MHz */
+               0x85, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2442 MHz */
+               0x8a, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2447 MHz */
+               0x8f, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2452 MHz */
+               0x94, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2457 MHz */
+               0x99, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2462 MHz */
+               0x9e, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2467 MHz */
+               0xa3, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+               /* 2472 MHz */
+               0xa8, 0x09,
+                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
+                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
+                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
+
+/* struct pda_iq_autocal_entry[13] */
+0x42, 0x00, 0x06, 0x19,                /* PDR_PRISM_ZIF_TX_IQ_CALIBRATION */
+       /* 2412 MHz */
+       0x6c, 0x09, 0x26, 0x00, 0xf8, 0xff, 0xf7, 0xff, 0xff, 0x00,
+       /* 2417 MHz */
+       0x71, 0x09, 0x26, 0x00, 0xf8, 0xff, 0xf7, 0xff, 0xff, 0x00,
+       /* 2422 MHz */
+       0x76, 0x09, 0x26, 0x00, 0xf8, 0xff, 0xf7, 0xff, 0xff, 0x00,
+       /* 2427 MHz */
+       0x7b, 0x09, 0x26, 0x00, 0xf8, 0xff, 0xf7, 0xff, 0xff, 0x00,
+       /* 2432 MHz */
+       0x80, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
+       /* 2437 MHz */
+       0x85, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
+       /* 2442 MHz */
+       0x8a, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
+       /* 2447 MHz */
+       0x8f, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
+       /* 2452 MHz */
+       0x94, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
+       /* 2457 MHz */
+       0x99, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
+       /* 2462 MHz */
+       0x9e, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
+       /* 2467 MHz */
+       0xa3, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
+       /* 2472 MHz */
+       0xa8, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
+
+0x02, 0x00, 0x00, 0x00,                /* PDR_END */
+       0xb6, 0x04,
+};
+
+#endif /* P54SPI_EEPROM_H */
+
diff --git a/drivers/net/wireless/intersil/p54/p54usb.c b/drivers/net/wireless/intersil/p54/p54usb.c
new file mode 100644 (file)
index 0000000..043bd1c
--- /dev/null
@@ -0,0 +1,1149 @@
+
+/*
+ * Linux device driver for USB based Prism54
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/usb.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/crc32.h>
+#include <linux/module.h>
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+#include "p54usb.h"
+
+MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
+MODULE_DESCRIPTION("Prism54 USB wireless driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("prism54usb");
+MODULE_FIRMWARE("isl3886usb");
+MODULE_FIRMWARE("isl3887usb");
+
+/*
+ * Note:
+ *
+ * Always update our wiki's device list (located at:
+ * http://wireless.kernel.org/en/users/Drivers/p54/devices ),
+ * whenever you add a new device.
+ */
+
+static struct usb_device_id p54u_table[] = {
+       /* Version 1 devices (pci chip + net2280) */
+       {USB_DEVICE(0x0411, 0x0050)},   /* Buffalo WLI2-USB2-G54 */
+       {USB_DEVICE(0x045e, 0x00c2)},   /* Microsoft MN-710 */
+       {USB_DEVICE(0x0506, 0x0a11)},   /* 3COM 3CRWE254G72 */
+       {USB_DEVICE(0x0675, 0x0530)},   /* DrayTek Vigor 530 */
+       {USB_DEVICE(0x06b9, 0x0120)},   /* Thomson SpeedTouch 120g */
+       {USB_DEVICE(0x0707, 0xee06)},   /* SMC 2862W-G */
+       {USB_DEVICE(0x07aa, 0x001c)},   /* Corega CG-WLUSB2GT */
+       {USB_DEVICE(0x083a, 0x4501)},   /* Accton 802.11g WN4501 USB */
+       {USB_DEVICE(0x083a, 0x4502)},   /* Siemens Gigaset USB Adapter */
+       {USB_DEVICE(0x083a, 0x5501)},   /* Phillips CPWUA054 */
+       {USB_DEVICE(0x0846, 0x4200)},   /* Netgear WG121 */
+       {USB_DEVICE(0x0846, 0x4210)},   /* Netgear WG121 the second ? */
+       {USB_DEVICE(0x0846, 0x4220)},   /* Netgear WG111 */
+       {USB_DEVICE(0x09aa, 0x1000)},   /* Spinnaker Proto board */
+       {USB_DEVICE(0x0bf8, 0x1007)},   /* Fujitsu E-5400 USB */
+       {USB_DEVICE(0x0cde, 0x0006)},   /* Medion 40900, Roper Europe */
+       {USB_DEVICE(0x0db0, 0x6826)},   /* MSI UB54G (MS-6826) */
+       {USB_DEVICE(0x107b, 0x55f2)},   /* Gateway WGU-210 (Gemtek) */
+       {USB_DEVICE(0x124a, 0x4023)},   /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
+       {USB_DEVICE(0x1435, 0x0210)},   /* Inventel UR054G */
+       {USB_DEVICE(0x15a9, 0x0002)},   /* Gemtek WUBI-100GW 802.11g */
+       {USB_DEVICE(0x1630, 0x0005)},   /* 2Wire 802.11g USB (v1) / Z-Com */
+       {USB_DEVICE(0x182d, 0x096b)},   /* Sitecom WL-107 */
+       {USB_DEVICE(0x1915, 0x2234)},   /* Linksys WUSB54G OEM */
+       {USB_DEVICE(0x1915, 0x2235)},   /* Linksys WUSB54G Portable OEM */
+       {USB_DEVICE(0x2001, 0x3701)},   /* DLink DWL-G120 Spinnaker */
+       {USB_DEVICE(0x2001, 0x3703)},   /* DLink DWL-G122 */
+       {USB_DEVICE(0x2001, 0x3762)},   /* Conceptronic C54U */
+       {USB_DEVICE(0x5041, 0x2234)},   /* Linksys WUSB54G */
+       {USB_DEVICE(0x5041, 0x2235)},   /* Linksys WUSB54G Portable */
+
+       /* Version 2 devices (3887) */
+       {USB_DEVICE(0x0471, 0x1230)},   /* Philips CPWUA054/00 */
+       {USB_DEVICE(0x050d, 0x7050)},   /* Belkin F5D7050 ver 1000 */
+       {USB_DEVICE(0x0572, 0x2000)},   /* Cohiba Proto board */
+       {USB_DEVICE(0x0572, 0x2002)},   /* Cohiba Proto board */
+       {USB_DEVICE(0x06a9, 0x000e)},   /* Westell 802.11g USB (A90-211WG-01) */
+       {USB_DEVICE(0x06b9, 0x0121)},   /* Thomson SpeedTouch 121g */
+       {USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
+       {USB_DEVICE(0x07aa, 0x0020)},   /* Corega WLUSB2GTST USB */
+       {USB_DEVICE(0x0803, 0x4310)},   /* Zoom 4410a */
+       {USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
+       {USB_DEVICE(0x083a, 0x4531)},   /* T-Com Sinus 154 data II */
+       {USB_DEVICE(0x083a, 0xc501)},   /* Zoom Wireless-G 4410 */
+       {USB_DEVICE(0x083a, 0xf503)},   /* Accton FD7050E ver 1010ec  */
+       {USB_DEVICE(0x0846, 0x4240)},   /* Netgear WG111 (v2) */
+       {USB_DEVICE(0x0915, 0x2000)},   /* Cohiba Proto board */
+       {USB_DEVICE(0x0915, 0x2002)},   /* Cohiba Proto board */
+       {USB_DEVICE(0x0baf, 0x0118)},   /* U.S. Robotics U5 802.11g Adapter*/
+       {USB_DEVICE(0x0bf8, 0x1009)},   /* FUJITSU E-5400 USB D1700*/
+       /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
+                                        * just noting it here for clarity */
+       {USB_DEVICE(0x0cde, 0x0008)},   /* Sagem XG703A */
+       {USB_DEVICE(0x0cde, 0x0015)},   /* Zcomax XG-705A */
+       {USB_DEVICE(0x0d8e, 0x3762)},   /* DLink DWL-G120 Cohiba */
+       {USB_DEVICE(0x124a, 0x4025)},   /* IOGear GWU513 (GW3887IK chip) */
+       {USB_DEVICE(0x1260, 0xee22)},   /* SMC 2862W-G version 2 */
+       {USB_DEVICE(0x13b1, 0x000a)},   /* Linksys WUSB54G ver 2 */
+       {USB_DEVICE(0x13B1, 0x000C)},   /* Linksys WUSB54AG */
+       {USB_DEVICE(0x1413, 0x5400)},   /* Telsey 802.11g USB2.0 Adapter */
+       {USB_DEVICE(0x1435, 0x0427)},   /* Inventel UR054G */
+       /* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */
+       {USB_DEVICE(0x1668, 0x1050)},   /* Actiontec 802UIG-1 */
+       {USB_DEVICE(0x1740, 0x1000)},   /* Senao NUB-350 */
+       {USB_DEVICE(0x2001, 0x3704)},   /* DLink DWL-G122 rev A2 */
+       {USB_DEVICE(0x2001, 0x3705)},   /* D-Link DWL-G120 rev C1 */
+       {USB_DEVICE(0x413c, 0x5513)},   /* Dell WLA3310 USB Wireless Adapter */
+       {USB_DEVICE(0x413c, 0x8102)},   /* Spinnaker DUT */
+       {USB_DEVICE(0x413c, 0x8104)},   /* Cohiba Proto board */
+       {}
+};
+
+MODULE_DEVICE_TABLE(usb, p54u_table);
+
+static const struct {
+       u32 intf;
+       enum p54u_hw_type type;
+       const char *fw;
+       char hw[20];
+} p54u_fwlist[__NUM_P54U_HWTYPES] = {
+       {
+               .type = P54U_NET2280,
+               .intf = FW_LM86,
+               .fw = "isl3886usb",
+               .hw = "ISL3886 + net2280",
+       },
+       {
+               .type = P54U_3887,
+               .intf = FW_LM87,
+               .fw = "isl3887usb",
+               .hw = "ISL3887",
+       },
+};
+
+static void p54u_rx_cb(struct urb *urb)
+{
+       struct sk_buff *skb = (struct sk_buff *) urb->context;
+       struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
+       struct ieee80211_hw *dev = info->dev;
+       struct p54u_priv *priv = dev->priv;
+
+       skb_unlink(skb, &priv->rx_queue);
+
+       if (unlikely(urb->status)) {
+               dev_kfree_skb_irq(skb);
+               return;
+       }
+
+       skb_put(skb, urb->actual_length);
+
+       if (priv->hw_type == P54U_NET2280)
+               skb_pull(skb, priv->common.tx_hdr_len);
+       if (priv->common.fw_interface == FW_LM87) {
+               skb_pull(skb, 4);
+               skb_put(skb, 4);
+       }
+
+       if (p54_rx(dev, skb)) {
+               skb = dev_alloc_skb(priv->common.rx_mtu + 32);
+               if (unlikely(!skb)) {
+                       /* TODO check rx queue length and refill *somewhere* */
+                       return;
+               }
+
+               info = (struct p54u_rx_info *) skb->cb;
+               info->urb = urb;
+               info->dev = dev;
+               urb->transfer_buffer = skb_tail_pointer(skb);
+               urb->context = skb;
+       } else {
+               if (priv->hw_type == P54U_NET2280)
+                       skb_push(skb, priv->common.tx_hdr_len);
+               if (priv->common.fw_interface == FW_LM87) {
+                       skb_push(skb, 4);
+                       skb_put(skb, 4);
+               }
+               skb_reset_tail_pointer(skb);
+               skb_trim(skb, 0);
+               urb->transfer_buffer = skb_tail_pointer(skb);
+       }
+       skb_queue_tail(&priv->rx_queue, skb);
+       usb_anchor_urb(urb, &priv->submitted);
+       if (usb_submit_urb(urb, GFP_ATOMIC)) {
+               skb_unlink(skb, &priv->rx_queue);
+               usb_unanchor_urb(urb);
+               dev_kfree_skb_irq(skb);
+       }
+}
+
+static void p54u_tx_cb(struct urb *urb)
+{
+       struct sk_buff *skb = urb->context;
+       struct ieee80211_hw *dev =
+               usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+
+       p54_free_skb(dev, skb);
+}
+
+static void p54u_tx_dummy_cb(struct urb *urb) { }
+
+static void p54u_free_urbs(struct ieee80211_hw *dev)
+{
+       struct p54u_priv *priv = dev->priv;
+       usb_kill_anchored_urbs(&priv->submitted);
+}
+
+static void p54u_stop(struct ieee80211_hw *dev)
+{
+       /*
+        * TODO: figure out how to reliably stop the 3887 and net2280 so
+        * the hardware is still usable next time we want to start it.
+        * until then, we just stop listening to the hardware..
+        */
+       p54u_free_urbs(dev);
+}
+
+static int p54u_init_urbs(struct ieee80211_hw *dev)
+{
+       struct p54u_priv *priv = dev->priv;
+       struct urb *entry = NULL;
+       struct sk_buff *skb;
+       struct p54u_rx_info *info;
+       int ret = 0;
+
+       while (skb_queue_len(&priv->rx_queue) < 32) {
+               skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
+               if (!skb) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               entry = usb_alloc_urb(0, GFP_KERNEL);
+               if (!entry) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               usb_fill_bulk_urb(entry, priv->udev,
+                                 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
+                                 skb_tail_pointer(skb),
+                                 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
+               info = (struct p54u_rx_info *) skb->cb;
+               info->urb = entry;
+               info->dev = dev;
+               skb_queue_tail(&priv->rx_queue, skb);
+
+               usb_anchor_urb(entry, &priv->submitted);
+               ret = usb_submit_urb(entry, GFP_KERNEL);
+               if (ret) {
+                       skb_unlink(skb, &priv->rx_queue);
+                       usb_unanchor_urb(entry);
+                       goto err;
+               }
+               usb_free_urb(entry);
+               entry = NULL;
+       }
+
+       return 0;
+
+ err:
+       usb_free_urb(entry);
+       kfree_skb(skb);
+       p54u_free_urbs(dev);
+       return ret;
+}
+
+static int p54u_open(struct ieee80211_hw *dev)
+{
+       /*
+        * TODO: Because we don't know how to reliably stop the 3887 and
+        * the isl3886+net2280, other than brutally cut off all
+        * communications. We have to reinitialize the urbs on every start.
+        */
+       return p54u_init_urbs(dev);
+}
+
+static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
+{
+       u32 chk = 0;
+
+       length >>= 2;
+       while (length--) {
+               chk ^= le32_to_cpu(*data++);
+               chk = (chk >> 5) ^ (chk << 3);
+       }
+
+       return cpu_to_le32(chk);
+}
+
+static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       struct p54u_priv *priv = dev->priv;
+       struct urb *data_urb;
+       struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
+
+       data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!data_urb) {
+               p54_free_skb(dev, skb);
+               return;
+       }
+
+       hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
+       hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
+
+       usb_fill_bulk_urb(data_urb, priv->udev,
+                         usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+                         hdr, skb->len + sizeof(*hdr),  FREE_AFTER_TX(skb) ?
+                         p54u_tx_cb : p54u_tx_dummy_cb, skb);
+       data_urb->transfer_flags |= URB_ZERO_PACKET;
+
+       usb_anchor_urb(data_urb, &priv->submitted);
+       if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
+               usb_unanchor_urb(data_urb);
+               p54_free_skb(dev, skb);
+       }
+       usb_free_urb(data_urb);
+}
+
+static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       struct p54u_priv *priv = dev->priv;
+       struct urb *int_urb = NULL, *data_urb = NULL;
+       struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
+       struct net2280_reg_write *reg = NULL;
+       int err = -ENOMEM;
+
+       reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
+       if (!reg)
+               goto out;
+
+       int_urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!int_urb)
+               goto out;
+
+       data_urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!data_urb)
+               goto out;
+
+       reg->port = cpu_to_le16(NET2280_DEV_U32);
+       reg->addr = cpu_to_le32(P54U_DEV_BASE);
+       reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
+
+       memset(hdr, 0, sizeof(*hdr));
+       hdr->len = cpu_to_le16(skb->len);
+       hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
+
+       usb_fill_bulk_urb(int_urb, priv->udev,
+               usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
+               p54u_tx_dummy_cb, dev);
+
+       /*
+        * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
+        * free what is inside the transfer_buffer after the last reference to
+        * the int_urb is dropped.
+        */
+       int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
+       reg = NULL;
+
+       usb_fill_bulk_urb(data_urb, priv->udev,
+                         usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
+                         hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
+                         p54u_tx_cb : p54u_tx_dummy_cb, skb);
+       data_urb->transfer_flags |= URB_ZERO_PACKET;
+
+       usb_anchor_urb(int_urb, &priv->submitted);
+       err = usb_submit_urb(int_urb, GFP_ATOMIC);
+       if (err) {
+               usb_unanchor_urb(int_urb);
+               goto out;
+       }
+
+       usb_anchor_urb(data_urb, &priv->submitted);
+       err = usb_submit_urb(data_urb, GFP_ATOMIC);
+       if (err) {
+               usb_unanchor_urb(data_urb);
+               goto out;
+       }
+out:
+       usb_free_urb(int_urb);
+       usb_free_urb(data_urb);
+
+       if (err) {
+               kfree(reg);
+               p54_free_skb(dev, skb);
+       }
+}
+
+static int p54u_write(struct p54u_priv *priv,
+                     struct net2280_reg_write *buf,
+                     enum net2280_op_type type,
+                     __le32 addr, __le32 val)
+{
+       unsigned int ep;
+       int alen;
+
+       if (type & 0x0800)
+               ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
+       else
+               ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
+
+       buf->port = cpu_to_le16(type);
+       buf->addr = addr;
+       buf->val = val;
+
+       return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
+}
+
+static int p54u_read(struct p54u_priv *priv, void *buf,
+                    enum net2280_op_type type,
+                    __le32 addr, __le32 *val)
+{
+       struct net2280_reg_read *read = buf;
+       __le32 *reg = buf;
+       unsigned int ep;
+       int alen, err;
+
+       if (type & 0x0800)
+               ep = P54U_PIPE_DEV;
+       else
+               ep = P54U_PIPE_BRG;
+
+       read->port = cpu_to_le16(type);
+       read->addr = addr;
+
+       err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
+                          read, sizeof(*read), &alen, 1000);
+       if (err)
+               return err;
+
+       err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
+                          reg, sizeof(*reg), &alen, 1000);
+       if (err)
+               return err;
+
+       *val = *reg;
+       return 0;
+}
+
+static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
+                        void *data, size_t len)
+{
+       int alen;
+       return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
+                           data, len, &alen, 2000);
+}
+
+static int p54u_device_reset(struct ieee80211_hw *dev)
+{
+       struct p54u_priv *priv = dev->priv;
+       int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
+
+       if (lock) {
+               ret = usb_lock_device_for_reset(priv->udev, priv->intf);
+               if (ret < 0) {
+                       dev_err(&priv->udev->dev, "(p54usb) unable to lock "
+                               "device for reset (%d)!\n", ret);
+                       return ret;
+               }
+       }
+
+       ret = usb_reset_device(priv->udev);
+       if (lock)
+               usb_unlock_device(priv->udev);
+
+       if (ret)
+               dev_err(&priv->udev->dev, "(p54usb) unable to reset "
+                       "device (%d)!\n", ret);
+
+       return ret;
+}
+
+static const char p54u_romboot_3887[] = "~~~~";
+static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
+{
+       struct p54u_priv *priv = dev->priv;
+       u8 *buf;
+       int ret;
+
+       buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
+                           buf, 4);
+       kfree(buf);
+       if (ret)
+               dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
+                       "boot ROM (%d)!\n", ret);
+
+       return ret;
+}
+
+static const char p54u_firmware_upload_3887[] = "<\r";
+static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
+{
+       struct p54u_priv *priv = dev->priv;
+       int err, alen;
+       u8 carry = 0;
+       u8 *buf, *tmp;
+       const u8 *data;
+       unsigned int left, remains, block_size;
+       struct x2_header *hdr;
+       unsigned long timeout;
+
+       err = p54u_firmware_reset_3887(dev);
+       if (err)
+               return err;
+
+       tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       left = block_size = min_t(size_t, P54U_FW_BLOCK, priv->fw->size);
+       strcpy(buf, p54u_firmware_upload_3887);
+       left -= strlen(p54u_firmware_upload_3887);
+       tmp += strlen(p54u_firmware_upload_3887);
+
+       data = priv->fw->data;
+       remains = priv->fw->size;
+
+       hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
+       memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
+       hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
+       hdr->fw_length = cpu_to_le32(priv->fw->size);
+       hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
+                                        sizeof(u32)*2));
+       left -= sizeof(*hdr);
+       tmp += sizeof(*hdr);
+
+       while (remains) {
+               while (left--) {
+                       if (carry) {
+                               *tmp++ = carry;
+                               carry = 0;
+                               remains--;
+                               continue;
+                       }
+                       switch (*data) {
+                       case '~':
+                               *tmp++ = '}';
+                               carry = '^';
+                               break;
+                       case '}':
+                               *tmp++ = '}';
+                               carry = ']';
+                               break;
+                       default:
+                               *tmp++ = *data;
+                               remains--;
+                               break;
+                       }
+                       data++;
+               }
+
+               err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
+               if (err) {
+                       dev_err(&priv->udev->dev, "(p54usb) firmware "
+                                                 "upload failed!\n");
+                       goto err_upload_failed;
+               }
+
+               tmp = buf;
+               left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
+       }
+
+       *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
+                                                priv->fw->size));
+       err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
+       if (err) {
+               dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
+               goto err_upload_failed;
+       }
+       timeout = jiffies + msecs_to_jiffies(1000);
+       while (!(err = usb_bulk_msg(priv->udev,
+               usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
+               if (alen > 2 && !memcmp(buf, "OK", 2))
+                       break;
+
+               if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (time_after(jiffies, timeout)) {
+                       dev_err(&priv->udev->dev, "(p54usb) firmware boot "
+                                                 "timed out!\n");
+                       err = -ETIMEDOUT;
+                       break;
+               }
+       }
+       if (err) {
+               dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
+               goto err_upload_failed;
+       }
+
+       buf[0] = 'g';
+       buf[1] = '\r';
+       err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
+       if (err) {
+               dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
+               goto err_upload_failed;
+       }
+
+       timeout = jiffies + msecs_to_jiffies(1000);
+       while (!(err = usb_bulk_msg(priv->udev,
+               usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
+               if (alen > 0 && buf[0] == 'g')
+                       break;
+
+               if (time_after(jiffies, timeout)) {
+                       err = -ETIMEDOUT;
+                       break;
+               }
+       }
+       if (err)
+               goto err_upload_failed;
+
+err_upload_failed:
+       kfree(buf);
+       return err;
+}
+
+static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
+{
+       struct p54u_priv *priv = dev->priv;
+       const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
+       int err, alen;
+       void *buf;
+       __le32 reg;
+       unsigned int remains, offset;
+       const u8 *data;
+
+       buf = kmalloc(512, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+#define P54U_WRITE(type, addr, data) \
+       do {\
+               err = p54u_write(priv, buf, type,\
+                                cpu_to_le32((u32)(unsigned long)addr), data);\
+               if (err) \
+                       goto fail;\
+       } while (0)
+
+#define P54U_READ(type, addr) \
+       do {\
+               err = p54u_read(priv, buf, type,\
+                               cpu_to_le32((u32)(unsigned long)addr), &reg);\
+               if (err)\
+                       goto fail;\
+       } while (0)
+
+       /* power down net2280 bridge */
+       P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
+       reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
+       reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
+       P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
+
+       mdelay(100);
+
+       /* power up bridge */
+       reg |= cpu_to_le32(P54U_BRG_POWER_UP);
+       reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
+       P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
+
+       mdelay(100);
+
+       P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
+                  cpu_to_le32(NET2280_CLK_30Mhz |
+                              NET2280_PCI_ENABLE |
+                              NET2280_PCI_SOFT_RESET));
+
+       mdelay(20);
+
+       P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
+                  cpu_to_le32(PCI_COMMAND_MEMORY |
+                              PCI_COMMAND_MASTER));
+
+       P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
+                  cpu_to_le32(NET2280_BASE));
+
+       P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
+       reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
+       P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
+
+       // TODO: we really need this?
+       P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
+
+       P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
+                  cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
+       P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
+                  cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
+
+       P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
+                  cpu_to_le32(NET2280_BASE2));
+
+       /* finally done setting up the bridge */
+
+       P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
+                  cpu_to_le32(PCI_COMMAND_MEMORY |
+                              PCI_COMMAND_MASTER));
+
+       P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
+       P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
+                  cpu_to_le32(P54U_DEV_BASE));
+
+       P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
+       P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+                  cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+       /* do romboot */
+       P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
+
+       P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+       mdelay(20);
+
+       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+       mdelay(20);
+
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+       mdelay(100);
+
+       P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+       P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+       /* finally, we can upload firmware now! */
+       remains = priv->fw->size;
+       data = priv->fw->data;
+       offset = ISL38XX_DEV_FIRMWARE_ADDR;
+
+       while (remains) {
+               unsigned int block_len = min(remains, (unsigned int)512);
+               memcpy(buf, data, block_len);
+
+               err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
+               if (err) {
+                       dev_err(&priv->udev->dev, "(p54usb) firmware block "
+                                                 "upload failed\n");
+                       goto fail;
+               }
+
+               P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
+                          cpu_to_le32(0xc0000f00));
+
+               P54U_WRITE(NET2280_DEV_U32,
+                          0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
+               P54U_WRITE(NET2280_DEV_U32,
+                          0x0020 | (unsigned long)&devreg->direct_mem_win,
+                          cpu_to_le32(1));
+
+               P54U_WRITE(NET2280_DEV_U32,
+                          0x0024 | (unsigned long)&devreg->direct_mem_win,
+                          cpu_to_le32(block_len));
+               P54U_WRITE(NET2280_DEV_U32,
+                          0x0028 | (unsigned long)&devreg->direct_mem_win,
+                          cpu_to_le32(offset));
+
+               P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
+                          cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
+               P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
+                          cpu_to_le32(block_len >> 2));
+               P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
+                          cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
+
+               mdelay(10);
+
+               P54U_READ(NET2280_DEV_U32,
+                         0x002C | (unsigned long)&devreg->direct_mem_win);
+               if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
+                   !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
+                       dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
+                                                 "transfer failed\n");
+                       goto fail;
+               }
+
+               P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
+                          cpu_to_le32(NET2280_FIFO_FLUSH));
+
+               remains -= block_len;
+               data += block_len;
+               offset += block_len;
+       }
+
+       /* do ramboot */
+       P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
+       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
+       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+       mdelay(20);
+
+       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
+       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
+       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
+
+       mdelay(100);
+
+       P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+       P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+       /* start up the firmware */
+       P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
+                  cpu_to_le32(ISL38XX_INT_IDENT_INIT));
+
+       P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+                  cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+       P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
+                  cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
+                              NET2280_USB_INTERRUPT_ENABLE));
+
+       P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
+                  cpu_to_le32(ISL38XX_DEV_INT_RESET));
+
+       err = usb_interrupt_msg(priv->udev,
+                               usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
+                               buf, sizeof(__le32), &alen, 1000);
+       if (err || alen != sizeof(__le32))
+               goto fail;
+
+       P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
+       P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
+
+       if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
+               err = -EINVAL;
+
+       P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
+       P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
+                  cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
+
+#undef P54U_WRITE
+#undef P54U_READ
+
+fail:
+       kfree(buf);
+       return err;
+}
+
+static int p54_find_type(struct p54u_priv *priv)
+{
+       int i;
+
+       for (i = 0; i < __NUM_P54U_HWTYPES; i++)
+               if (p54u_fwlist[i].type == priv->hw_type)
+                       break;
+       if (i == __NUM_P54U_HWTYPES)
+               return -EOPNOTSUPP;
+
+       return i;
+}
+
+static int p54u_start_ops(struct p54u_priv *priv)
+{
+       struct ieee80211_hw *dev = priv->common.hw;
+       int ret;
+
+       ret = p54_parse_firmware(dev, priv->fw);
+       if (ret)
+               goto err_out;
+
+       ret = p54_find_type(priv);
+       if (ret < 0)
+               goto err_out;
+
+       if (priv->common.fw_interface != p54u_fwlist[ret].intf) {
+               dev_err(&priv->udev->dev, "wrong firmware, please get "
+                       "a firmware for \"%s\" and try again.\n",
+                       p54u_fwlist[ret].hw);
+               ret = -ENODEV;
+               goto err_out;
+       }
+
+       ret = priv->upload_fw(dev);
+       if (ret)
+               goto err_out;
+
+       ret = p54u_open(dev);
+       if (ret)
+               goto err_out;
+
+       ret = p54_read_eeprom(dev);
+       if (ret)
+               goto err_stop;
+
+       p54u_stop(dev);
+
+       ret = p54_register_common(dev, &priv->udev->dev);
+       if (ret)
+               goto err_stop;
+
+       return 0;
+
+err_stop:
+       p54u_stop(dev);
+
+err_out:
+       /*
+        * p54u_disconnect will do the rest of the
+        * cleanup
+        */
+       return ret;
+}
+
+static void p54u_load_firmware_cb(const struct firmware *firmware,
+                                 void *context)
+{
+       struct p54u_priv *priv = context;
+       struct usb_device *udev = priv->udev;
+       int err;
+
+       complete(&priv->fw_wait_load);
+       if (firmware) {
+               priv->fw = firmware;
+               err = p54u_start_ops(priv);
+       } else {
+               err = -ENOENT;
+               dev_err(&udev->dev, "Firmware not found.\n");
+       }
+
+       if (err) {
+               struct device *parent = priv->udev->dev.parent;
+
+               dev_err(&udev->dev, "failed to initialize device (%d)\n", err);
+
+               if (parent)
+                       device_lock(parent);
+
+               device_release_driver(&udev->dev);
+               /*
+                * At this point p54u_disconnect has already freed
+                * the "priv" context. Do not use it anymore!
+                */
+               priv = NULL;
+
+               if (parent)
+                       device_unlock(parent);
+       }
+
+       usb_put_dev(udev);
+}
+
+static int p54u_load_firmware(struct ieee80211_hw *dev,
+                             struct usb_interface *intf)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct p54u_priv *priv = dev->priv;
+       struct device *device = &udev->dev;
+       int err, i;
+
+       BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
+
+       init_completion(&priv->fw_wait_load);
+       i = p54_find_type(priv);
+       if (i < 0)
+               return i;
+
+       dev_info(&priv->udev->dev, "Loading firmware file %s\n",
+              p54u_fwlist[i].fw);
+
+       usb_get_dev(udev);
+       err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw,
+                                     device, GFP_KERNEL, priv,
+                                     p54u_load_firmware_cb);
+       if (err) {
+               dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
+                                         "(%d)!\n", p54u_fwlist[i].fw, err);
+               usb_put_dev(udev);
+       }
+
+       return err;
+}
+
+static int p54u_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct ieee80211_hw *dev;
+       struct p54u_priv *priv;
+       int err;
+       unsigned int i, recognized_pipes;
+
+       dev = p54_init_common(sizeof(*priv));
+
+       if (!dev) {
+               dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
+               return -ENOMEM;
+       }
+
+       priv = dev->priv;
+       priv->hw_type = P54U_INVALID_HW;
+
+       SET_IEEE80211_DEV(dev, &intf->dev);
+       usb_set_intfdata(intf, dev);
+       priv->udev = udev;
+       priv->intf = intf;
+       skb_queue_head_init(&priv->rx_queue);
+       init_usb_anchor(&priv->submitted);
+
+       usb_get_dev(udev);
+
+       /* really lazy and simple way of figuring out if we're a 3887 */
+       /* TODO: should just stick the identification in the device table */
+       i = intf->altsetting->desc.bNumEndpoints;
+       recognized_pipes = 0;
+       while (i--) {
+               switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
+               case P54U_PIPE_DATA:
+               case P54U_PIPE_MGMT:
+               case P54U_PIPE_BRG:
+               case P54U_PIPE_DEV:
+               case P54U_PIPE_DATA | USB_DIR_IN:
+               case P54U_PIPE_MGMT | USB_DIR_IN:
+               case P54U_PIPE_BRG | USB_DIR_IN:
+               case P54U_PIPE_DEV | USB_DIR_IN:
+               case P54U_PIPE_INT | USB_DIR_IN:
+                       recognized_pipes++;
+               }
+       }
+       priv->common.open = p54u_open;
+       priv->common.stop = p54u_stop;
+       if (recognized_pipes < P54U_PIPE_NUMBER) {
+#ifdef CONFIG_PM
+               /* ISL3887 needs a full reset on resume */
+               udev->reset_resume = 1;
+#endif /* CONFIG_PM */
+               err = p54u_device_reset(dev);
+
+               priv->hw_type = P54U_3887;
+               dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
+               priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
+               priv->common.tx = p54u_tx_lm87;
+               priv->upload_fw = p54u_upload_firmware_3887;
+       } else {
+               priv->hw_type = P54U_NET2280;
+               dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
+               priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
+               priv->common.tx = p54u_tx_net2280;
+               priv->upload_fw = p54u_upload_firmware_net2280;
+       }
+       err = p54u_load_firmware(dev, intf);
+       if (err) {
+               usb_put_dev(udev);
+               p54_free_common(dev);
+       }
+       return err;
+}
+
+static void p54u_disconnect(struct usb_interface *intf)
+{
+       struct ieee80211_hw *dev = usb_get_intfdata(intf);
+       struct p54u_priv *priv;
+
+       if (!dev)
+               return;
+
+       priv = dev->priv;
+       wait_for_completion(&priv->fw_wait_load);
+       p54_unregister_common(dev);
+
+       usb_put_dev(interface_to_usbdev(intf));
+       release_firmware(priv->fw);
+       p54_free_common(dev);
+}
+
+static int p54u_pre_reset(struct usb_interface *intf)
+{
+       struct ieee80211_hw *dev = usb_get_intfdata(intf);
+
+       if (!dev)
+               return -ENODEV;
+
+       p54u_stop(dev);
+       return 0;
+}
+
+static int p54u_resume(struct usb_interface *intf)
+{
+       struct ieee80211_hw *dev = usb_get_intfdata(intf);
+       struct p54u_priv *priv;
+
+       if (!dev)
+               return -ENODEV;
+
+       priv = dev->priv;
+       if (unlikely(!(priv->upload_fw && priv->fw)))
+               return 0;
+
+       return priv->upload_fw(dev);
+}
+
+static int p54u_post_reset(struct usb_interface *intf)
+{
+       struct ieee80211_hw *dev = usb_get_intfdata(intf);
+       struct p54u_priv *priv;
+       int err;
+
+       err = p54u_resume(intf);
+       if (err)
+               return err;
+
+       /* reinitialize old device state */
+       priv = dev->priv;
+       if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
+               ieee80211_restart_hw(dev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       return p54u_pre_reset(intf);
+}
+
+#endif /* CONFIG_PM */
+
+static struct usb_driver p54u_driver = {
+       .name   = "p54usb",
+       .id_table = p54u_table,
+       .probe = p54u_probe,
+       .disconnect = p54u_disconnect,
+       .pre_reset = p54u_pre_reset,
+       .post_reset = p54u_post_reset,
+#ifdef CONFIG_PM
+       .suspend = p54u_suspend,
+       .resume = p54u_resume,
+       .reset_resume = p54u_resume,
+#endif /* CONFIG_PM */
+       .soft_unbind = 1,
+       .disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(p54u_driver);
diff --git a/drivers/net/wireless/intersil/p54/p54usb.h b/drivers/net/wireless/intersil/p54/p54usb.h
new file mode 100644 (file)
index 0000000..a5f5f0f
--- /dev/null
@@ -0,0 +1,162 @@
+#ifndef P54USB_H
+#define P54USB_H
+
+/*
+ * Defines for USB based mac80211 Prism54 driver
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ *
+ * Based on the islsm (softmac prism54) driver, which is:
+ * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/* for isl3886 register definitions used on ver 1 devices */
+#include "p54pci.h"
+#include <linux/usb/net2280.h>
+
+/* pci */
+#define NET2280_BASE           0x10000000
+#define NET2280_BASE2          0x20000000
+
+/* gpio */
+#define P54U_BRG_POWER_UP      (1 << GPIO0_DATA)
+#define P54U_BRG_POWER_DOWN    (1 << GPIO1_DATA)
+
+/* devinit */
+#define NET2280_CLK_4Mhz       (15 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_30Mhz      (2 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_60Mhz      (1 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_CLK_STOP       (0 << LOCAL_CLOCK_FREQUENCY)
+#define NET2280_PCI_ENABLE     (1 << PCI_ENABLE)
+#define NET2280_PCI_SOFT_RESET (1 << PCI_SOFT_RESET)
+
+/* endpoints */
+#define NET2280_CLEAR_NAK_OUT_PACKETS_MODE     (1 << CLEAR_NAK_OUT_PACKETS_MODE)
+#define NET2280_FIFO_FLUSH                     (1 << FIFO_FLUSH)
+
+/* irq */
+#define NET2280_USB_INTERRUPT_ENABLE           (1 << USB_INTERRUPT_ENABLE)
+#define NET2280_PCI_INTA_INTERRUPT             (1 << PCI_INTA_INTERRUPT)
+#define NET2280_PCI_INTA_INTERRUPT_ENABLE      (1 << PCI_INTA_INTERRUPT_ENABLE)
+
+/* registers */
+#define NET2280_DEVINIT                0x00
+#define NET2280_USBIRQENB1     0x24
+#define NET2280_IRQSTAT1       0x2c
+#define NET2280_FIFOCTL         0x38
+#define NET2280_GPIOCTL                0x50
+#define NET2280_RELNUM         0x88
+#define NET2280_EPA_RSP                0x324
+#define NET2280_EPA_STAT       0x32c
+#define NET2280_EPB_STAT       0x34c
+#define NET2280_EPC_RSP                0x364
+#define NET2280_EPC_STAT       0x36c
+#define NET2280_EPD_STAT       0x38c
+
+#define NET2280_EPA_CFG     0x320
+#define NET2280_EPB_CFG     0x340
+#define NET2280_EPC_CFG     0x360
+#define NET2280_EPD_CFG     0x380
+#define NET2280_EPE_CFG     0x3A0
+#define NET2280_EPF_CFG     0x3C0
+#define P54U_DEV_BASE 0x40000000
+
+struct net2280_tx_hdr {
+       __le32 device_addr;
+       __le16 len;
+       __le16 follower;        /* ? */
+       u8 padding[8];
+} __packed;
+
+struct lm87_tx_hdr {
+       __le32 device_addr;
+       __le32 chksum;
+} __packed;
+
+/* Some flags for the isl hardware registers controlling DMA inside the
+ * chip */
+#define ISL38XX_DMA_STATUS_DONE                        0x00000001
+#define ISL38XX_DMA_STATUS_READY               0x00000002
+#define NET2280_EPA_FIFO_PCI_ADDR              0x20000000
+#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER     0x00000004
+
+enum net2280_op_type {
+       NET2280_BRG_U32         = 0x001F,
+       NET2280_BRG_CFG_U32     = 0x000F,
+       NET2280_BRG_CFG_U16     = 0x0003,
+       NET2280_DEV_U32         = 0x080F,
+       NET2280_DEV_CFG_U32     = 0x088F,
+       NET2280_DEV_CFG_U16     = 0x0883
+};
+
+struct net2280_reg_write {
+       __le16 port;
+       __le32 addr;
+       __le32 val;
+} __packed;
+
+struct net2280_reg_read {
+       __le16 port;
+       __le32 addr;
+} __packed;
+
+#define P54U_FW_BLOCK 2048
+
+#define X2_SIGNATURE "x2  "
+#define X2_SIGNATURE_SIZE 4
+
+struct x2_header {
+       u8 signature[X2_SIGNATURE_SIZE];
+       __le32 fw_load_addr;
+       __le32 fw_length;
+       __le32 crc;
+} __packed;
+
+/* pipes 3 and 4 are not used by the driver */
+#define P54U_PIPE_NUMBER 9
+
+enum p54u_pipe_addr {
+        P54U_PIPE_DATA = 0x01,
+        P54U_PIPE_MGMT = 0x02,
+        P54U_PIPE_3 = 0x03,
+        P54U_PIPE_4 = 0x04,
+        P54U_PIPE_BRG = 0x0d,
+        P54U_PIPE_DEV = 0x0e,
+        P54U_PIPE_INT = 0x0f
+};
+
+struct p54u_rx_info {
+       struct urb *urb;
+       struct ieee80211_hw *dev;
+};
+
+enum p54u_hw_type {
+       P54U_INVALID_HW,
+       P54U_NET2280,
+       P54U_3887,
+
+       /* keep last */
+       __NUM_P54U_HWTYPES,
+};
+
+struct p54u_priv {
+       struct p54_common common;
+       struct usb_device *udev;
+       struct usb_interface *intf;
+       int (*upload_fw)(struct ieee80211_hw *dev);
+
+       enum p54u_hw_type hw_type;
+       spinlock_t lock;
+       struct sk_buff_head rx_queue;
+       struct usb_anchor submitted;
+       const struct firmware *fw;
+
+       /* asynchronous firmware callback */
+       struct completion fw_wait_load;
+};
+
+#endif /* P54USB_H */
diff --git a/drivers/net/wireless/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c
new file mode 100644 (file)
index 0000000..24e5ff9
--- /dev/null
@@ -0,0 +1,940 @@
+/*
+ * Common code for mac80211 Prism54 drivers
+ *
+ * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
+ * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
+ * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * Based on:
+ * - the islsm (softmac prism54) driver, which is:
+ *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
+ * - stlc45xx driver
+ *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/export.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <asm/div64.h>
+
+#include <net/mac80211.h>
+
+#include "p54.h"
+#include "lmac.h"
+
+#ifdef P54_MM_DEBUG
+static void p54_dump_tx_queue(struct p54_common *priv)
+{
+       unsigned long flags;
+       struct ieee80211_tx_info *info;
+       struct p54_tx_info *range;
+       struct sk_buff *skb;
+       struct p54_hdr *hdr;
+       unsigned int i = 0;
+       u32 prev_addr;
+       u32 largest_hole = 0, free;
+
+       spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       wiphy_debug(priv->hw->wiphy, "/ --- tx queue dump (%d entries) ---\n",
+                   skb_queue_len(&priv->tx_queue));
+
+       prev_addr = priv->rx_start;
+       skb_queue_walk(&priv->tx_queue, skb) {
+               info = IEEE80211_SKB_CB(skb);
+               range = (void *) info->rate_driver_data;
+               hdr = (void *) skb->data;
+
+               free = range->start_addr - prev_addr;
+               wiphy_debug(priv->hw->wiphy,
+                           "| [%02d] => [skb:%p skb_len:0x%04x "
+                           "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
+                           "mem:{start:%04x end:%04x, free:%d}]\n",
+                           i++, skb, skb->len,
+                           le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
+                           le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
+                           range->start_addr, range->end_addr, free);
+
+               prev_addr = range->end_addr;
+               largest_hole = max(largest_hole, free);
+       }
+       free = priv->rx_end - prev_addr;
+       largest_hole = max(largest_hole, free);
+       wiphy_debug(priv->hw->wiphy,
+                   "\\ --- [free: %d], largest free block: %d ---\n",
+                   free, largest_hole);
+       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+}
+#endif /* P54_MM_DEBUG */
+
+/*
+ * So, the firmware is somewhat stupid and doesn't know what places in its
+ * memory incoming data should go to. By poking around in the firmware, we
+ * can find some unused memory to upload our packets to. However, data that we
+ * want the card to TX needs to stay intact until the card has told us that
+ * it is done with it. This function finds empty places we can upload to and
+ * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or
+ * p54_free_skb frees allocated areas.
+ */
+static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct sk_buff *entry, *target_skb = NULL;
+       struct ieee80211_tx_info *info;
+       struct p54_tx_info *range;
+       struct p54_hdr *data = (void *) skb->data;
+       unsigned long flags;
+       u32 last_addr = priv->rx_start;
+       u32 target_addr = priv->rx_start;
+       u16 len = priv->headroom + skb->len + priv->tailroom + 3;
+
+       info = IEEE80211_SKB_CB(skb);
+       range = (void *) info->rate_driver_data;
+       len = (range->extra_len + len) & ~0x3;
+
+       spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) {
+               /*
+                * The tx_queue is now really full.
+                *
+                * TODO: check if the device has crashed and reset it.
+                */
+               spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+               return -EBUSY;
+       }
+
+       skb_queue_walk(&priv->tx_queue, entry) {
+               u32 hole_size;
+               info = IEEE80211_SKB_CB(entry);
+               range = (void *) info->rate_driver_data;
+               hole_size = range->start_addr - last_addr;
+
+               if (!target_skb && hole_size >= len) {
+                       target_skb = entry->prev;
+                       hole_size -= len;
+                       target_addr = last_addr;
+                       break;
+               }
+               last_addr = range->end_addr;
+       }
+       if (unlikely(!target_skb)) {
+               if (priv->rx_end - last_addr >= len) {
+                       target_skb = priv->tx_queue.prev;
+                       if (!skb_queue_empty(&priv->tx_queue)) {
+                               info = IEEE80211_SKB_CB(target_skb);
+                               range = (void *)info->rate_driver_data;
+                               target_addr = range->end_addr;
+                       }
+               } else {
+                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+                       return -ENOSPC;
+               }
+       }
+
+       info = IEEE80211_SKB_CB(skb);
+       range = (void *) info->rate_driver_data;
+       range->start_addr = target_addr;
+       range->end_addr = target_addr + len;
+       data->req_id = cpu_to_le32(target_addr + priv->headroom);
+       if (IS_DATA_FRAME(skb) &&
+           unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
+               priv->beacon_req_id = data->req_id;
+
+       __skb_queue_after(&priv->tx_queue, target_skb, skb);
+       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+       return 0;
+}
+
+static void p54_tx_pending(struct p54_common *priv)
+{
+       struct sk_buff *skb;
+       int ret;
+
+       skb = skb_dequeue(&priv->tx_pending);
+       if (unlikely(!skb))
+               return ;
+
+       ret = p54_assign_address(priv, skb);
+       if (unlikely(ret))
+               skb_queue_head(&priv->tx_pending, skb);
+       else
+               priv->tx(priv->hw, skb);
+}
+
+static void p54_wake_queues(struct p54_common *priv)
+{
+       unsigned long flags;
+       unsigned int i;
+
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return ;
+
+       p54_tx_pending(priv);
+
+       spin_lock_irqsave(&priv->tx_stats_lock, flags);
+       for (i = 0; i < priv->hw->queues; i++) {
+               if (priv->tx_stats[i + P54_QUEUE_DATA].len <
+                   priv->tx_stats[i + P54_QUEUE_DATA].limit)
+                       ieee80211_wake_queue(priv->hw, i);
+       }
+       spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+}
+
+static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
+                                      struct sk_buff *skb,
+                                      const u16 p54_queue)
+{
+       struct p54_tx_queue_stats *queue;
+       unsigned long flags;
+
+       if (WARN_ON(p54_queue >= P54_QUEUE_NUM))
+               return -EINVAL;
+
+       queue = &priv->tx_stats[p54_queue];
+
+       spin_lock_irqsave(&priv->tx_stats_lock, flags);
+       if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) {
+               spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+               return -ENOSPC;
+       }
+
+       queue->len++;
+       queue->count++;
+
+       if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) {
+               u16 ac_queue = p54_queue - P54_QUEUE_DATA;
+               ieee80211_stop_queue(priv->hw, ac_queue);
+       }
+
+       spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+       return 0;
+}
+
+static void p54_tx_qos_accounting_free(struct p54_common *priv,
+                                      struct sk_buff *skb)
+{
+       if (IS_DATA_FRAME(skb)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&priv->tx_stats_lock, flags);
+               priv->tx_stats[GET_HW_QUEUE(skb)].len--;
+               spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
+
+               if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
+                       if (priv->beacon_req_id == GET_REQ_ID(skb)) {
+                               /* this is the  active beacon set anymore */
+                               priv->beacon_req_id = 0;
+                       }
+                       complete(&priv->beacon_comp);
+               }
+       }
+       p54_wake_queues(priv);
+}
+
+void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       struct p54_common *priv = dev->priv;
+       if (unlikely(!skb))
+               return ;
+
+       skb_unlink(skb, &priv->tx_queue);
+       p54_tx_qos_accounting_free(priv, skb);
+       ieee80211_free_txskb(dev, skb);
+}
+EXPORT_SYMBOL_GPL(p54_free_skb);
+
+static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
+                                              const __le32 req_id)
+{
+       struct sk_buff *entry;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       skb_queue_walk(&priv->tx_queue, entry) {
+               struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
+
+               if (hdr->req_id == req_id) {
+                       __skb_unlink(entry, &priv->tx_queue);
+                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+                       p54_tx_qos_accounting_free(priv, entry);
+                       return entry;
+               }
+       }
+       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
+       return NULL;
+}
+
+void p54_tx(struct p54_common *priv, struct sk_buff *skb)
+{
+       skb_queue_tail(&priv->tx_pending, skb);
+       p54_tx_pending(priv);
+}
+
+static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
+{
+       if (priv->rxhw != 5) {
+               return ((rssi * priv->cur_rssi->mul) / 64 +
+                        priv->cur_rssi->add) / 4;
+       } else {
+               /*
+                * TODO: find the correct formula
+                */
+               return rssi / 2 - 110;
+       }
+}
+
+/*
+ * Even if the firmware is capable of dealing with incoming traffic,
+ * while dozing, we have to prepared in case mac80211 uses PS-POLL
+ * to retrieve outstanding frames from our AP.
+ * (see comment in net/mac80211/mlme.c @ line 1993)
+ */
+static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (void *) skb->data;
+       struct ieee80211_tim_ie *tim_ie;
+       u8 *tim;
+       u8 tim_len;
+       bool new_psm;
+
+       /* only beacons have a TIM IE */
+       if (!ieee80211_is_beacon(hdr->frame_control))
+               return;
+
+       if (!priv->aid)
+               return;
+
+       /* only consider beacons from the associated BSSID */
+       if (!ether_addr_equal_64bits(hdr->addr3, priv->bssid))
+               return;
+
+       tim = p54_find_ie(skb, WLAN_EID_TIM);
+       if (!tim)
+               return;
+
+       tim_len = tim[1];
+       tim_ie = (struct ieee80211_tim_ie *) &tim[2];
+
+       new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
+       if (new_psm != priv->powersave_override) {
+               priv->powersave_override = new_psm;
+               p54_set_ps(priv);
+       }
+}
+
+static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
+       struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+       u16 freq = le16_to_cpu(hdr->freq);
+       size_t header_len = sizeof(*hdr);
+       u32 tsf32;
+       u8 rate = hdr->rate & 0xf;
+
+       /*
+        * If the device is in a unspecified state we have to
+        * ignore all data frames. Else we could end up with a
+        * nasty crash.
+        */
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return 0;
+
+       if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD)))
+               return 0;
+
+       if (hdr->decrypt_status == P54_DECRYPT_OK)
+               rx_status->flag |= RX_FLAG_DECRYPTED;
+       if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
+           (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
+               rx_status->flag |= RX_FLAG_MMIC_ERROR;
+
+       rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
+       if (hdr->rate & 0x10)
+               rx_status->flag |= RX_FLAG_SHORTPRE;
+       if (priv->hw->conf.chandef.chan->band == IEEE80211_BAND_5GHZ)
+               rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;
+       else
+               rx_status->rate_idx = rate;
+
+       rx_status->freq = freq;
+       rx_status->band =  priv->hw->conf.chandef.chan->band;
+       rx_status->antenna = hdr->antenna;
+
+       tsf32 = le32_to_cpu(hdr->tsf32);
+       if (tsf32 < priv->tsf_low32)
+               priv->tsf_high32++;
+       rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
+       priv->tsf_low32 = tsf32;
+
+       /* LMAC API Page 10/29 - s_lm_data_in - clock
+        * "usec accurate timestamp of hardware clock
+        * at end of frame (before OFDM SIFS EOF padding"
+        */
+       rx_status->flag |= RX_FLAG_MACTIME_END;
+
+       if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+               header_len += hdr->align[0];
+
+       skb_pull(skb, header_len);
+       skb_trim(skb, le16_to_cpu(hdr->len));
+       if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
+               p54_pspoll_workaround(priv, skb);
+
+       ieee80211_rx_irqsafe(priv->hw, skb);
+
+       ieee80211_queue_delayed_work(priv->hw, &priv->work,
+                          msecs_to_jiffies(P54_STATISTICS_UPDATE));
+
+       return -1;
+}
+
+static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
+       struct ieee80211_tx_info *info;
+       struct p54_hdr *entry_hdr;
+       struct p54_tx_data *entry_data;
+       struct sk_buff *entry;
+       unsigned int pad = 0, frame_len;
+       int count, idx;
+
+       entry = p54_find_and_unlink_skb(priv, hdr->req_id);
+       if (unlikely(!entry))
+               return ;
+
+       frame_len = entry->len;
+       info = IEEE80211_SKB_CB(entry);
+       entry_hdr = (struct p54_hdr *) entry->data;
+       entry_data = (struct p54_tx_data *) entry_hdr->data;
+       priv->stats.dot11ACKFailureCount += payload->tries - 1;
+
+       /*
+        * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
+        * generated by the driver. Therefore tx_status is bogus
+        * and we don't want to confuse the mac80211 stack.
+        */
+       if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
+               dev_kfree_skb_any(entry);
+               return ;
+       }
+
+       /*
+        * Clear manually, ieee80211_tx_info_clear_status would
+        * clear the counts too and we need them.
+        */
+       memset(&info->status.ack_signal, 0,
+              sizeof(struct ieee80211_tx_info) -
+              offsetof(struct ieee80211_tx_info, status.ack_signal));
+       BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
+                             status.ack_signal) != 20);
+
+       if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
+               pad = entry_data->align[0];
+
+       /* walk through the rates array and adjust the counts */
+       count = payload->tries;
+       for (idx = 0; idx < 4; idx++) {
+               if (count >= info->status.rates[idx].count) {
+                       count -= info->status.rates[idx].count;
+               } else if (count > 0) {
+                       info->status.rates[idx].count = count;
+                       count = 0;
+               } else {
+                       info->status.rates[idx].idx = -1;
+                       info->status.rates[idx].count = 0;
+               }
+       }
+
+       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+            !(payload->status & P54_TX_FAILED))
+               info->flags |= IEEE80211_TX_STAT_ACK;
+       if (payload->status & P54_TX_PSM_CANCELLED)
+               info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
+       info->status.ack_signal = p54_rssi_to_dbm(priv,
+                                                 (int)payload->ack_rssi);
+
+       /* Undo all changes to the frame. */
+       switch (entry_data->key_type) {
+       case P54_CRYPTO_TKIPMICHAEL: {
+               u8 *iv = (u8 *)(entry_data->align + pad +
+                               entry_data->crypt_offset);
+
+               /* Restore the original TKIP IV. */
+               iv[2] = iv[0];
+               iv[0] = iv[1];
+               iv[1] = (iv[0] | 0x20) & 0x7f;  /* WEPSeed - 8.3.2.2 */
+
+               frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
+               break;
+               }
+       case P54_CRYPTO_AESCCMP:
+               frame_len -= 8; /* remove CCMP_MIC */
+               break;
+       case P54_CRYPTO_WEP:
+               frame_len -= 4; /* remove WEP_ICV */
+               break;
+       }
+
+       skb_trim(entry, frame_len);
+       skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
+       ieee80211_tx_status_irqsafe(priv->hw, entry);
+}
+
+static void p54_rx_eeprom_readback(struct p54_common *priv,
+                                  struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
+       struct sk_buff *tmp;
+
+       if (!priv->eeprom)
+               return ;
+
+       if (priv->fw_var >= 0x509) {
+               memcpy(priv->eeprom, eeprom->v2.data,
+                      le16_to_cpu(eeprom->v2.len));
+       } else {
+               memcpy(priv->eeprom, eeprom->v1.data,
+                      le16_to_cpu(eeprom->v1.len));
+       }
+
+       priv->eeprom = NULL;
+       tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+       dev_kfree_skb_any(tmp);
+       complete(&priv->eeprom_comp);
+}
+
+static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
+       struct sk_buff *tmp;
+       struct ieee80211_channel *chan;
+       unsigned int i, rssi, tx, cca, dtime, dtotal, dcca, dtx, drssi, unit;
+       u32 tsf32;
+
+       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
+               return ;
+
+       tsf32 = le32_to_cpu(stats->tsf32);
+       if (tsf32 < priv->tsf_low32)
+               priv->tsf_high32++;
+       priv->tsf_low32 = tsf32;
+
+       priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
+       priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
+       priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
+
+       priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
+
+       /*
+        * STSW450X LMAC API page 26 - 3.8 Statistics
+        * "The exact measurement period can be derived from the
+        * timestamp member".
+        */
+       dtime = tsf32 - priv->survey_raw.timestamp;
+
+       /*
+        * STSW450X LMAC API page 26 - 3.8.1 Noise histogram
+        * The LMAC samples RSSI, CCA and transmit state at regular
+        * periods (typically 8 times per 1k [as in 1024] usec).
+        */
+       cca = le32_to_cpu(stats->sample_cca);
+       tx = le32_to_cpu(stats->sample_tx);
+       rssi = 0;
+       for (i = 0; i < ARRAY_SIZE(stats->sample_noise); i++)
+               rssi += le32_to_cpu(stats->sample_noise[i]);
+
+       dcca = cca - priv->survey_raw.cached_cca;
+       drssi = rssi - priv->survey_raw.cached_rssi;
+       dtx = tx - priv->survey_raw.cached_tx;
+       dtotal = dcca + drssi + dtx;
+
+       /*
+        * update statistics when more than a second is over since the
+        * last call, or when a update is badly needed.
+        */
+       if (dtotal && (priv->update_stats || dtime >= USEC_PER_SEC) &&
+           dtime >= dtotal) {
+               priv->survey_raw.timestamp = tsf32;
+               priv->update_stats = false;
+               unit = dtime / dtotal;
+
+               if (dcca) {
+                       priv->survey_raw.cca += dcca * unit;
+                       priv->survey_raw.cached_cca = cca;
+               }
+               if (dtx) {
+                       priv->survey_raw.tx += dtx * unit;
+                       priv->survey_raw.cached_tx = tx;
+               }
+               if (drssi) {
+                       priv->survey_raw.rssi += drssi * unit;
+                       priv->survey_raw.cached_rssi = rssi;
+               }
+
+               /* 1024 usec / 8 times = 128 usec / time */
+               if (!(priv->phy_ps || priv->phy_idle))
+                       priv->survey_raw.active += dtotal * unit;
+               else
+                       priv->survey_raw.active += (dcca + dtx) * unit;
+       }
+
+       chan = priv->curchan;
+       if (chan) {
+               struct survey_info *survey = &priv->survey[chan->hw_value];
+               survey->noise = clamp(priv->noise, -128, 127);
+               survey->time = priv->survey_raw.active;
+               survey->time_tx = priv->survey_raw.tx;
+               survey->time_busy = priv->survey_raw.tx +
+                       priv->survey_raw.cca;
+               do_div(survey->time, 1024);
+               do_div(survey->time_tx, 1024);
+               do_div(survey->time_busy, 1024);
+       }
+
+       tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
+       dev_kfree_skb_any(tmp);
+       complete(&priv->stat_comp);
+}
+
+static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+       struct p54_trap *trap = (struct p54_trap *) hdr->data;
+       u16 event = le16_to_cpu(trap->event);
+       u16 freq = le16_to_cpu(trap->frequency);
+
+       switch (event) {
+       case P54_TRAP_BEACON_TX:
+               break;
+       case P54_TRAP_RADAR:
+               wiphy_info(priv->hw->wiphy, "radar (freq:%d MHz)\n", freq);
+               break;
+       case P54_TRAP_NO_BEACON:
+               if (priv->vif)
+                       ieee80211_beacon_loss(priv->vif);
+               break;
+       case P54_TRAP_SCAN:
+               break;
+       case P54_TRAP_TBTT:
+               break;
+       case P54_TRAP_TIMER:
+               break;
+       case P54_TRAP_FAA_RADIO_OFF:
+               wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
+               break;
+       case P54_TRAP_FAA_RADIO_ON:
+               wiphy_rfkill_set_hw_state(priv->hw->wiphy, false);
+               break;
+       default:
+               wiphy_info(priv->hw->wiphy, "received event:%x freq:%d\n",
+                          event, freq);
+               break;
+       }
+}
+
+static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
+{
+       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
+
+       switch (le16_to_cpu(hdr->type)) {
+       case P54_CONTROL_TYPE_TXDONE:
+               p54_rx_frame_sent(priv, skb);
+               break;
+       case P54_CONTROL_TYPE_TRAP:
+               p54_rx_trap(priv, skb);
+               break;
+       case P54_CONTROL_TYPE_BBP:
+               break;
+       case P54_CONTROL_TYPE_STAT_READBACK:
+               p54_rx_stats(priv, skb);
+               break;
+       case P54_CONTROL_TYPE_EEPROM_READBACK:
+               p54_rx_eeprom_readback(priv, skb);
+               break;
+       default:
+               wiphy_debug(priv->hw->wiphy,
+                           "not handling 0x%02x type control frame\n",
+                           le16_to_cpu(hdr->type));
+               break;
+       }
+       return 0;
+}
+
+/* returns zero if skb can be reused */
+int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
+{
+       struct p54_common *priv = dev->priv;
+       u16 type = le16_to_cpu(*((__le16 *)skb->data));
+
+       if (type & P54_HDR_FLAG_CONTROL)
+               return p54_rx_control(priv, skb);
+       else
+               return p54_rx_data(priv, skb);
+}
+EXPORT_SYMBOL_GPL(p54_rx);
+
+static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
+                               struct ieee80211_tx_info *info,
+                               struct ieee80211_sta *sta,
+                               u8 *queue, u32 *extra_len, u16 *flags, u16 *aid,
+                               bool *burst_possible)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+       if (ieee80211_is_data_qos(hdr->frame_control))
+               *burst_possible = true;
+       else
+               *burst_possible = false;
+
+       if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
+               *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
+
+       if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)
+               *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+
+       if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
+               *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+
+       *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
+
+       switch (priv->mode) {
+       case NL80211_IFTYPE_MONITOR:
+               /*
+                * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
+                * every frame in promiscuous/monitor mode.
+                * see STSW45x0C LMAC API - page 12.
+                */
+               *aid = 0;
+               *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC;
+               break;
+       case NL80211_IFTYPE_STATION:
+               *aid = 1;
+               break;
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_MESH_POINT:
+               if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+                       *aid = 0;
+                       *queue = P54_QUEUE_CAB;
+                       return;
+               }
+
+               if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
+                       if (ieee80211_is_probe_resp(hdr->frame_control)) {
+                               *aid = 0;
+                               *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
+                                         P54_HDR_FLAG_DATA_OUT_NOCANCEL;
+                               return;
+                       } else if (ieee80211_is_beacon(hdr->frame_control)) {
+                               *aid = 0;
+
+                               if (info->flags & IEEE80211_TX_CTL_INJECTED) {
+                                       /*
+                                        * Injecting beacons on top of a AP is
+                                        * not a good idea... nevertheless,
+                                        * it should be doable.
+                                        */
+
+                                       return;
+                               }
+
+                               *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
+                               *queue = P54_QUEUE_BEACON;
+                               *extra_len = IEEE80211_MAX_TIM_LEN;
+                               return;
+                       }
+               }
+
+               if (sta)
+                       *aid = sta->aid;
+               break;
+       }
+}
+
+static u8 p54_convert_algo(u32 cipher)
+{
+       switch (cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               return P54_CRYPTO_WEP;
+       case WLAN_CIPHER_SUITE_TKIP:
+               return P54_CRYPTO_TKIPMICHAEL;
+       case WLAN_CIPHER_SUITE_CCMP:
+               return P54_CRYPTO_AESCCMP;
+       default:
+               return 0;
+       }
+}
+
+void p54_tx_80211(struct ieee80211_hw *dev,
+                 struct ieee80211_tx_control *control,
+                 struct sk_buff *skb)
+{
+       struct p54_common *priv = dev->priv;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct p54_tx_info *p54info;
+       struct p54_hdr *hdr;
+       struct p54_tx_data *txhdr;
+       unsigned int padding, len, extra_len = 0;
+       int i, j, ridx;
+       u16 hdr_flags = 0, aid = 0;
+       u8 rate, queue = 0, crypt_offset = 0;
+       u8 cts_rate = 0x20;
+       u8 rc_flags;
+       u8 calculated_tries[4];
+       u8 nrates = 0, nremaining = 8;
+       bool burst_allowed = false;
+
+       p54_tx_80211_header(priv, skb, info, control->sta, &queue, &extra_len,
+                           &hdr_flags, &aid, &burst_allowed);
+
+       if (p54_tx_qos_accounting_alloc(priv, skb, queue)) {
+               ieee80211_free_txskb(dev, skb);
+               return;
+       }
+
+       padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
+       len = skb->len;
+
+       if (info->control.hw_key) {
+               crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
+               if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+                       u8 *iv = (u8 *)(skb->data + crypt_offset);
+                       /*
+                        * The firmware excepts that the IV has to have
+                        * this special format
+                        */
+                       iv[1] = iv[0];
+                       iv[0] = iv[2];
+                       iv[2] = 0;
+               }
+       }
+
+       txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
+       hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
+
+       if (padding)
+               hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
+       hdr->type = cpu_to_le16(aid);
+       hdr->rts_tries = info->control.rates[0].count;
+
+       /*
+        * we register the rates in perfect order, and
+        * RTS/CTS won't happen on 5 GHz
+        */
+       cts_rate = info->control.rts_cts_rate_idx;
+
+       memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
+
+       /* see how many rates got used */
+       for (i = 0; i < dev->max_rates; i++) {
+               if (info->control.rates[i].idx < 0)
+                       break;
+               nrates++;
+       }
+
+       /* limit tries to 8/nrates per rate */
+       for (i = 0; i < nrates; i++) {
+               /*
+                * The magic expression here is equivalent to 8/nrates for
+                * all values that matter, but avoids division and jumps.
+                * Note that nrates can only take the values 1 through 4.
+                */
+               calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
+                                                info->control.rates[i].count);
+               nremaining -= calculated_tries[i];
+       }
+
+       /* if there are tries left, distribute from back to front */
+       for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
+               int tmp = info->control.rates[i].count - calculated_tries[i];
+
+               if (tmp <= 0)
+                       continue;
+               /* RC requested more tries at this rate */
+
+               tmp = min_t(int, tmp, nremaining);
+               calculated_tries[i] += tmp;
+               nremaining -= tmp;
+       }
+
+       ridx = 0;
+       for (i = 0; i < nrates && ridx < 8; i++) {
+               /* we register the rates in perfect order */
+               rate = info->control.rates[i].idx;
+               if (info->band == IEEE80211_BAND_5GHZ)
+                       rate += 4;
+
+               /* store the count we actually calculated for TX status */
+               info->control.rates[i].count = calculated_tries[i];
+
+               rc_flags = info->control.rates[i].flags;
+               if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
+                       rate |= 0x10;
+                       cts_rate |= 0x10;
+               }
+               if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
+                       burst_allowed = false;
+                       rate |= 0x40;
+               } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+                       rate |= 0x20;
+                       burst_allowed = false;
+               }
+               for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
+                       txhdr->rateset[ridx] = rate;
+                       ridx++;
+               }
+       }
+
+       if (burst_allowed)
+               hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST;
+
+       /* TODO: enable bursting */
+       hdr->flags = cpu_to_le16(hdr_flags);
+       hdr->tries = ridx;
+       txhdr->rts_rate_idx = 0;
+       if (info->control.hw_key) {
+               txhdr->key_type = p54_convert_algo(info->control.hw_key->cipher);
+               txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
+               memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
+               if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
+                       /* reserve space for the MIC key */
+                       len += 8;
+                       memcpy(skb_put(skb, 8), &(info->control.hw_key->key
+                               [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
+               }
+               /* reserve some space for ICV */
+               len += info->control.hw_key->icv_len;
+               memset(skb_put(skb, info->control.hw_key->icv_len), 0,
+                      info->control.hw_key->icv_len);
+       } else {
+               txhdr->key_type = 0;
+               txhdr->key_len = 0;
+       }
+       txhdr->crypt_offset = crypt_offset;
+       txhdr->hw_queue = queue;
+       txhdr->backlog = priv->tx_stats[queue].len - 1;
+       memset(txhdr->durations, 0, sizeof(txhdr->durations));
+       txhdr->tx_antenna = 2 & priv->tx_diversity_mask;
+       if (priv->rxhw == 5) {
+               txhdr->longbow.cts_rate = cts_rate;
+               txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
+       } else {
+               txhdr->normal.output_power = priv->output_power;
+               txhdr->normal.cts_rate = cts_rate;
+       }
+       if (padding)
+               txhdr->align[0] = padding;
+
+       hdr->len = cpu_to_le16(len);
+       /* modifies skb->cb and with it info, so must be last! */
+       p54info = (void *) info->rate_driver_data;
+       p54info->extra_len = extra_len;
+
+       p54_tx(priv, skb);
+}
diff --git a/drivers/net/wireless/p54/Kconfig b/drivers/net/wireless/p54/Kconfig
deleted file mode 100644 (file)
index cdafb8c..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-config P54_COMMON
-       tristate "Softmac Prism54 support"
-       depends on MAC80211
-       select FW_LOADER
-       select CRC_CCITT
-       ---help---
-         This is common code for isl38xx/stlc45xx based modules.
-         This module does nothing by itself - the USB/PCI/SPI front-ends
-         also need to be enabled in order to support any devices.
-
-         These devices require softmac firmware which can be found at
-         <http://wireless.kernel.org/en/users/Drivers/p54>
-
-         If you choose to build a module, it'll be called p54common.
-
-config P54_USB
-       tristate "Prism54 USB support"
-       depends on P54_COMMON && USB
-       select CRC32
-       ---help---
-         This driver is for USB isl38xx based wireless cards.
-
-         These devices require softmac firmware which can be found at
-         <http://wireless.kernel.org/en/users/Drivers/p54>
-
-         If you choose to build a module, it'll be called p54usb.
-
-config P54_PCI
-       tristate "Prism54 PCI support"
-       depends on P54_COMMON && PCI
-       ---help---
-         This driver is for PCI isl38xx based wireless cards.
-         This driver supports most devices that are supported by the
-         fullmac prism54 driver plus many devices which are not
-         supported by the fullmac driver/firmware.
-
-         This driver requires softmac firmware which can be found at
-         <http://wireless.kernel.org/en/users/Drivers/p54>
-
-         If you choose to build a module, it'll be called p54pci.
-
-config P54_SPI
-       tristate "Prism54 SPI (stlc45xx) support"
-       depends on P54_COMMON && SPI_MASTER
-       ---help---
-         This driver is for stlc4550 or stlc4560 based wireless chips
-         such as Nokia's N800/N810 Portable Internet Tablet.
-
-         If you choose to build a module, it'll be called p54spi.
-
-config P54_SPI_DEFAULT_EEPROM
-       bool "Include fallback EEPROM blob"
-       depends on P54_SPI
-       default n
-       ---help---
-        Unlike the PCI or USB devices, the SPI variants don't have
-        a dedicated EEPROM chip to store all device specific values
-        for calibration, country and interface settings.
-
-        The driver will try to load the image "3826.eeprom", if the
-        file is put at the right place. (usually /lib/firmware.)
-
-        Only if this request fails, this option will provide a
-        backup set of generic values to get the device working.
-
-        Enabling this option adds about 4k to p54spi.
-
-config P54_LEDS
-       bool
-       depends on P54_COMMON && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = P54_COMMON)
-       default y
diff --git a/drivers/net/wireless/p54/Makefile b/drivers/net/wireless/p54/Makefile
deleted file mode 100644 (file)
index b542e68..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-p54common-objs                 := eeprom.o fwio.o txrx.o main.o
-p54common-$(CONFIG_P54_LEDS)   += led.o
-
-obj-$(CONFIG_P54_COMMON)       += p54common.o
-obj-$(CONFIG_P54_USB)          += p54usb.o
-obj-$(CONFIG_P54_PCI)          += p54pci.o
-obj-$(CONFIG_P54_SPI)          += p54spi.o
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
deleted file mode 100644 (file)
index 2fe713e..0000000
+++ /dev/null
@@ -1,982 +0,0 @@
-/*
- * EEPROM parser code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-#include <linux/sort.h>
-#include <linux/slab.h>
-
-#include <net/mac80211.h>
-#include <linux/crc-ccitt.h>
-#include <linux/export.h>
-
-#include "p54.h"
-#include "eeprom.h"
-#include "lmac.h"
-
-static struct ieee80211_rate p54_bgrates[] = {
-       { .bitrate = 10, .hw_value = 0, },
-       { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-       { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-       { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE },
-       { .bitrate = 60, .hw_value = 4, },
-       { .bitrate = 90, .hw_value = 5, },
-       { .bitrate = 120, .hw_value = 6, },
-       { .bitrate = 180, .hw_value = 7, },
-       { .bitrate = 240, .hw_value = 8, },
-       { .bitrate = 360, .hw_value = 9, },
-       { .bitrate = 480, .hw_value = 10, },
-       { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct ieee80211_rate p54_arates[] = {
-       { .bitrate = 60, .hw_value = 4, },
-       { .bitrate = 90, .hw_value = 5, },
-       { .bitrate = 120, .hw_value = 6, },
-       { .bitrate = 180, .hw_value = 7, },
-       { .bitrate = 240, .hw_value = 8, },
-       { .bitrate = 360, .hw_value = 9, },
-       { .bitrate = 480, .hw_value = 10, },
-       { .bitrate = 540, .hw_value = 11, },
-};
-
-static struct p54_rssi_db_entry p54_rssi_default = {
-       /*
-        * The defaults are taken from usb-logs of the
-        * vendor driver. So, they should be safe to
-        * use in case we can't get a match from the
-        * rssi <-> dBm conversion database.
-        */
-       .mul = 130,
-       .add = -398,
-};
-
-#define CHAN_HAS_CAL           BIT(0)
-#define CHAN_HAS_LIMIT         BIT(1)
-#define CHAN_HAS_CURVE         BIT(2)
-#define CHAN_HAS_ALL           (CHAN_HAS_CAL | CHAN_HAS_LIMIT | CHAN_HAS_CURVE)
-
-struct p54_channel_entry {
-       u16 freq;
-       u16 data;
-       int index;
-       int max_power;
-       enum ieee80211_band band;
-};
-
-struct p54_channel_list {
-       struct p54_channel_entry *channels;
-       size_t entries;
-       size_t max_entries;
-       size_t band_channel_num[IEEE80211_NUM_BANDS];
-};
-
-static int p54_get_band_from_freq(u16 freq)
-{
-       /* FIXME: sync these values with the 802.11 spec */
-
-       if ((freq >= 2412) && (freq <= 2484))
-               return IEEE80211_BAND_2GHZ;
-
-       if ((freq >= 4920) && (freq <= 5825))
-               return IEEE80211_BAND_5GHZ;
-
-       return -1;
-}
-
-static int same_band(u16 freq, u16 freq2)
-{
-       return p54_get_band_from_freq(freq) == p54_get_band_from_freq(freq2);
-}
-
-static int p54_compare_channels(const void *_a,
-                               const void *_b)
-{
-       const struct p54_channel_entry *a = _a;
-       const struct p54_channel_entry *b = _b;
-
-       return a->freq - b->freq;
-}
-
-static int p54_compare_rssichan(const void *_a,
-                               const void *_b)
-{
-       const struct p54_rssi_db_entry *a = _a;
-       const struct p54_rssi_db_entry *b = _b;
-
-       return a->freq - b->freq;
-}
-
-static int p54_fill_band_bitrates(struct ieee80211_hw *dev,
-                                 struct ieee80211_supported_band *band_entry,
-                                 enum ieee80211_band band)
-{
-       /* TODO: generate rate array dynamically */
-
-       switch (band) {
-       case IEEE80211_BAND_2GHZ:
-               band_entry->bitrates = p54_bgrates;
-               band_entry->n_bitrates = ARRAY_SIZE(p54_bgrates);
-               break;
-       case IEEE80211_BAND_5GHZ:
-               band_entry->bitrates = p54_arates;
-               band_entry->n_bitrates = ARRAY_SIZE(p54_arates);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int p54_generate_band(struct ieee80211_hw *dev,
-                            struct p54_channel_list *list,
-                            unsigned int *chan_num,
-                            enum ieee80211_band band)
-{
-       struct p54_common *priv = dev->priv;
-       struct ieee80211_supported_band *tmp, *old;
-       unsigned int i, j;
-       int ret = -ENOMEM;
-
-       if ((!list->entries) || (!list->band_channel_num[band]))
-               return -EINVAL;
-
-       tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
-       if (!tmp)
-               goto err_out;
-
-       tmp->channels = kzalloc(sizeof(struct ieee80211_channel) *
-                               list->band_channel_num[band], GFP_KERNEL);
-       if (!tmp->channels)
-               goto err_out;
-
-       ret = p54_fill_band_bitrates(dev, tmp, band);
-       if (ret)
-               goto err_out;
-
-       for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
-                          (i < list->entries); i++) {
-               struct p54_channel_entry *chan = &list->channels[i];
-               struct ieee80211_channel *dest = &tmp->channels[j];
-
-               if (chan->band != band)
-                       continue;
-
-               if (chan->data != CHAN_HAS_ALL) {
-                       wiphy_err(dev->wiphy, "%s%s%s is/are missing for "
-                                 "channel:%d [%d MHz].\n",
-                                 (chan->data & CHAN_HAS_CAL ? "" :
-                                  " [iqauto calibration data]"),
-                                 (chan->data & CHAN_HAS_LIMIT ? "" :
-                                  " [output power limits]"),
-                                 (chan->data & CHAN_HAS_CURVE ? "" :
-                                  " [curve data]"),
-                                 chan->index, chan->freq);
-                       continue;
-               }
-
-               dest->band = chan->band;
-               dest->center_freq = chan->freq;
-               dest->max_power = chan->max_power;
-               priv->survey[*chan_num].channel = &tmp->channels[j];
-               priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
-                       SURVEY_INFO_TIME |
-                       SURVEY_INFO_TIME_BUSY |
-                       SURVEY_INFO_TIME_TX;
-               dest->hw_value = (*chan_num);
-               j++;
-               (*chan_num)++;
-       }
-
-       if (j == 0) {
-               wiphy_err(dev->wiphy, "Disabling totally damaged %d GHz band\n",
-                         (band == IEEE80211_BAND_2GHZ) ? 2 : 5);
-
-               ret = -ENODATA;
-               goto err_out;
-       }
-
-       tmp->n_channels = j;
-       old = priv->band_table[band];
-       priv->band_table[band] = tmp;
-       if (old) {
-               kfree(old->channels);
-               kfree(old);
-       }
-
-       return 0;
-
-err_out:
-       if (tmp) {
-               kfree(tmp->channels);
-               kfree(tmp);
-       }
-
-       return ret;
-}
-
-static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
-                                                         u16 freq, u16 data)
-{
-       int i;
-       struct p54_channel_entry *entry = NULL;
-
-       /*
-        * usually all lists in the eeprom are mostly sorted.
-        * so it's very likely that the entry we are looking for
-        * is right at the end of the list
-        */
-       for (i = list->entries; i >= 0; i--) {
-               if (freq == list->channels[i].freq) {
-                       entry = &list->channels[i];
-                       break;
-               }
-       }
-
-       if ((i < 0) && (list->entries < list->max_entries)) {
-               /* entry does not exist yet. Initialize a new one. */
-               int band = p54_get_band_from_freq(freq);
-
-               /*
-                * filter out frequencies which don't belong into
-                * any supported band.
-                */
-               if (band >= 0) {
-                       i = list->entries++;
-                       list->band_channel_num[band]++;
-
-                       entry = &list->channels[i];
-                       entry->freq = freq;
-                       entry->band = band;
-                       entry->index = ieee80211_frequency_to_channel(freq);
-                       entry->max_power = 0;
-                       entry->data = 0;
-               }
-       }
-
-       if (entry)
-               entry->data |= data;
-
-       return entry;
-}
-
-static int p54_get_maxpower(struct p54_common *priv, void *data)
-{
-       switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) {
-       case PDR_SYNTH_FRONTEND_LONGBOW: {
-               struct pda_channel_output_limit_longbow *pda = data;
-               int j;
-               u16 rawpower = 0;
-               pda = data;
-               for (j = 0; j < ARRAY_SIZE(pda->point); j++) {
-                       struct pda_channel_output_limit_point_longbow *point =
-                               &pda->point[j];
-                       rawpower = max_t(u16,
-                               rawpower, le16_to_cpu(point->val_qpsk));
-                       rawpower = max_t(u16,
-                               rawpower, le16_to_cpu(point->val_bpsk));
-                       rawpower = max_t(u16,
-                               rawpower, le16_to_cpu(point->val_16qam));
-                       rawpower = max_t(u16,
-                               rawpower, le16_to_cpu(point->val_64qam));
-               }
-               /* longbow seems to use 1/16 dBm units */
-               return rawpower / 16;
-               }
-
-       case PDR_SYNTH_FRONTEND_DUETTE3:
-       case PDR_SYNTH_FRONTEND_DUETTE2:
-       case PDR_SYNTH_FRONTEND_FRISBEE:
-       case PDR_SYNTH_FRONTEND_XBOW: {
-               struct pda_channel_output_limit *pda = data;
-               u8 rawpower = 0;
-               rawpower = max(rawpower, pda->val_qpsk);
-               rawpower = max(rawpower, pda->val_bpsk);
-               rawpower = max(rawpower, pda->val_16qam);
-               rawpower = max(rawpower, pda->val_64qam);
-               /* raw values are in 1/4 dBm units */
-               return rawpower / 4;
-               }
-
-       default:
-               return 20;
-       }
-}
-
-static int p54_generate_channel_lists(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_channel_list *list;
-       unsigned int i, j, k, max_channel_num;
-       int ret = 0;
-       u16 freq;
-
-       if ((priv->iq_autocal_len != priv->curve_data->entries) ||
-           (priv->iq_autocal_len != priv->output_limit->entries))
-               wiphy_err(dev->wiphy,
-                         "Unsupported or damaged EEPROM detected. "
-                         "You may not be able to use all channels.\n");
-
-       max_channel_num = max_t(unsigned int, priv->output_limit->entries,
-                               priv->iq_autocal_len);
-       max_channel_num = max_t(unsigned int, max_channel_num,
-                               priv->curve_data->entries);
-
-       list = kzalloc(sizeof(*list), GFP_KERNEL);
-       if (!list) {
-               ret = -ENOMEM;
-               goto free;
-       }
-       priv->chan_num = max_channel_num;
-       priv->survey = kzalloc(sizeof(struct survey_info) * max_channel_num,
-                              GFP_KERNEL);
-       if (!priv->survey) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       list->max_entries = max_channel_num;
-       list->channels = kzalloc(sizeof(struct p54_channel_entry) *
-                                max_channel_num, GFP_KERNEL);
-       if (!list->channels) {
-               ret = -ENOMEM;
-               goto free;
-       }
-
-       for (i = 0; i < max_channel_num; i++) {
-               if (i < priv->iq_autocal_len) {
-                       freq = le16_to_cpu(priv->iq_autocal[i].freq);
-                       p54_update_channel_param(list, freq, CHAN_HAS_CAL);
-               }
-
-               if (i < priv->output_limit->entries) {
-                       struct p54_channel_entry *tmp;
-
-                       void *data = (void *) ((unsigned long) i *
-                               priv->output_limit->entry_size +
-                               priv->output_limit->offset +
-                               priv->output_limit->data);
-
-                       freq = le16_to_cpup((__le16 *) data);
-                       tmp = p54_update_channel_param(list, freq,
-                                                      CHAN_HAS_LIMIT);
-                       if (tmp) {
-                               tmp->max_power = p54_get_maxpower(priv, data);
-                       }
-               }
-
-               if (i < priv->curve_data->entries) {
-                       freq = le16_to_cpup((__le16 *) (i *
-                                           priv->curve_data->entry_size +
-                                           priv->curve_data->offset +
-                                           priv->curve_data->data));
-
-                       p54_update_channel_param(list, freq, CHAN_HAS_CURVE);
-               }
-       }
-
-       /* sort the channel list by frequency */
-       sort(list->channels, list->entries, sizeof(struct p54_channel_entry),
-            p54_compare_channels, NULL);
-
-       k = 0;
-       for (i = 0, j = 0; i < IEEE80211_NUM_BANDS; i++) {
-               if (p54_generate_band(dev, list, &k, i) == 0)
-                       j++;
-       }
-       if (j == 0) {
-               /* no useable band available. */
-               ret = -EINVAL;
-       }
-
-free:
-       if (list) {
-               kfree(list->channels);
-               kfree(list);
-       }
-       if (ret) {
-               kfree(priv->survey);
-               priv->survey = NULL;
-       }
-
-       return ret;
-}
-
-static int p54_convert_rev0(struct ieee80211_hw *dev,
-                           struct pda_pa_curve_data *curve_data)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_pa_curve_data_sample *dst;
-       struct pda_pa_curve_data_sample_rev0 *src;
-       size_t cd_len = sizeof(*curve_data) +
-               (curve_data->points_per_channel*sizeof(*dst) + 2) *
-                curve_data->channels;
-       unsigned int i, j;
-       void *source, *target;
-
-       priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len,
-                                  GFP_KERNEL);
-       if (!priv->curve_data)
-               return -ENOMEM;
-
-       priv->curve_data->entries = curve_data->channels;
-       priv->curve_data->entry_size = sizeof(__le16) +
-               sizeof(*dst) * curve_data->points_per_channel;
-       priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
-       priv->curve_data->len = cd_len;
-       memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
-       source = curve_data->data;
-       target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
-       for (i = 0; i < curve_data->channels; i++) {
-               __le16 *freq = source;
-               source += sizeof(__le16);
-               *((__le16 *)target) = *freq;
-               target += sizeof(__le16);
-               for (j = 0; j < curve_data->points_per_channel; j++) {
-                       dst = target;
-                       src = source;
-
-                       dst->rf_power = src->rf_power;
-                       dst->pa_detector = src->pa_detector;
-                       dst->data_64qam = src->pcv;
-                       /* "invent" the points for the other modulations */
-#define SUB(x, y) (u8)(((x) - (y)) > (x) ? 0 : (x) - (y))
-                       dst->data_16qam = SUB(src->pcv, 12);
-                       dst->data_qpsk = SUB(dst->data_16qam, 12);
-                       dst->data_bpsk = SUB(dst->data_qpsk, 12);
-                       dst->data_barker = SUB(dst->data_bpsk, 14);
-#undef SUB
-                       target += sizeof(*dst);
-                       source += sizeof(*src);
-               }
-       }
-
-       return 0;
-}
-
-static int p54_convert_rev1(struct ieee80211_hw *dev,
-                           struct pda_pa_curve_data *curve_data)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_pa_curve_data_sample *dst;
-       struct pda_pa_curve_data_sample_rev1 *src;
-       size_t cd_len = sizeof(*curve_data) +
-               (curve_data->points_per_channel*sizeof(*dst) + 2) *
-                curve_data->channels;
-       unsigned int i, j;
-       void *source, *target;
-
-       priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data),
-                                  GFP_KERNEL);
-       if (!priv->curve_data)
-               return -ENOMEM;
-
-       priv->curve_data->entries = curve_data->channels;
-       priv->curve_data->entry_size = sizeof(__le16) +
-               sizeof(*dst) * curve_data->points_per_channel;
-       priv->curve_data->offset = offsetof(struct pda_pa_curve_data, data);
-       priv->curve_data->len = cd_len;
-       memcpy(priv->curve_data->data, curve_data, sizeof(*curve_data));
-       source = curve_data->data;
-       target = ((struct pda_pa_curve_data *) priv->curve_data->data)->data;
-       for (i = 0; i < curve_data->channels; i++) {
-               __le16 *freq = source;
-               source += sizeof(__le16);
-               *((__le16 *)target) = *freq;
-               target += sizeof(__le16);
-               for (j = 0; j < curve_data->points_per_channel; j++) {
-                       memcpy(target, source, sizeof(*src));
-
-                       target += sizeof(*dst);
-                       source += sizeof(*src);
-               }
-               source++;
-       }
-
-       return 0;
-}
-
-static const char *p54_rf_chips[] = { "INVALID-0", "Duette3", "Duette2",
-       "Frisbee", "Xbow", "Longbow", "INVALID-6", "INVALID-7" };
-
-static int p54_parse_rssical(struct ieee80211_hw *dev,
-                            u8 *data, int len, u16 type)
-{
-       struct p54_common *priv = dev->priv;
-       struct p54_rssi_db_entry *entry;
-       size_t db_len, entries;
-       int offset = 0, i;
-
-       if (type != PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
-               entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2;
-               if (len != sizeof(struct pda_rssi_cal_entry) * entries) {
-                       wiphy_err(dev->wiphy, "rssical size mismatch.\n");
-                       goto err_data;
-               }
-       } else {
-               /*
-                * Some devices (Dell 1450 USB, Xbow 5GHz card, etc...)
-                * have an empty two byte header.
-                */
-               if (*((__le16 *)&data[offset]) == cpu_to_le16(0))
-                       offset += 2;
-
-               entries = (len - offset) /
-                       sizeof(struct pda_rssi_cal_ext_entry);
-
-               if (len < offset ||
-                   (len - offset) % sizeof(struct pda_rssi_cal_ext_entry) ||
-                   entries == 0) {
-                       wiphy_err(dev->wiphy, "invalid rssi database.\n");
-                       goto err_data;
-               }
-       }
-
-       db_len = sizeof(*entry) * entries;
-       priv->rssi_db = kzalloc(db_len + sizeof(*priv->rssi_db), GFP_KERNEL);
-       if (!priv->rssi_db)
-               return -ENOMEM;
-
-       priv->rssi_db->offset = 0;
-       priv->rssi_db->entries = entries;
-       priv->rssi_db->entry_size = sizeof(*entry);
-       priv->rssi_db->len = db_len;
-
-       entry = (void *)((unsigned long)priv->rssi_db->data + priv->rssi_db->offset);
-       if (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) {
-               struct pda_rssi_cal_ext_entry *cal = (void *) &data[offset];
-
-               for (i = 0; i < entries; i++) {
-                       entry[i].freq = le16_to_cpu(cal[i].freq);
-                       entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
-                       entry[i].add = (s16) le16_to_cpu(cal[i].add);
-               }
-       } else {
-               struct pda_rssi_cal_entry *cal = (void *) &data[offset];
-
-               for (i = 0; i < entries; i++) {
-                       u16 freq = 0;
-                       switch (i) {
-                       case IEEE80211_BAND_2GHZ:
-                               freq = 2437;
-                               break;
-                       case IEEE80211_BAND_5GHZ:
-                               freq = 5240;
-                               break;
-                       }
-
-                       entry[i].freq = freq;
-                       entry[i].mul = (s16) le16_to_cpu(cal[i].mul);
-                       entry[i].add = (s16) le16_to_cpu(cal[i].add);
-               }
-       }
-
-       /* sort the list by channel frequency */
-       sort(entry, entries, sizeof(*entry), p54_compare_rssichan, NULL);
-       return 0;
-
-err_data:
-       wiphy_err(dev->wiphy,
-                 "rssi calibration data packing type:(%x) len:%d.\n",
-                 type, len);
-
-       print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, data, len);
-
-       wiphy_err(dev->wiphy, "please report this issue.\n");
-       return -EINVAL;
-}
-
-struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *priv, const u16 freq)
-{
-       struct p54_rssi_db_entry *entry;
-       int i, found = -1;
-
-       if (!priv->rssi_db)
-               return &p54_rssi_default;
-
-       entry = (void *)(priv->rssi_db->data + priv->rssi_db->offset);
-       for (i = 0; i < priv->rssi_db->entries; i++) {
-               if (!same_band(freq, entry[i].freq))
-                       continue;
-
-               if (found == -1) {
-                       found = i;
-                       continue;
-               }
-
-               /* nearest match */
-               if (abs(freq - entry[i].freq) <
-                   abs(freq - entry[found].freq)) {
-                       found = i;
-                       continue;
-               } else {
-                       break;
-               }
-       }
-
-       return found < 0 ? &p54_rssi_default : &entry[found];
-}
-
-static void p54_parse_default_country(struct ieee80211_hw *dev,
-                                     void *data, int len)
-{
-       struct pda_country *country;
-
-       if (len != sizeof(*country)) {
-               wiphy_err(dev->wiphy,
-                         "found possible invalid default country eeprom entry. (entry size: %d)\n",
-                         len);
-
-               print_hex_dump_bytes("country:", DUMP_PREFIX_NONE,
-                                    data, len);
-
-               wiphy_err(dev->wiphy, "please report this issue.\n");
-               return;
-       }
-
-       country = (struct pda_country *) data;
-       if (country->flags == PDR_COUNTRY_CERT_CODE_PSEUDO)
-               regulatory_hint(dev->wiphy, country->alpha2);
-       else {
-               /* TODO:
-                * write a shared/common function that converts
-                * "Regulatory domain codes" (802.11-2007 14.8.2.2)
-                * into ISO/IEC 3166-1 alpha2 for regulatory_hint.
-                */
-       }
-}
-
-static int p54_convert_output_limits(struct ieee80211_hw *dev,
-                                    u8 *data, size_t len)
-{
-       struct p54_common *priv = dev->priv;
-
-       if (len < 2)
-               return -EINVAL;
-
-       if (data[0] != 0) {
-               wiphy_err(dev->wiphy, "unknown output power db revision:%x\n",
-                         data[0]);
-               return -EINVAL;
-       }
-
-       if (2 + data[1] * sizeof(struct pda_channel_output_limit) > len)
-               return -EINVAL;
-
-       priv->output_limit = kmalloc(data[1] *
-               sizeof(struct pda_channel_output_limit) +
-               sizeof(*priv->output_limit), GFP_KERNEL);
-
-       if (!priv->output_limit)
-               return -ENOMEM;
-
-       priv->output_limit->offset = 0;
-       priv->output_limit->entries = data[1];
-       priv->output_limit->entry_size =
-               sizeof(struct pda_channel_output_limit);
-       priv->output_limit->len = priv->output_limit->entry_size *
-                                 priv->output_limit->entries +
-                                 priv->output_limit->offset;
-
-       memcpy(priv->output_limit->data, &data[2],
-              data[1] * sizeof(struct pda_channel_output_limit));
-
-       return 0;
-}
-
-static struct p54_cal_database *p54_convert_db(struct pda_custom_wrapper *src,
-                                              size_t total_len)
-{
-       struct p54_cal_database *dst;
-       size_t payload_len, entries, entry_size, offset;
-
-       payload_len = le16_to_cpu(src->len);
-       entries = le16_to_cpu(src->entries);
-       entry_size = le16_to_cpu(src->entry_size);
-       offset = le16_to_cpu(src->offset);
-       if (((entries * entry_size + offset) != payload_len) ||
-            (payload_len + sizeof(*src) != total_len))
-               return NULL;
-
-       dst = kmalloc(sizeof(*dst) + payload_len, GFP_KERNEL);
-       if (!dst)
-               return NULL;
-
-       dst->entries = entries;
-       dst->entry_size = entry_size;
-       dst->offset = offset;
-       dst->len = payload_len;
-
-       memcpy(dst->data, src->data, payload_len);
-       return dst;
-}
-
-int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
-{
-       struct p54_common *priv = dev->priv;
-       struct eeprom_pda_wrap *wrap;
-       struct pda_entry *entry;
-       unsigned int data_len, entry_len;
-       void *tmp;
-       int err;
-       u8 *end = (u8 *)eeprom + len;
-       u16 synth = 0;
-       u16 crc16 = ~0;
-
-       wrap = (struct eeprom_pda_wrap *) eeprom;
-       entry = (void *)wrap->data + le16_to_cpu(wrap->len);
-
-       /* verify that at least the entry length/code fits */
-       while ((u8 *)entry <= end - sizeof(*entry)) {
-               entry_len = le16_to_cpu(entry->len);
-               data_len = ((entry_len - 1) << 1);
-
-               /* abort if entry exceeds whole structure */
-               if ((u8 *)entry + sizeof(*entry) + data_len > end)
-                       break;
-
-               switch (le16_to_cpu(entry->code)) {
-               case PDR_MAC_ADDRESS:
-                       if (data_len != ETH_ALEN)
-                               break;
-                       SET_IEEE80211_PERM_ADDR(dev, entry->data);
-                       break;
-               case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS:
-                       if (priv->output_limit)
-                               break;
-                       err = p54_convert_output_limits(dev, entry->data,
-                                                       data_len);
-                       if (err)
-                               goto err;
-                       break;
-               case PDR_PRISM_PA_CAL_CURVE_DATA: {
-                       struct pda_pa_curve_data *curve_data =
-                               (struct pda_pa_curve_data *)entry->data;
-                       if (data_len < sizeof(*curve_data)) {
-                               err = -EINVAL;
-                               goto err;
-                       }
-
-                       switch (curve_data->cal_method_rev) {
-                       case 0:
-                               err = p54_convert_rev0(dev, curve_data);
-                               break;
-                       case 1:
-                               err = p54_convert_rev1(dev, curve_data);
-                               break;
-                       default:
-                               wiphy_err(dev->wiphy,
-                                         "unknown curve data revision %d\n",
-                                         curve_data->cal_method_rev);
-                               err = -ENODEV;
-                               break;
-                       }
-                       if (err)
-                               goto err;
-                       }
-                       break;
-               case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
-                       priv->iq_autocal = kmemdup(entry->data, data_len,
-                                                  GFP_KERNEL);
-                       if (!priv->iq_autocal) {
-                               err = -ENOMEM;
-                               goto err;
-                       }
-
-                       priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
-                       break;
-               case PDR_DEFAULT_COUNTRY:
-                       p54_parse_default_country(dev, entry->data, data_len);
-                       break;
-               case PDR_INTERFACE_LIST:
-                       tmp = entry->data;
-                       while ((u8 *)tmp < entry->data + data_len) {
-                               struct exp_if *exp_if = tmp;
-                               if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000))
-                                       synth = le16_to_cpu(exp_if->variant);
-                               tmp += sizeof(*exp_if);
-                       }
-                       break;
-               case PDR_HARDWARE_PLATFORM_COMPONENT_ID:
-                       if (data_len < 2)
-                               break;
-                       priv->version = *(u8 *)(entry->data + 1);
-                       break;
-               case PDR_RSSI_LINEAR_APPROXIMATION:
-               case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND:
-               case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED:
-                       err = p54_parse_rssical(dev, entry->data, data_len,
-                                               le16_to_cpu(entry->code));
-                       if (err)
-                               goto err;
-                       break;
-               case PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2: {
-                       struct pda_custom_wrapper *pda = (void *) entry->data;
-                       __le16 *src;
-                       u16 *dst;
-                       int i;
-
-                       if (priv->rssi_db || data_len < sizeof(*pda))
-                               break;
-
-                       priv->rssi_db = p54_convert_db(pda, data_len);
-                       if (!priv->rssi_db)
-                               break;
-
-                       src = (void *) priv->rssi_db->data;
-                       dst = (void *) priv->rssi_db->data;
-
-                       for (i = 0; i < priv->rssi_db->entries; i++)
-                               *(dst++) = (s16) le16_to_cpu(*(src++));
-
-                       }
-                       break;
-               case PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM: {
-                       struct pda_custom_wrapper *pda = (void *) entry->data;
-                       if (priv->output_limit || data_len < sizeof(*pda))
-                               break;
-                       priv->output_limit = p54_convert_db(pda, data_len);
-                       }
-                       break;
-               case PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM: {
-                       struct pda_custom_wrapper *pda = (void *) entry->data;
-                       if (priv->curve_data || data_len < sizeof(*pda))
-                               break;
-                       priv->curve_data = p54_convert_db(pda, data_len);
-                       }
-                       break;
-               case PDR_END:
-                       crc16 = ~crc_ccitt(crc16, (u8 *) entry, sizeof(*entry));
-                       if (crc16 != le16_to_cpup((__le16 *)entry->data)) {
-                               wiphy_err(dev->wiphy, "eeprom failed checksum "
-                                        "test!\n");
-                               err = -ENOMSG;
-                               goto err;
-                       } else {
-                               goto good_eeprom;
-                       }
-                       break;
-               default:
-                       break;
-               }
-
-               crc16 = crc_ccitt(crc16, (u8 *)entry, (entry_len + 1) * 2);
-               entry = (void *)entry + (entry_len + 1) * 2;
-       }
-
-       wiphy_err(dev->wiphy, "unexpected end of eeprom data.\n");
-       err = -ENODATA;
-       goto err;
-
-good_eeprom:
-       if (!synth || !priv->iq_autocal || !priv->output_limit ||
-           !priv->curve_data) {
-               wiphy_err(dev->wiphy,
-                         "not all required entries found in eeprom!\n");
-               err = -EINVAL;
-               goto err;
-       }
-
-       priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
-
-       err = p54_generate_channel_lists(dev);
-       if (err)
-               goto err;
-
-       if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
-               p54_init_xbow_synth(priv);
-       if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
-               dev->wiphy->bands[IEEE80211_BAND_2GHZ] =
-                       priv->band_table[IEEE80211_BAND_2GHZ];
-       if (!(synth & PDR_SYNTH_5_GHZ_DISABLED))
-               dev->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       priv->band_table[IEEE80211_BAND_5GHZ];
-       if ((synth & PDR_SYNTH_RX_DIV_MASK) == PDR_SYNTH_RX_DIV_SUPPORTED)
-               priv->rx_diversity_mask = 3;
-       if ((synth & PDR_SYNTH_TX_DIV_MASK) == PDR_SYNTH_TX_DIV_SUPPORTED)
-               priv->tx_diversity_mask = 3;
-
-       if (!is_valid_ether_addr(dev->wiphy->perm_addr)) {
-               u8 perm_addr[ETH_ALEN];
-
-               wiphy_warn(dev->wiphy,
-                          "Invalid hwaddr! Using randomly generated MAC addr\n");
-               eth_random_addr(perm_addr);
-               SET_IEEE80211_PERM_ADDR(dev, perm_addr);
-       }
-
-       priv->cur_rssi = &p54_rssi_default;
-
-       wiphy_info(dev->wiphy, "hwaddr %pM, MAC:isl38%02x RF:%s\n",
-                  dev->wiphy->perm_addr, priv->version,
-                  p54_rf_chips[priv->rxhw]);
-
-       return 0;
-
-err:
-       kfree(priv->iq_autocal);
-       kfree(priv->output_limit);
-       kfree(priv->curve_data);
-       kfree(priv->rssi_db);
-       kfree(priv->survey);
-       priv->iq_autocal = NULL;
-       priv->output_limit = NULL;
-       priv->curve_data = NULL;
-       priv->rssi_db = NULL;
-       priv->survey = NULL;
-
-       wiphy_err(dev->wiphy, "eeprom parse failed!\n");
-       return err;
-}
-EXPORT_SYMBOL_GPL(p54_parse_eeprom);
-
-int p54_read_eeprom(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize;
-       int ret = -ENOMEM;
-       void *eeprom;
-
-       maxblocksize = EEPROM_READBACK_LEN;
-       if (priv->fw_var >= 0x509)
-               maxblocksize -= 0xc;
-       else
-               maxblocksize -= 0x4;
-
-       eeprom = kzalloc(eeprom_size, GFP_KERNEL);
-       if (unlikely(!eeprom))
-               goto free;
-
-       while (eeprom_size) {
-               blocksize = min(eeprom_size, maxblocksize);
-               ret = p54_download_eeprom(priv, eeprom + offset,
-                                         offset, blocksize);
-               if (unlikely(ret))
-                       goto free;
-
-               offset += blocksize;
-               eeprom_size -= blocksize;
-       }
-
-       ret = p54_parse_eeprom(dev, eeprom, offset);
-free:
-       kfree(eeprom);
-       return ret;
-}
-EXPORT_SYMBOL_GPL(p54_read_eeprom);
diff --git a/drivers/net/wireless/p54/eeprom.h b/drivers/net/wireless/p54/eeprom.h
deleted file mode 100644 (file)
index 20ebe39..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * eeprom specific definitions for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
- *   Copyright (C) 2007 Conexant Systems, Inc.
- *
- * - islmvc driver
- *   Copyright (C) 2001 Intersil Americas Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef EEPROM_H
-#define EEPROM_H
-
-/* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */
-
-struct pda_entry {
-       __le16 len;     /* includes both code and data */
-       __le16 code;
-       u8 data[0];
-} __packed;
-
-struct eeprom_pda_wrap {
-       __le32 magic;
-       __le16 pad;
-       __le16 len;
-       __le32 arm_opcode;
-       u8 data[0];
-} __packed;
-
-struct p54_iq_autocal_entry {
-       __le16 iq_param[4];
-} __packed;
-
-struct pda_iq_autocal_entry {
-       __le16 freq;
-       struct p54_iq_autocal_entry params;
-} __packed;
-
-struct pda_channel_output_limit {
-       __le16 freq;
-       u8 val_bpsk;
-       u8 val_qpsk;
-       u8 val_16qam;
-       u8 val_64qam;
-       u8 rate_set_mask;
-       u8 rate_set_size;
-} __packed;
-
-struct pda_channel_output_limit_point_longbow {
-       __le16 val_bpsk;
-       __le16 val_qpsk;
-       __le16 val_16qam;
-       __le16 val_64qam;
-} __packed;
-
-struct pda_channel_output_limit_longbow {
-       __le16 freq;
-       struct pda_channel_output_limit_point_longbow point[3];
-} __packed;
-
-struct pda_pa_curve_data_sample_rev0 {
-       u8 rf_power;
-       u8 pa_detector;
-       u8 pcv;
-} __packed;
-
-struct pda_pa_curve_data_sample_rev1 {
-       u8 rf_power;
-       u8 pa_detector;
-       u8 data_barker;
-       u8 data_bpsk;
-       u8 data_qpsk;
-       u8 data_16qam;
-       u8 data_64qam;
-} __packed;
-
-struct pda_pa_curve_data {
-       u8 cal_method_rev;
-       u8 channels;
-       u8 points_per_channel;
-       u8 padding;
-       u8 data[0];
-} __packed;
-
-struct pda_rssi_cal_ext_entry {
-       __le16 freq;
-       __le16 mul;
-       __le16 add;
-} __packed;
-
-struct pda_rssi_cal_entry {
-       __le16 mul;
-       __le16 add;
-} __packed;
-
-struct pda_country {
-       u8 regdomain;
-       u8 alpha2[2];
-       u8 flags;
-} __packed;
-
-struct pda_antenna_gain {
-       struct {
-               u8 gain_5GHz;   /* 0.25 dBi units */
-               u8 gain_2GHz;   /* 0.25 dBi units */
-       } __packed antenna[0];
-} __packed;
-
-struct pda_custom_wrapper {
-       __le16 entries;
-       __le16 entry_size;
-       __le16 offset;
-       __le16 len;
-       u8 data[0];
-} __packed;
-
-/*
- * this defines the PDR codes used to build PDAs as defined in document
- * number 553155. The current implementation mirrors version 1.1 of the
- * document and lists only PDRs supported by the ARM platform.
- */
-
-/* common and choice range (0x0000 - 0x0fff) */
-#define PDR_END                                        0x0000
-#define PDR_MANUFACTURING_PART_NUMBER          0x0001
-#define PDR_PDA_VERSION                                0x0002
-#define PDR_NIC_SERIAL_NUMBER                  0x0003
-#define PDR_NIC_RAM_SIZE                       0x0005
-#define PDR_RFMODEM_SUP_RANGE                  0x0006
-#define PDR_PRISM_MAC_SUP_RANGE                        0x0007
-#define PDR_NIC_ID                             0x0008
-
-#define PDR_MAC_ADDRESS                                0x0101
-#define PDR_REGULATORY_DOMAIN_LIST             0x0103 /* obsolete */
-#define PDR_ALLOWED_CHAN_SET                   0x0104
-#define PDR_DEFAULT_CHAN                       0x0105
-#define PDR_TEMPERATURE_TYPE                   0x0107
-
-#define PDR_IFR_SETTING                                0x0200
-#define PDR_RFR_SETTING                                0x0201
-#define PDR_3861_BASELINE_REG_SETTINGS         0x0202
-#define PDR_3861_SHADOW_REG_SETTINGS           0x0203
-#define PDR_3861_IFRF_REG_SETTINGS             0x0204
-
-#define PDR_3861_CHAN_CALIB_SET_POINTS         0x0300
-#define PDR_3861_CHAN_CALIB_INTEGRATOR         0x0301
-
-#define PDR_3842_PRISM_II_NIC_CONFIG           0x0400
-#define PDR_PRISM_USB_ID                       0x0401
-#define PDR_PRISM_PCI_ID                       0x0402
-#define PDR_PRISM_PCI_IF_CONFIG                        0x0403
-#define PDR_PRISM_PCI_PM_CONFIG                        0x0404
-
-#define PDR_3861_MF_TEST_CHAN_SET_POINTS       0x0900
-#define PDR_3861_MF_TEST_CHAN_INTEGRATORS      0x0901
-
-/* ARM range (0x1000 - 0x1fff) */
-#define PDR_COUNTRY_INFORMATION                        0x1000 /* obsolete */
-#define PDR_INTERFACE_LIST                     0x1001
-#define PDR_HARDWARE_PLATFORM_COMPONENT_ID     0x1002
-#define PDR_OEM_NAME                           0x1003
-#define PDR_PRODUCT_NAME                       0x1004
-#define PDR_UTF8_OEM_NAME                      0x1005
-#define PDR_UTF8_PRODUCT_NAME                  0x1006
-#define PDR_COUNTRY_LIST                       0x1007
-#define PDR_DEFAULT_COUNTRY                    0x1008
-
-#define PDR_ANTENNA_GAIN                       0x1100
-
-#define PDR_PRISM_INDIGO_PA_CALIBRATION_DATA   0x1901
-#define PDR_RSSI_LINEAR_APPROXIMATION          0x1902
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS   0x1903
-#define PDR_PRISM_PA_CAL_CURVE_DATA            0x1904
-#define PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND        0x1905
-#define PDR_PRISM_ZIF_TX_IQ_CALIBRATION                0x1906
-#define PDR_REGULATORY_POWER_LIMITS            0x1907
-#define PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED 0x1908
-#define PDR_RADIATED_TRANSMISSION_CORRECTION   0x1909
-#define PDR_PRISM_TX_IQ_CALIBRATION            0x190a
-
-/* reserved range (0x2000 - 0x7fff) */
-
-/* customer range (0x8000 - 0xffff) */
-#define PDR_BASEBAND_REGISTERS                         0x8000
-#define PDR_PER_CHANNEL_BASEBAND_REGISTERS             0x8001
-
-/* used by our modificated eeprom image */
-#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOM           0xDEAD
-#define PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2         0xCAFF
-#define PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM    0xBEEF
-#define PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM             0xB05D
-
-/* Interface Definitions */
-#define PDR_INTERFACE_ROLE_SERVER      0x0000
-#define PDR_INTERFACE_ROLE_CLIENT      0x0001
-
-/* PDR definitions for default country & country list */
-#define PDR_COUNTRY_CERT_CODE          0x80
-#define PDR_COUNTRY_CERT_CODE_REAL     0x00
-#define PDR_COUNTRY_CERT_CODE_PSEUDO   0x80
-#define PDR_COUNTRY_CERT_BAND          0x40
-#define PDR_COUNTRY_CERT_BAND_2GHZ     0x00
-#define PDR_COUNTRY_CERT_BAND_5GHZ     0x40
-#define PDR_COUNTRY_CERT_IODOOR                0x30
-#define PDR_COUNTRY_CERT_IODOOR_BOTH   0x00
-#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20
-#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR        0x30
-#define PDR_COUNTRY_CERT_INDEX         0x0f
-
-/* Specific LMAC FW/HW variant definitions */
-#define PDR_SYNTH_FRONTEND_MASK                0x0007
-#define PDR_SYNTH_FRONTEND_DUETTE3     0x0001
-#define PDR_SYNTH_FRONTEND_DUETTE2     0x0002
-#define PDR_SYNTH_FRONTEND_FRISBEE     0x0003
-#define PDR_SYNTH_FRONTEND_XBOW                0x0004
-#define PDR_SYNTH_FRONTEND_LONGBOW     0x0005
-#define PDR_SYNTH_IQ_CAL_MASK          0x0018
-#define PDR_SYNTH_IQ_CAL_PA_DETECTOR   0x0000
-#define PDR_SYNTH_IQ_CAL_DISABLED      0x0008
-#define PDR_SYNTH_IQ_CAL_ZIF           0x0010
-#define PDR_SYNTH_FAA_SWITCH_MASK      0x0020
-#define PDR_SYNTH_FAA_SWITCH_ENABLED   0x0020
-#define PDR_SYNTH_24_GHZ_MASK          0x0040
-#define PDR_SYNTH_24_GHZ_DISABLED      0x0040
-#define PDR_SYNTH_5_GHZ_MASK           0x0080
-#define PDR_SYNTH_5_GHZ_DISABLED       0x0080
-#define PDR_SYNTH_RX_DIV_MASK          0x0100
-#define PDR_SYNTH_RX_DIV_SUPPORTED     0x0100
-#define PDR_SYNTH_TX_DIV_MASK          0x0200
-#define PDR_SYNTH_TX_DIV_SUPPORTED     0x0200
-#define PDR_SYNTH_ASM_MASK             0x0400
-#define PDR_SYNTH_ASM_XSWON            0x0400
-
-#endif /* EEPROM_H */
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
deleted file mode 100644 (file)
index 257a9ea..0000000
+++ /dev/null
@@ -1,764 +0,0 @@
-/*
- * Firmware I/O code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-#include <linux/export.h>
-
-#include <net/mac80211.h>
-
-#include "p54.h"
-#include "eeprom.h"
-#include "lmac.h"
-
-int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
-{
-       struct p54_common *priv = dev->priv;
-       struct exp_if *exp_if;
-       struct bootrec *bootrec;
-       u32 *data = (u32 *)fw->data;
-       u32 *end_data = (u32 *)fw->data + (fw->size >> 2);
-       u8 *fw_version = NULL;
-       size_t len;
-       int i;
-       int maxlen;
-
-       if (priv->rx_start)
-               return 0;
-
-       while (data < end_data && *data)
-               data++;
-
-       while (data < end_data && !*data)
-               data++;
-
-       bootrec = (struct bootrec *) data;
-
-       while (bootrec->data <= end_data && (bootrec->data +
-              (len = le32_to_cpu(bootrec->len))) <= end_data) {
-               u32 code = le32_to_cpu(bootrec->code);
-               switch (code) {
-               case BR_CODE_COMPONENT_ID:
-                       priv->fw_interface = be32_to_cpup((__be32 *)
-                                            bootrec->data);
-                       switch (priv->fw_interface) {
-                       case FW_LM86:
-                       case FW_LM20:
-                       case FW_LM87: {
-                               char *iftype = (char *)bootrec->data;
-                               wiphy_info(priv->hw->wiphy,
-                                          "p54 detected a LM%c%c firmware\n",
-                                          iftype[2], iftype[3]);
-                               break;
-                               }
-                       case FW_FMAC:
-                       default:
-                               wiphy_err(priv->hw->wiphy,
-                                         "unsupported firmware\n");
-                               return -ENODEV;
-                       }
-                       break;
-               case BR_CODE_COMPONENT_VERSION:
-                       /* 24 bytes should be enough for all firmwares */
-                       if (strnlen((unsigned char *) bootrec->data, 24) < 24)
-                               fw_version = (unsigned char *) bootrec->data;
-                       break;
-               case BR_CODE_DESCR: {
-                       struct bootrec_desc *desc =
-                               (struct bootrec_desc *)bootrec->data;
-                       priv->rx_start = le32_to_cpu(desc->rx_start);
-                       /* FIXME add sanity checking */
-                       priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
-                       priv->headroom = desc->headroom;
-                       priv->tailroom = desc->tailroom;
-                       priv->privacy_caps = desc->privacy_caps;
-                       priv->rx_keycache_size = desc->rx_keycache_size;
-                       if (le32_to_cpu(bootrec->len) == 11)
-                               priv->rx_mtu = le16_to_cpu(desc->rx_mtu);
-                       else
-                               priv->rx_mtu = (size_t)
-                                       0x620 - priv->tx_hdr_len;
-                       maxlen = priv->tx_hdr_len + /* USB devices */
-                                sizeof(struct p54_rx_data) +
-                                4 + /* rx alignment */
-                                IEEE80211_MAX_FRAG_THRESHOLD;
-                       if (priv->rx_mtu > maxlen && PAGE_SIZE == 4096) {
-                               printk(KERN_INFO "p54: rx_mtu reduced from %d "
-                                      "to %d\n", priv->rx_mtu, maxlen);
-                               priv->rx_mtu = maxlen;
-                       }
-                       break;
-                       }
-               case BR_CODE_EXPOSED_IF:
-                       exp_if = (struct exp_if *) bootrec->data;
-                       for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
-                               if (exp_if[i].if_id == cpu_to_le16(IF_ID_LMAC))
-                                       priv->fw_var = le16_to_cpu(exp_if[i].variant);
-                       break;
-               case BR_CODE_DEPENDENT_IF:
-                       break;
-               case BR_CODE_END_OF_BRA:
-               case LEGACY_BR_CODE_END_OF_BRA:
-                       end_data = NULL;
-                       break;
-               default:
-                       break;
-               }
-               bootrec = (struct bootrec *)&bootrec->data[len];
-       }
-
-       if (fw_version) {
-               wiphy_info(priv->hw->wiphy,
-                          "FW rev %s - Softmac protocol %x.%x\n",
-                          fw_version, priv->fw_var >> 8, priv->fw_var & 0xff);
-               snprintf(dev->wiphy->fw_version, sizeof(dev->wiphy->fw_version),
-                               "%s - %x.%x", fw_version,
-                               priv->fw_var >> 8, priv->fw_var & 0xff);
-       }
-
-       if (priv->fw_var < 0x500)
-               wiphy_info(priv->hw->wiphy,
-                          "you are using an obsolete firmware. "
-                          "visit http://wireless.kernel.org/en/users/Drivers/p54 "
-                          "and grab one for \"kernel >= 2.6.28\"!\n");
-
-       if (priv->fw_var >= 0x300) {
-               /* Firmware supports QoS, use it! */
-
-               if (priv->fw_var >= 0x500) {
-                       priv->tx_stats[P54_QUEUE_AC_VO].limit = 16;
-                       priv->tx_stats[P54_QUEUE_AC_VI].limit = 16;
-                       priv->tx_stats[P54_QUEUE_AC_BE].limit = 16;
-                       priv->tx_stats[P54_QUEUE_AC_BK].limit = 16;
-               } else {
-                       priv->tx_stats[P54_QUEUE_AC_VO].limit = 3;
-                       priv->tx_stats[P54_QUEUE_AC_VI].limit = 4;
-                       priv->tx_stats[P54_QUEUE_AC_BE].limit = 3;
-                       priv->tx_stats[P54_QUEUE_AC_BK].limit = 2;
-               }
-               priv->hw->queues = P54_QUEUE_AC_NUM;
-       }
-
-       wiphy_info(priv->hw->wiphy,
-                  "cryptographic accelerator WEP:%s, TKIP:%s, CCMP:%s\n",
-                  (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : "no",
-                  (priv->privacy_caps &
-                   (BR_DESC_PRIV_CAP_TKIP | BR_DESC_PRIV_CAP_MICHAEL))
-                  ? "YES" : "no",
-                  (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)
-                  ? "YES" : "no");
-
-       if (priv->rx_keycache_size) {
-               /*
-                * NOTE:
-                *
-                * The firmware provides at most 255 (0 - 254) slots
-                * for keys which are then used to offload decryption.
-                * As a result the 255 entry (aka 0xff) can be used
-                * safely by the driver to mark keys that didn't fit
-                * into the full cache. This trick saves us from
-                * keeping a extra list for uploaded keys.
-                */
-
-               priv->used_rxkeys = kzalloc(BITS_TO_LONGS(
-                       priv->rx_keycache_size), GFP_KERNEL);
-
-               if (!priv->used_rxkeys)
-                       return -ENOMEM;
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(p54_parse_firmware);
-
-static struct sk_buff *p54_alloc_skb(struct p54_common *priv, u16 hdr_flags,
-                                    u16 payload_len, u16 type, gfp_t memflags)
-{
-       struct p54_hdr *hdr;
-       struct sk_buff *skb;
-       size_t frame_len = sizeof(*hdr) + payload_len;
-
-       if (frame_len > P54_MAX_CTRL_FRAME_LEN)
-               return NULL;
-
-       if (unlikely(skb_queue_len(&priv->tx_pending) > 64))
-               return NULL;
-
-       skb = __dev_alloc_skb(priv->tx_hdr_len + frame_len, memflags);
-       if (!skb)
-               return NULL;
-       skb_reserve(skb, priv->tx_hdr_len);
-
-       hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr));
-       hdr->flags = cpu_to_le16(hdr_flags);
-       hdr->len = cpu_to_le16(payload_len);
-       hdr->type = cpu_to_le16(type);
-       hdr->tries = hdr->rts_tries = 0;
-       return skb;
-}
-
-int p54_download_eeprom(struct p54_common *priv, void *buf,
-                       u16 offset, u16 len)
-{
-       struct p54_eeprom_lm86 *eeprom_hdr;
-       struct sk_buff *skb;
-       size_t eeprom_hdr_size;
-       int ret = 0;
-       long timeout;
-
-       if (priv->fw_var >= 0x509)
-               eeprom_hdr_size = sizeof(*eeprom_hdr);
-       else
-               eeprom_hdr_size = 0x4;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL, eeprom_hdr_size +
-                           len, P54_CONTROL_TYPE_EEPROM_READBACK,
-                           GFP_KERNEL);
-       if (unlikely(!skb))
-               return -ENOMEM;
-
-       mutex_lock(&priv->eeprom_mutex);
-       priv->eeprom = buf;
-       eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb,
-               eeprom_hdr_size + len);
-
-       if (priv->fw_var < 0x509) {
-               eeprom_hdr->v1.offset = cpu_to_le16(offset);
-               eeprom_hdr->v1.len = cpu_to_le16(len);
-       } else {
-               eeprom_hdr->v2.offset = cpu_to_le32(offset);
-               eeprom_hdr->v2.len = cpu_to_le16(len);
-               eeprom_hdr->v2.magic2 = 0xf;
-               memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4);
-       }
-
-       p54_tx(priv, skb);
-
-       timeout = wait_for_completion_interruptible_timeout(
-                       &priv->eeprom_comp, HZ);
-       if (timeout <= 0) {
-               wiphy_err(priv->hw->wiphy,
-                       "device does not respond or signal received!\n");
-               ret = -EBUSY;
-       }
-       priv->eeprom = NULL;
-       mutex_unlock(&priv->eeprom_mutex);
-       return ret;
-}
-
-int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set)
-{
-       struct sk_buff *skb;
-       struct p54_tim *tim;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*tim),
-                           P54_CONTROL_TYPE_TIM, GFP_ATOMIC);
-       if (unlikely(!skb))
-               return -ENOMEM;
-
-       tim = (struct p54_tim *) skb_put(skb, sizeof(*tim));
-       tim->count = 1;
-       tim->entry[0] = cpu_to_le16(set ? (aid | 0x8000) : aid);
-       p54_tx(priv, skb);
-       return 0;
-}
-
-int p54_sta_unlock(struct p54_common *priv, u8 *addr)
-{
-       struct sk_buff *skb;
-       struct p54_sta_unlock *sta;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*sta),
-                           P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC);
-       if (unlikely(!skb))
-               return -ENOMEM;
-
-       sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta));
-       memcpy(sta->addr, addr, ETH_ALEN);
-       p54_tx(priv, skb);
-       return 0;
-}
-
-int p54_tx_cancel(struct p54_common *priv, __le32 req_id)
-{
-       struct sk_buff *skb;
-       struct p54_txcancel *cancel;
-       u32 _req_id = le32_to_cpu(req_id);
-
-       if (unlikely(_req_id < priv->rx_start || _req_id > priv->rx_end))
-               return -EINVAL;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*cancel),
-                           P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC);
-       if (unlikely(!skb))
-               return -ENOMEM;
-
-       cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel));
-       cancel->req_id = req_id;
-       p54_tx(priv, skb);
-       return 0;
-}
-
-int p54_setup_mac(struct p54_common *priv)
-{
-       struct sk_buff *skb;
-       struct p54_setup_mac *setup;
-       u16 mode;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup),
-                           P54_CONTROL_TYPE_SETUP, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup));
-       if (!(priv->hw->conf.flags & IEEE80211_CONF_IDLE)) {
-               switch (priv->mode) {
-               case NL80211_IFTYPE_STATION:
-                       mode = P54_FILTER_TYPE_STATION;
-                       break;
-               case NL80211_IFTYPE_AP:
-                       mode = P54_FILTER_TYPE_AP;
-                       break;
-               case NL80211_IFTYPE_ADHOC:
-               case NL80211_IFTYPE_MESH_POINT:
-                       mode = P54_FILTER_TYPE_IBSS;
-                       break;
-               case NL80211_IFTYPE_MONITOR:
-                       mode = P54_FILTER_TYPE_PROMISCUOUS;
-                       break;
-               default:
-                       mode = P54_FILTER_TYPE_HIBERNATE;
-                       break;
-               }
-
-               /*
-                * "TRANSPARENT and PROMISCUOUS are mutually exclusive"
-                * STSW45X0C LMAC API - page 12
-                */
-               if (priv->filter_flags & FIF_OTHER_BSS &&
-                   (mode != P54_FILTER_TYPE_PROMISCUOUS))
-                       mode |= P54_FILTER_TYPE_TRANSPARENT;
-       } else {
-               mode = P54_FILTER_TYPE_HIBERNATE;
-       }
-
-       setup->mac_mode = cpu_to_le16(mode);
-       memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
-       memcpy(setup->bssid, priv->bssid, ETH_ALEN);
-       setup->rx_antenna = 2 & priv->rx_diversity_mask; /* automatic */
-       setup->rx_align = 0;
-       if (priv->fw_var < 0x500) {
-               setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
-               memset(setup->v1.rts_rates, 0, 8);
-               setup->v1.rx_addr = cpu_to_le32(priv->rx_end);
-               setup->v1.max_rx = cpu_to_le16(priv->rx_mtu);
-               setup->v1.rxhw = cpu_to_le16(priv->rxhw);
-               setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer);
-               setup->v1.unalloc0 = cpu_to_le16(0);
-       } else {
-               setup->v2.rx_addr = cpu_to_le32(priv->rx_end);
-               setup->v2.max_rx = cpu_to_le16(priv->rx_mtu);
-               setup->v2.rxhw = cpu_to_le16(priv->rxhw);
-               setup->v2.timer = cpu_to_le16(priv->wakeup_timer);
-               setup->v2.truncate = cpu_to_le16(48896);
-               setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
-               setup->v2.sbss_offset = 0;
-               setup->v2.mcast_window = 0;
-               setup->v2.rx_rssi_threshold = 0;
-               setup->v2.rx_ed_threshold = 0;
-               setup->v2.ref_clock = cpu_to_le32(644245094);
-               setup->v2.lpf_bandwidth = cpu_to_le16(65535);
-               setup->v2.osc_start_delay = cpu_to_le16(65535);
-       }
-       p54_tx(priv, skb);
-       priv->phy_idle = mode == P54_FILTER_TYPE_HIBERNATE;
-       return 0;
-}
-
-int p54_scan(struct p54_common *priv, u16 mode, u16 dwell)
-{
-       struct sk_buff *skb;
-       struct p54_hdr *hdr;
-       struct p54_scan_head *head;
-       struct p54_iq_autocal_entry *iq_autocal;
-       union p54_scan_body_union *body;
-       struct p54_scan_tail_rate *rate;
-       struct pda_rssi_cal_entry *rssi;
-       struct p54_rssi_db_entry *rssi_data;
-       unsigned int i;
-       void *entry;
-       __le16 freq = cpu_to_le16(priv->hw->conf.chandef.chan->center_freq);
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*head) +
-                           2 + sizeof(*iq_autocal) + sizeof(*body) +
-                           sizeof(*rate) + 2 * sizeof(*rssi),
-                           P54_CONTROL_TYPE_SCAN, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       head = (struct p54_scan_head *) skb_put(skb, sizeof(*head));
-       memset(head->scan_params, 0, sizeof(head->scan_params));
-       head->mode = cpu_to_le16(mode);
-       head->dwell = cpu_to_le16(dwell);
-       head->freq = freq;
-
-       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
-               __le16 *pa_power_points = (__le16 *) skb_put(skb, 2);
-               *pa_power_points = cpu_to_le16(0x0c);
-       }
-
-       iq_autocal = (void *) skb_put(skb, sizeof(*iq_autocal));
-       for (i = 0; i < priv->iq_autocal_len; i++) {
-               if (priv->iq_autocal[i].freq != freq)
-                       continue;
-
-               memcpy(iq_autocal, &priv->iq_autocal[i].params,
-                      sizeof(struct p54_iq_autocal_entry));
-               break;
-       }
-       if (i == priv->iq_autocal_len)
-               goto err;
-
-       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW)
-               body = (void *) skb_put(skb, sizeof(body->longbow));
-       else
-               body = (void *) skb_put(skb, sizeof(body->normal));
-
-       for (i = 0; i < priv->output_limit->entries; i++) {
-               __le16 *entry_freq = (void *) (priv->output_limit->data +
-                                    priv->output_limit->entry_size * i);
-
-               if (*entry_freq != freq)
-                       continue;
-
-               if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
-                       memcpy(&body->longbow.power_limits,
-                              (void *) entry_freq + sizeof(__le16),
-                              priv->output_limit->entry_size);
-               } else {
-                       struct pda_channel_output_limit *limits =
-                              (void *) entry_freq;
-
-                       body->normal.val_barker = 0x38;
-                       body->normal.val_bpsk = body->normal.dup_bpsk =
-                               limits->val_bpsk;
-                       body->normal.val_qpsk = body->normal.dup_qpsk =
-                               limits->val_qpsk;
-                       body->normal.val_16qam = body->normal.dup_16qam =
-                               limits->val_16qam;
-                       body->normal.val_64qam = body->normal.dup_64qam =
-                               limits->val_64qam;
-               }
-               break;
-       }
-       if (i == priv->output_limit->entries)
-               goto err;
-
-       entry = (void *)(priv->curve_data->data + priv->curve_data->offset);
-       for (i = 0; i < priv->curve_data->entries; i++) {
-               if (*((__le16 *)entry) != freq) {
-                       entry += priv->curve_data->entry_size;
-                       continue;
-               }
-
-               if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
-                       memcpy(&body->longbow.curve_data,
-                               entry + sizeof(__le16),
-                               priv->curve_data->entry_size);
-               } else {
-                       struct p54_scan_body *chan = &body->normal;
-                       struct pda_pa_curve_data *curve_data =
-                               (void *) priv->curve_data->data;
-
-                       entry += sizeof(__le16);
-                       chan->pa_points_per_curve = 8;
-                       memset(chan->curve_data, 0, sizeof(*chan->curve_data));
-                       memcpy(chan->curve_data, entry,
-                              sizeof(struct p54_pa_curve_data_sample) *
-                              min((u8)8, curve_data->points_per_channel));
-               }
-               break;
-       }
-       if (i == priv->curve_data->entries)
-               goto err;
-
-       if ((priv->fw_var >= 0x500) && (priv->fw_var < 0x509)) {
-               rate = (void *) skb_put(skb, sizeof(*rate));
-               rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
-               for (i = 0; i < sizeof(rate->rts_rates); i++)
-                       rate->rts_rates[i] = i;
-       }
-
-       rssi = (struct pda_rssi_cal_entry *) skb_put(skb, sizeof(*rssi));
-       rssi_data = p54_rssi_find(priv, le16_to_cpu(freq));
-       rssi->mul = cpu_to_le16(rssi_data->mul);
-       rssi->add = cpu_to_le16(rssi_data->add);
-       if (priv->rxhw == PDR_SYNTH_FRONTEND_LONGBOW) {
-               /* Longbow frontend needs ever more */
-               rssi = (void *) skb_put(skb, sizeof(*rssi));
-               rssi->mul = cpu_to_le16(rssi_data->longbow_unkn);
-               rssi->add = cpu_to_le16(rssi_data->longbow_unk2);
-       }
-
-       if (priv->fw_var >= 0x509) {
-               rate = (void *) skb_put(skb, sizeof(*rate));
-               rate->basic_rate_mask = cpu_to_le32(priv->basic_rate_mask);
-               for (i = 0; i < sizeof(rate->rts_rates); i++)
-                       rate->rts_rates[i] = i;
-       }
-
-       hdr = (struct p54_hdr *) skb->data;
-       hdr->len = cpu_to_le16(skb->len - sizeof(*hdr));
-
-       p54_tx(priv, skb);
-       priv->cur_rssi = rssi_data;
-       return 0;
-
-err:
-       wiphy_err(priv->hw->wiphy, "frequency change to channel %d failed.\n",
-                 ieee80211_frequency_to_channel(
-                         priv->hw->conf.chandef.chan->center_freq));
-
-       dev_kfree_skb_any(skb);
-       return -EINVAL;
-}
-
-int p54_set_leds(struct p54_common *priv)
-{
-       struct sk_buff *skb;
-       struct p54_led *led;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led),
-                           P54_CONTROL_TYPE_LED, GFP_ATOMIC);
-       if (unlikely(!skb))
-               return -ENOMEM;
-
-       led = (struct p54_led *) skb_put(skb, sizeof(*led));
-       led->flags = cpu_to_le16(0x0003);
-       led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
-       led->delay[0] = cpu_to_le16(1);
-       led->delay[1] = cpu_to_le16(0);
-       p54_tx(priv, skb);
-       return 0;
-}
-
-int p54_set_edcf(struct p54_common *priv)
-{
-       struct sk_buff *skb;
-       struct p54_edcf *edcf;
-       u8 rtd;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf),
-                           P54_CONTROL_TYPE_DCFINIT, GFP_ATOMIC);
-       if (unlikely(!skb))
-               return -ENOMEM;
-
-       edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf));
-       if (priv->use_short_slot) {
-               edcf->slottime = 9;
-               edcf->sifs = 0x10;
-               edcf->eofpad = 0x00;
-       } else {
-               edcf->slottime = 20;
-               edcf->sifs = 0x0a;
-               edcf->eofpad = 0x06;
-       }
-       /*
-        * calculate the extra round trip delay according to the
-        * formula from 802.11-2007 17.3.8.6.
-        */
-       rtd = 3 * priv->coverage_class;
-       edcf->slottime += rtd;
-       edcf->round_trip_delay = cpu_to_le16(rtd);
-       /* (see prism54/isl_oid.h for further details) */
-       edcf->frameburst = cpu_to_le16(0);
-       edcf->flags = 0;
-       memset(edcf->mapping, 0, sizeof(edcf->mapping));
-       memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue));
-       p54_tx(priv, skb);
-       return 0;
-}
-
-int p54_set_ps(struct p54_common *priv)
-{
-       struct sk_buff *skb;
-       struct p54_psm *psm;
-       unsigned int i;
-       u16 mode;
-
-       if (priv->hw->conf.flags & IEEE80211_CONF_PS &&
-           !priv->powersave_override)
-               mode = P54_PSM | P54_PSM_BEACON_TIMEOUT | P54_PSM_DTIM |
-                      P54_PSM_CHECKSUM | P54_PSM_MCBC;
-       else
-               mode = P54_PSM_CAM;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*psm),
-                           P54_CONTROL_TYPE_PSM, GFP_ATOMIC);
-       if (!skb)
-               return -ENOMEM;
-
-       psm = (struct p54_psm *)skb_put(skb, sizeof(*psm));
-       psm->mode = cpu_to_le16(mode);
-       psm->aid = cpu_to_le16(priv->aid);
-       for (i = 0; i < ARRAY_SIZE(psm->intervals); i++) {
-               psm->intervals[i].interval =
-                       cpu_to_le16(priv->hw->conf.listen_interval);
-               psm->intervals[i].periods = cpu_to_le16(1);
-       }
-
-       psm->beacon_rssi_skip_max = 200;
-       psm->rssi_delta_threshold = 0;
-       psm->nr = 1;
-       psm->exclude[0] = WLAN_EID_TIM;
-
-       p54_tx(priv, skb);
-       priv->phy_ps = mode != P54_PSM_CAM;
-       return 0;
-}
-
-int p54_init_xbow_synth(struct p54_common *priv)
-{
-       struct sk_buff *skb;
-       struct p54_xbow_synth *xbow;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow),
-                           P54_CONTROL_TYPE_XBOW_SYNTH_CFG, GFP_KERNEL);
-       if (unlikely(!skb))
-               return -ENOMEM;
-
-       xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow));
-       xbow->magic1 = cpu_to_le16(0x1);
-       xbow->magic2 = cpu_to_le16(0x2);
-       xbow->freq = cpu_to_le16(5390);
-       memset(xbow->padding, 0, sizeof(xbow->padding));
-       p54_tx(priv, skb);
-       return 0;
-}
-
-int p54_upload_key(struct p54_common *priv, u8 algo, int slot, u8 idx, u8 len,
-                  u8 *addr, u8* key)
-{
-       struct sk_buff *skb;
-       struct p54_keycache *rxkey;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey),
-                           P54_CONTROL_TYPE_RX_KEYCACHE, GFP_KERNEL);
-       if (unlikely(!skb))
-               return -ENOMEM;
-
-       rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey));
-       rxkey->entry = slot;
-       rxkey->key_id = idx;
-       rxkey->key_type = algo;
-       if (addr)
-               memcpy(rxkey->mac, addr, ETH_ALEN);
-       else
-               eth_broadcast_addr(rxkey->mac);
-
-       switch (algo) {
-       case P54_CRYPTO_WEP:
-       case P54_CRYPTO_AESCCMP:
-               rxkey->key_len = min_t(u8, 16, len);
-               memcpy(rxkey->key, key, rxkey->key_len);
-               break;
-
-       case P54_CRYPTO_TKIPMICHAEL:
-               rxkey->key_len = 24;
-               memcpy(rxkey->key, key, 16);
-               memcpy(&(rxkey->key[16]), &(key
-                       [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8);
-               break;
-
-       case P54_CRYPTO_NONE:
-               rxkey->key_len = 0;
-               memset(rxkey->key, 0, sizeof(rxkey->key));
-               break;
-
-       default:
-               wiphy_err(priv->hw->wiphy,
-                         "invalid cryptographic algorithm: %d\n", algo);
-               dev_kfree_skb(skb);
-               return -EINVAL;
-       }
-
-       p54_tx(priv, skb);
-       return 0;
-}
-
-int p54_fetch_statistics(struct p54_common *priv)
-{
-       struct ieee80211_tx_info *txinfo;
-       struct p54_tx_info *p54info;
-       struct sk_buff *skb;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL,
-                           sizeof(struct p54_statistics),
-                           P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL);
-       if (!skb)
-               return -ENOMEM;
-
-       /*
-        * The statistic feedback causes some extra headaches here, if it
-        * is not to crash/corrupt the firmware data structures.
-        *
-        * Unlike all other Control Get OIDs we can not use helpers like
-        * skb_put to reserve the space for the data we're requesting.
-        * Instead the extra frame length -which will hold the results later-
-        * will only be told to the p54_assign_address, so that following
-        * frames won't be placed into the  allegedly empty area.
-        */
-       txinfo = IEEE80211_SKB_CB(skb);
-       p54info = (void *) txinfo->rate_driver_data;
-       p54info->extra_len = sizeof(struct p54_statistics);
-
-       p54_tx(priv, skb);
-       return 0;
-}
-
-int p54_set_groupfilter(struct p54_common *priv)
-{
-       struct p54_group_address_table *grp;
-       struct sk_buff *skb;
-       bool on = false;
-
-       skb = p54_alloc_skb(priv, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*grp),
-                           P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE, GFP_KERNEL);
-       if (!skb)
-               return -ENOMEM;
-
-       grp = (struct p54_group_address_table *)skb_put(skb, sizeof(*grp));
-
-       on = !(priv->filter_flags & FIF_ALLMULTI) &&
-            (priv->mc_maclist_num > 0 &&
-             priv->mc_maclist_num <= MC_FILTER_ADDRESS_NUM);
-
-       if (on) {
-               grp->filter_enable = cpu_to_le16(1);
-               grp->num_address = cpu_to_le16(priv->mc_maclist_num);
-               memcpy(grp->mac_list, priv->mc_maclist, sizeof(grp->mac_list));
-       } else {
-               grp->filter_enable = cpu_to_le16(0);
-               grp->num_address = cpu_to_le16(0);
-               memset(grp->mac_list, 0, sizeof(grp->mac_list));
-       }
-
-       p54_tx(priv, skb);
-       return 0;
-}
diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c
deleted file mode 100644 (file)
index 9a8fedd..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Common code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-
-#include <net/mac80211.h>
-#ifdef CONFIG_P54_LEDS
-#include <linux/leds.h>
-#endif /* CONFIG_P54_LEDS */
-
-#include "p54.h"
-#include "lmac.h"
-
-static void p54_update_leds(struct work_struct *work)
-{
-       struct p54_common *priv = container_of(work, struct p54_common,
-                                              led_work.work);
-       int err, i, tmp, blink_delay = 400;
-       bool rerun = false;
-
-       /* Don't toggle the LED, when the device is down. */
-       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
-               return ;
-
-       for (i = 0; i < ARRAY_SIZE(priv->leds); i++)
-               if (priv->leds[i].toggled) {
-                       priv->softled_state |= BIT(i);
-
-                       tmp = 70 + 200 / (priv->leds[i].toggled);
-                       if (tmp < blink_delay)
-                               blink_delay = tmp;
-
-                       if (priv->leds[i].led_dev.brightness == LED_OFF)
-                               rerun = true;
-
-                       priv->leds[i].toggled =
-                               !!priv->leds[i].led_dev.brightness;
-               } else
-                       priv->softled_state &= ~BIT(i);
-
-       err = p54_set_leds(priv);
-       if (err && net_ratelimit())
-               wiphy_err(priv->hw->wiphy,
-                         "failed to update LEDs (%d).\n", err);
-
-       if (rerun)
-               ieee80211_queue_delayed_work(priv->hw, &priv->led_work,
-                       msecs_to_jiffies(blink_delay));
-}
-
-static void p54_led_brightness_set(struct led_classdev *led_dev,
-                                  enum led_brightness brightness)
-{
-       struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
-                                              led_dev);
-       struct ieee80211_hw *dev = led->hw_dev;
-       struct p54_common *priv = dev->priv;
-
-       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
-               return ;
-
-       if ((brightness) && (led->registered)) {
-               led->toggled++;
-               ieee80211_queue_delayed_work(priv->hw, &priv->led_work, HZ/10);
-       }
-}
-
-static int p54_register_led(struct p54_common *priv,
-                           unsigned int led_index,
-                           char *name, const char *trigger)
-{
-       struct p54_led_dev *led = &priv->leds[led_index];
-       int err;
-
-       if (led->registered)
-               return -EEXIST;
-
-       snprintf(led->name, sizeof(led->name), "p54-%s::%s",
-                wiphy_name(priv->hw->wiphy), name);
-       led->hw_dev = priv->hw;
-       led->index = led_index;
-       led->led_dev.name = led->name;
-       led->led_dev.default_trigger = trigger;
-       led->led_dev.brightness_set = p54_led_brightness_set;
-
-       err = led_classdev_register(wiphy_dev(priv->hw->wiphy), &led->led_dev);
-       if (err)
-               wiphy_err(priv->hw->wiphy,
-                         "Failed to register %s LED.\n", name);
-       else
-               led->registered = 1;
-
-       return err;
-}
-
-int p54_init_leds(struct p54_common *priv)
-{
-       int err;
-
-       /*
-        * TODO:
-        * Figure out if the EEPROM contains some hints about the number
-        * of available/programmable LEDs of the device.
-        */
-
-       INIT_DELAYED_WORK(&priv->led_work, p54_update_leds);
-
-       err = p54_register_led(priv, 0, "assoc",
-                              ieee80211_get_assoc_led_name(priv->hw));
-       if (err)
-               return err;
-
-       err = p54_register_led(priv, 1, "tx",
-                              ieee80211_get_tx_led_name(priv->hw));
-       if (err)
-               return err;
-
-       err = p54_register_led(priv, 2, "rx",
-                              ieee80211_get_rx_led_name(priv->hw));
-       if (err)
-               return err;
-
-       err = p54_register_led(priv, 3, "radio",
-                              ieee80211_get_radio_led_name(priv->hw));
-       if (err)
-               return err;
-
-       err = p54_set_leds(priv);
-       return err;
-}
-
-void p54_unregister_leds(struct p54_common *priv)
-{
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(priv->leds); i++) {
-               if (priv->leds[i].registered) {
-                       priv->leds[i].registered = false;
-                       priv->leds[i].toggled = 0;
-                       led_classdev_unregister(&priv->leds[i].led_dev);
-               }
-       }
-
-       cancel_delayed_work_sync(&priv->led_work);
-}
diff --git a/drivers/net/wireless/p54/lmac.h b/drivers/net/wireless/p54/lmac.h
deleted file mode 100644 (file)
index de1d46b..0000000
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * LMAC Interface specific definitions for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007 - 2009, Christian Lamparter <chunkeey@web.de>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * - LMAC API interface header file for STLC4560 (lmac_longbow.h)
- *   Copyright (C) 2007 Conexant Systems, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef LMAC_H
-#define LMAC_H
-
-enum p54_control_frame_types {
-       P54_CONTROL_TYPE_SETUP = 0,
-       P54_CONTROL_TYPE_SCAN,
-       P54_CONTROL_TYPE_TRAP,
-       P54_CONTROL_TYPE_DCFINIT,
-       P54_CONTROL_TYPE_RX_KEYCACHE,
-       P54_CONTROL_TYPE_TIM,
-       P54_CONTROL_TYPE_PSM,
-       P54_CONTROL_TYPE_TXCANCEL,
-       P54_CONTROL_TYPE_TXDONE,
-       P54_CONTROL_TYPE_BURST,
-       P54_CONTROL_TYPE_STAT_READBACK,
-       P54_CONTROL_TYPE_BBP,
-       P54_CONTROL_TYPE_EEPROM_READBACK,
-       P54_CONTROL_TYPE_LED,
-       P54_CONTROL_TYPE_GPIO,
-       P54_CONTROL_TYPE_TIMER,
-       P54_CONTROL_TYPE_MODULATION,
-       P54_CONTROL_TYPE_SYNTH_CONFIG,
-       P54_CONTROL_TYPE_DETECTOR_VALUE,
-       P54_CONTROL_TYPE_XBOW_SYNTH_CFG,
-       P54_CONTROL_TYPE_CCE_QUIET,
-       P54_CONTROL_TYPE_PSM_STA_UNLOCK,
-       P54_CONTROL_TYPE_PCS,
-       P54_CONTROL_TYPE_BT_BALANCER = 28,
-       P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30,
-       P54_CONTROL_TYPE_ARPTABLE = 31,
-       P54_CONTROL_TYPE_BT_OPTIONS = 35,
-};
-
-#define P54_HDR_FLAG_CONTROL           BIT(15)
-#define P54_HDR_FLAG_CONTROL_OPSET     (BIT(15) + BIT(0))
-#define P54_HDR_FLAG_DATA_ALIGN                BIT(14)
-
-#define P54_HDR_FLAG_DATA_OUT_PROMISC          BIT(0)
-#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP                BIT(1)
-#define P54_HDR_FLAG_DATA_OUT_SEQNR            BIT(2)
-#define P54_HDR_FLAG_DATA_OUT_BIT3             BIT(3)
-#define P54_HDR_FLAG_DATA_OUT_BURST            BIT(4)
-#define P54_HDR_FLAG_DATA_OUT_NOCANCEL         BIT(5)
-#define P54_HDR_FLAG_DATA_OUT_CLEARTIM         BIT(6)
-#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE                BIT(7)
-#define P54_HDR_FLAG_DATA_OUT_COMPRESS         BIT(8)
-#define P54_HDR_FLAG_DATA_OUT_CONCAT           BIT(9)
-#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT       BIT(10)
-#define P54_HDR_FLAG_DATA_OUT_WAITEOSP         BIT(11)
-
-#define P54_HDR_FLAG_DATA_IN_FCS_GOOD          BIT(0)
-#define P54_HDR_FLAG_DATA_IN_MATCH_MAC         BIT(1)
-#define P54_HDR_FLAG_DATA_IN_MCBC              BIT(2)
-#define P54_HDR_FLAG_DATA_IN_BEACON            BIT(3)
-#define P54_HDR_FLAG_DATA_IN_MATCH_BSS         BIT(4)
-#define P54_HDR_FLAG_DATA_IN_BCAST_BSS         BIT(5)
-#define P54_HDR_FLAG_DATA_IN_DATA              BIT(6)
-#define P54_HDR_FLAG_DATA_IN_TRUNCATED         BIT(7)
-#define P54_HDR_FLAG_DATA_IN_BIT8              BIT(8)
-#define P54_HDR_FLAG_DATA_IN_TRANSPARENT       BIT(9)
-
-struct p54_hdr {
-       __le16 flags;
-       __le16 len;
-       __le32 req_id;
-       __le16 type;    /* enum p54_control_frame_types */
-       u8 rts_tries;
-       u8 tries;
-       u8 data[0];
-} __packed;
-
-#define GET_REQ_ID(skb)                                                        \
-       (((struct p54_hdr *) ((struct sk_buff *) skb)->data)->req_id)   \
-
-#define FREE_AFTER_TX(skb)                                             \
-       ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->         \
-       flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET))
-
-#define IS_DATA_FRAME(skb)                                             \
-       (!((((struct p54_hdr *) ((struct sk_buff *) skb)->data)->       \
-       flags) & cpu_to_le16(P54_HDR_FLAG_CONTROL)))
-
-#define GET_HW_QUEUE(skb)                                              \
-       (((struct p54_tx_data *)((struct p54_hdr *)                     \
-       skb->data)->data)->hw_queue)
-
-/*
- * shared interface ID definitions
- * The interface ID is a unique identification of a specific interface.
- * The following values are reserved: 0x0000, 0x0002, 0x0012, 0x0014, 0x0015
- */
-#define IF_ID_ISL36356A                        0x0001  /* ISL36356A <-> Firmware */
-#define IF_ID_MVC                      0x0003  /* MAC Virtual Coprocessor */
-#define IF_ID_DEBUG                    0x0008  /* PolDebug Interface */
-#define IF_ID_PRODUCT                  0x0009
-#define IF_ID_OEM                      0x000a
-#define IF_ID_PCI3877                  0x000b  /* 3877 <-> Host PCI */
-#define IF_ID_ISL37704C                        0x000c  /* ISL37704C <-> Fw */
-#define IF_ID_ISL39000                 0x000f  /* ISL39000 <-> Fw */
-#define IF_ID_ISL39300A                        0x0010  /* ISL39300A <-> Fw */
-#define IF_ID_ISL37700_UAP             0x0016  /* ISL37700 uAP Fw <-> Fw */
-#define IF_ID_ISL39000_UAP             0x0017  /* ISL39000 uAP Fw <-> Fw */
-#define IF_ID_LMAC                     0x001a  /* Interface exposed by LMAC */
-
-struct exp_if {
-       __le16 role;
-       __le16 if_id;
-       __le16 variant;
-       __le16 btm_compat;
-       __le16 top_compat;
-} __packed;
-
-struct dep_if {
-       __le16 role;
-       __le16 if_id;
-       __le16 variant;
-} __packed;
-
-/* driver <-> lmac definitions */
-struct p54_eeprom_lm86 {
-       union {
-               struct {
-                       __le16 offset;
-                       __le16 len;
-                       u8 data[0];
-               } __packed v1;
-               struct {
-                       __le32 offset;
-                       __le16 len;
-                       u8 magic2;
-                       u8 pad;
-                       u8 magic[4];
-                       u8 data[0];
-               } __packed v2;
-       }  __packed;
-} __packed;
-
-enum p54_rx_decrypt_status {
-       P54_DECRYPT_NONE = 0,
-       P54_DECRYPT_OK,
-       P54_DECRYPT_NOKEY,
-       P54_DECRYPT_NOMICHAEL,
-       P54_DECRYPT_NOCKIPMIC,
-       P54_DECRYPT_FAIL_WEP,
-       P54_DECRYPT_FAIL_TKIP,
-       P54_DECRYPT_FAIL_MICHAEL,
-       P54_DECRYPT_FAIL_CKIPKP,
-       P54_DECRYPT_FAIL_CKIPMIC,
-       P54_DECRYPT_FAIL_AESCCMP
-};
-
-struct p54_rx_data {
-       __le16 flags;
-       __le16 len;
-       __le16 freq;
-       u8 antenna;
-       u8 rate;
-       u8 rssi;
-       u8 quality;
-       u8 decrypt_status;
-       u8 rssi_raw;
-       __le32 tsf32;
-       __le32 unalloc0;
-       u8 align[0];
-} __packed;
-
-enum p54_trap_type {
-       P54_TRAP_SCAN = 0,
-       P54_TRAP_TIMER,
-       P54_TRAP_BEACON_TX,
-       P54_TRAP_FAA_RADIO_ON,
-       P54_TRAP_FAA_RADIO_OFF,
-       P54_TRAP_RADAR,
-       P54_TRAP_NO_BEACON,
-       P54_TRAP_TBTT,
-       P54_TRAP_SCO_ENTER,
-       P54_TRAP_SCO_EXIT
-};
-
-struct p54_trap {
-       __le16 event;
-       __le16 frequency;
-} __packed;
-
-enum p54_frame_sent_status {
-       P54_TX_OK = 0,
-       P54_TX_FAILED,
-       P54_TX_PSM,
-       P54_TX_PSM_CANCELLED = 4
-};
-
-struct p54_frame_sent {
-       u8 status;
-       u8 tries;
-       u8 ack_rssi;
-       u8 quality;
-       __le16 seq;
-       u8 antenna;
-       u8 padding;
-} __packed;
-
-enum p54_tx_data_crypt {
-       P54_CRYPTO_NONE = 0,
-       P54_CRYPTO_WEP,
-       P54_CRYPTO_TKIP,
-       P54_CRYPTO_TKIPMICHAEL,
-       P54_CRYPTO_CCX_WEPMIC,
-       P54_CRYPTO_CCX_KPMIC,
-       P54_CRYPTO_CCX_KP,
-       P54_CRYPTO_AESCCMP
-};
-
-enum p54_tx_data_queue {
-       P54_QUEUE_BEACON        = 0,
-       P54_QUEUE_FWSCAN        = 1,
-       P54_QUEUE_MGMT          = 2,
-       P54_QUEUE_CAB           = 3,
-       P54_QUEUE_DATA          = 4,
-
-       P54_QUEUE_AC_NUM        = 4,
-       P54_QUEUE_AC_VO         = 4,
-       P54_QUEUE_AC_VI         = 5,
-       P54_QUEUE_AC_BE         = 6,
-       P54_QUEUE_AC_BK         = 7,
-
-       /* keep last */
-       P54_QUEUE_NUM           = 8,
-};
-
-#define IS_QOS_QUEUE(n)        (n >= P54_QUEUE_DATA)
-
-struct p54_tx_data {
-       u8 rateset[8];
-       u8 rts_rate_idx;
-       u8 crypt_offset;
-       u8 key_type;
-       u8 key_len;
-       u8 key[16];
-       u8 hw_queue;
-       u8 backlog;
-       __le16 durations[4];
-       u8 tx_antenna;
-       union {
-               struct {
-                       u8 cts_rate;
-                       __le16 output_power;
-               } __packed longbow;
-               struct {
-                       u8 output_power;
-                       u8 cts_rate;
-                       u8 unalloc;
-               } __packed normal;
-       } __packed;
-       u8 unalloc2[2];
-       u8 align[0];
-} __packed;
-
-/* unit is ms */
-#define P54_TX_FRAME_LIFETIME 2000
-#define P54_TX_TIMEOUT 4000
-#define P54_STATISTICS_UPDATE 5000
-
-#define P54_FILTER_TYPE_NONE           0
-#define P54_FILTER_TYPE_STATION                BIT(0)
-#define P54_FILTER_TYPE_IBSS           BIT(1)
-#define P54_FILTER_TYPE_AP             BIT(2)
-#define P54_FILTER_TYPE_TRANSPARENT    BIT(3)
-#define P54_FILTER_TYPE_PROMISCUOUS    BIT(4)
-#define P54_FILTER_TYPE_HIBERNATE      BIT(5)
-#define P54_FILTER_TYPE_NOACK          BIT(6)
-#define P54_FILTER_TYPE_RX_DISABLED    BIT(7)
-
-struct p54_setup_mac {
-       __le16 mac_mode;
-       u8 mac_addr[ETH_ALEN];
-       u8 bssid[ETH_ALEN];
-       u8 rx_antenna;
-       u8 rx_align;
-       union {
-               struct {
-                       __le32 basic_rate_mask;
-                       u8 rts_rates[8];
-                       __le32 rx_addr;
-                       __le16 max_rx;
-                       __le16 rxhw;
-                       __le16 wakeup_timer;
-                       __le16 unalloc0;
-               } __packed v1;
-               struct {
-                       __le32 rx_addr;
-                       __le16 max_rx;
-                       __le16 rxhw;
-                       __le16 timer;
-                       __le16 truncate;
-                       __le32 basic_rate_mask;
-                       u8 sbss_offset;
-                       u8 mcast_window;
-                       u8 rx_rssi_threshold;
-                       u8 rx_ed_threshold;
-                       __le32 ref_clock;
-                       __le16 lpf_bandwidth;
-                       __le16 osc_start_delay;
-               } __packed v2;
-       } __packed;
-} __packed;
-
-#define P54_SETUP_V1_LEN 40
-#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac))
-
-#define P54_SCAN_EXIT  BIT(0)
-#define P54_SCAN_TRAP  BIT(1)
-#define P54_SCAN_ACTIVE BIT(2)
-#define P54_SCAN_FILTER BIT(3)
-
-struct p54_scan_head {
-       __le16 mode;
-       __le16 dwell;
-       u8 scan_params[20];
-       __le16 freq;
-} __packed;
-
-struct p54_pa_curve_data_sample {
-       u8 rf_power;
-       u8 pa_detector;
-       u8 data_barker;
-       u8 data_bpsk;
-       u8 data_qpsk;
-       u8 data_16qam;
-       u8 data_64qam;
-       u8 padding;
-} __packed;
-
-struct p54_scan_body {
-       u8 pa_points_per_curve;
-       u8 val_barker;
-       u8 val_bpsk;
-       u8 val_qpsk;
-       u8 val_16qam;
-       u8 val_64qam;
-       struct p54_pa_curve_data_sample curve_data[8];
-       u8 dup_bpsk;
-       u8 dup_qpsk;
-       u8 dup_16qam;
-       u8 dup_64qam;
-} __packed;
-
-/*
- * Warning: Longbow's structures are bogus.
- */
-struct p54_channel_output_limit_longbow {
-       __le16 rf_power_points[12];
-} __packed;
-
-struct p54_pa_curve_data_sample_longbow {
-       __le16 rf_power;
-       __le16 pa_detector;
-       struct {
-               __le16 data[4];
-       } points[3] __packed;
-} __packed;
-
-struct p54_scan_body_longbow {
-       struct p54_channel_output_limit_longbow power_limits;
-       struct p54_pa_curve_data_sample_longbow curve_data[8];
-       __le16 unkn[6];         /* maybe more power_limits or rate_mask */
-} __packed;
-
-union p54_scan_body_union {
-       struct p54_scan_body normal;
-       struct p54_scan_body_longbow longbow;
-} __packed;
-
-struct p54_scan_tail_rate {
-       __le32 basic_rate_mask;
-       u8 rts_rates[8];
-} __packed;
-
-struct p54_led {
-       __le16 flags;
-       __le16 mask[2];
-       __le16 delay[2];
-} __packed;
-
-struct p54_edcf {
-       u8 flags;
-       u8 slottime;
-       u8 sifs;
-       u8 eofpad;
-       struct p54_edcf_queue_param queue[8];
-       u8 mapping[4];
-       __le16 frameburst;
-       __le16 round_trip_delay;
-} __packed;
-
-struct p54_statistics {
-       __le32 rx_success;
-       __le32 rx_bad_fcs;
-       __le32 rx_abort;
-       __le32 rx_abort_phy;
-       __le32 rts_success;
-       __le32 rts_fail;
-       __le32 tsf32;
-       __le32 airtime;
-       __le32 noise;
-       __le32 sample_noise[8];
-       __le32 sample_cca;
-       __le32 sample_tx;
-} __packed;
-
-struct p54_xbow_synth {
-       __le16 magic1;
-       __le16 magic2;
-       __le16 freq;
-       u32 padding[5];
-} __packed;
-
-struct p54_timer {
-       __le32 interval;
-} __packed;
-
-struct p54_keycache {
-       u8 entry;
-       u8 key_id;
-       u8 mac[ETH_ALEN];
-       u8 padding[2];
-       u8 key_type;
-       u8 key_len;
-       u8 key[24];
-} __packed;
-
-struct p54_burst {
-       u8 flags;
-       u8 queue;
-       u8 backlog;
-       u8 pad;
-       __le16 durations[32];
-} __packed;
-
-struct p54_psm_interval {
-       __le16 interval;
-       __le16 periods;
-} __packed;
-
-#define P54_PSM_CAM                    0
-#define P54_PSM                                BIT(0)
-#define P54_PSM_DTIM                   BIT(1)
-#define P54_PSM_MCBC                   BIT(2)
-#define P54_PSM_CHECKSUM               BIT(3)
-#define P54_PSM_SKIP_MORE_DATA         BIT(4)
-#define P54_PSM_BEACON_TIMEOUT         BIT(5)
-#define P54_PSM_HFOSLEEP               BIT(6)
-#define P54_PSM_AUTOSWITCH_SLEEP       BIT(7)
-#define P54_PSM_LPIT                   BIT(8)
-#define P54_PSM_BF_UCAST_SKIP          BIT(9)
-#define P54_PSM_BF_MCAST_SKIP          BIT(10)
-
-struct p54_psm {
-       __le16 mode;
-       __le16 aid;
-       struct p54_psm_interval intervals[4];
-       u8 beacon_rssi_skip_max;
-       u8 rssi_delta_threshold;
-       u8 nr;
-       u8 exclude[1];
-} __packed;
-
-#define MC_FILTER_ADDRESS_NUM 4
-
-struct p54_group_address_table {
-       __le16 filter_enable;
-       __le16 num_address;
-       u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN];
-} __packed;
-
-struct p54_txcancel {
-       __le32 req_id;
-} __packed;
-
-struct p54_sta_unlock {
-       u8 addr[ETH_ALEN];
-       u16 padding;
-} __packed;
-
-#define P54_TIM_CLEAR BIT(15)
-struct p54_tim {
-       u8 count;
-       u8 padding[3];
-       __le16 entry[8];
-} __packed;
-
-struct p54_cce_quiet {
-       __le32 period;
-} __packed;
-
-struct p54_bt_balancer {
-       __le16 prio_thresh;
-       __le16 acl_thresh;
-} __packed;
-
-struct p54_arp_table {
-       __le16 filter_enable;
-       u8 ipv4_addr[4];
-} __packed;
-
-/* LED control */
-int p54_set_leds(struct p54_common *priv);
-int p54_init_leds(struct p54_common *priv);
-void p54_unregister_leds(struct p54_common *priv);
-
-/* xmit functions */
-void p54_tx_80211(struct ieee80211_hw *dev,
-                 struct ieee80211_tx_control *control,
-                 struct sk_buff *skb);
-int p54_tx_cancel(struct p54_common *priv, __le32 req_id);
-void p54_tx(struct p54_common *priv, struct sk_buff *skb);
-
-/* synth/phy configuration */
-int p54_init_xbow_synth(struct p54_common *priv);
-int p54_scan(struct p54_common *priv, u16 mode, u16 dwell);
-
-/* MAC */
-int p54_sta_unlock(struct p54_common *priv, u8 *addr);
-int p54_update_beacon_tim(struct p54_common *priv, u16 aid, bool set);
-int p54_setup_mac(struct p54_common *priv);
-int p54_set_ps(struct p54_common *priv);
-int p54_fetch_statistics(struct p54_common *priv);
-int p54_set_groupfilter(struct p54_common *priv);
-
-/* e/v DCF setup */
-int p54_set_edcf(struct p54_common *priv);
-
-/* cryptographic engine */
-int p54_upload_key(struct p54_common *priv, u8 algo, int slot,
-                  u8 idx, u8 len, u8 *addr, u8* key);
-
-/* eeprom */
-int p54_download_eeprom(struct p54_common *priv, void *buf,
-                       u16 offset, u16 len);
-struct p54_rssi_db_entry *p54_rssi_find(struct p54_common *p, const u16 freq);
-
-/* utility */
-u8 *p54_find_ie(struct sk_buff *skb, u8 ie);
-
-#endif /* LMAC_H */
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
deleted file mode 100644 (file)
index 7805864..0000000
+++ /dev/null
@@ -1,867 +0,0 @@
-/*
- * mac80211 glue code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-
-#include <net/mac80211.h>
-
-#include "p54.h"
-#include "lmac.h"
-
-static bool modparam_nohwcrypt;
-module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
-MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
-MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
-MODULE_DESCRIPTION("Softmac Prism54 common code");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54common");
-
-static int p54_sta_add_remove(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif,
-                             struct ieee80211_sta *sta)
-{
-       struct p54_common *priv = hw->priv;
-
-       /*
-        * Notify the firmware that we don't want or we don't
-        * need to buffer frames for this station anymore.
-        */
-
-       p54_sta_unlock(priv, sta->addr);
-
-       return 0;
-}
-
-static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
-                             enum sta_notify_cmd notify_cmd,
-                             struct ieee80211_sta *sta)
-{
-       struct p54_common *priv = dev->priv;
-
-       switch (notify_cmd) {
-       case STA_NOTIFY_AWAKE:
-               /* update the firmware's filter table */
-               p54_sta_unlock(priv, sta->addr);
-               break;
-       default:
-               break;
-       }
-}
-
-static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta,
-                       bool set)
-{
-       struct p54_common *priv = dev->priv;
-
-       return p54_update_beacon_tim(priv, sta->aid, set);
-}
-
-u8 *p54_find_ie(struct sk_buff *skb, u8 ie)
-{
-       struct ieee80211_mgmt *mgmt = (void *)skb->data;
-       u8 *pos, *end;
-
-       if (skb->len <= sizeof(mgmt))
-               return NULL;
-
-       pos = (u8 *)mgmt->u.beacon.variable;
-       end = skb->data + skb->len;
-       while (pos < end) {
-               if (pos + 2 + pos[1] > end)
-                       return NULL;
-
-               if (pos[0] == ie)
-                       return pos;
-
-               pos += 2 + pos[1];
-       }
-       return NULL;
-}
-
-static int p54_beacon_format_ie_tim(struct sk_buff *skb)
-{
-       /*
-        * the good excuse for this mess is ... the firmware.
-        * The dummy TIM MUST be at the end of the beacon frame,
-        * because it'll be overwritten!
-        */
-       u8 *tim;
-       u8 dtim_len;
-       u8 dtim_period;
-       u8 *next;
-
-       tim = p54_find_ie(skb, WLAN_EID_TIM);
-       if (!tim)
-               return 0;
-
-       dtim_len = tim[1];
-       dtim_period = tim[3];
-       next = tim + 2 + dtim_len;
-
-       if (dtim_len < 3)
-               return -EINVAL;
-
-       memmove(tim, next, skb_tail_pointer(skb) - next);
-       tim = skb_tail_pointer(skb) - (dtim_len + 2);
-
-       /* add the dummy at the end */
-       tim[0] = WLAN_EID_TIM;
-       tim[1] = 3;
-       tim[2] = 0;
-       tim[3] = dtim_period;
-       tim[4] = 0;
-
-       if (dtim_len > 3)
-               skb_trim(skb, skb->len - (dtim_len - 3));
-
-       return 0;
-}
-
-static int p54_beacon_update(struct p54_common *priv,
-                       struct ieee80211_vif *vif)
-{
-       struct ieee80211_tx_control control = { };
-       struct sk_buff *beacon;
-       int ret;
-
-       beacon = ieee80211_beacon_get(priv->hw, vif);
-       if (!beacon)
-               return -ENOMEM;
-       ret = p54_beacon_format_ie_tim(beacon);
-       if (ret)
-               return ret;
-
-       /*
-        * During operation, the firmware takes care of beaconing.
-        * The driver only needs to upload a new beacon template, once
-        * the template was changed by the stack or userspace.
-        *
-        * LMAC API 3.2.2 also specifies that the driver does not need
-        * to cancel the old beacon template by hand, instead the firmware
-        * will release the previous one through the feedback mechanism.
-        */
-       p54_tx_80211(priv->hw, &control, beacon);
-       priv->tsf_high32 = 0;
-       priv->tsf_low32 = 0;
-
-       return 0;
-}
-
-static int p54_start(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       int err;
-
-       mutex_lock(&priv->conf_mutex);
-       err = priv->open(dev);
-       if (err)
-               goto out;
-       P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47);
-       P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94);
-       P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0);
-       P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0);
-       err = p54_set_edcf(priv);
-       if (err)
-               goto out;
-
-       eth_broadcast_addr(priv->bssid);
-       priv->mode = NL80211_IFTYPE_MONITOR;
-       err = p54_setup_mac(priv);
-       if (err) {
-               priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-               goto out;
-       }
-
-       ieee80211_queue_delayed_work(dev, &priv->work, 0);
-
-       priv->softled_state = 0;
-       err = p54_set_leds(priv);
-
-out:
-       mutex_unlock(&priv->conf_mutex);
-       return err;
-}
-
-static void p54_stop(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       int i;
-
-       priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-       priv->softled_state = 0;
-       cancel_delayed_work_sync(&priv->work);
-       mutex_lock(&priv->conf_mutex);
-       p54_set_leds(priv);
-       priv->stop(dev);
-       skb_queue_purge(&priv->tx_pending);
-       skb_queue_purge(&priv->tx_queue);
-       for (i = 0; i < P54_QUEUE_NUM; i++) {
-               priv->tx_stats[i].count = 0;
-               priv->tx_stats[i].len = 0;
-       }
-
-       priv->beacon_req_id = cpu_to_le32(0);
-       priv->tsf_high32 = priv->tsf_low32 = 0;
-       mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_add_interface(struct ieee80211_hw *dev,
-                            struct ieee80211_vif *vif)
-{
-       struct p54_common *priv = dev->priv;
-       int err;
-
-       vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER;
-
-       mutex_lock(&priv->conf_mutex);
-       if (priv->mode != NL80211_IFTYPE_MONITOR) {
-               mutex_unlock(&priv->conf_mutex);
-               return -EOPNOTSUPP;
-       }
-
-       priv->vif = vif;
-
-       switch (vif->type) {
-       case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_MESH_POINT:
-               priv->mode = vif->type;
-               break;
-       default:
-               mutex_unlock(&priv->conf_mutex);
-               return -EOPNOTSUPP;
-       }
-
-       memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
-       err = p54_setup_mac(priv);
-       mutex_unlock(&priv->conf_mutex);
-       return err;
-}
-
-static void p54_remove_interface(struct ieee80211_hw *dev,
-                                struct ieee80211_vif *vif)
-{
-       struct p54_common *priv = dev->priv;
-
-       mutex_lock(&priv->conf_mutex);
-       priv->vif = NULL;
-
-       /*
-        * LMAC API 3.2.2 states that any active beacon template must be
-        * canceled by the driver before attempting a mode transition.
-        */
-       if (le32_to_cpu(priv->beacon_req_id) != 0) {
-               p54_tx_cancel(priv, priv->beacon_req_id);
-               wait_for_completion_interruptible_timeout(&priv->beacon_comp, HZ);
-       }
-       priv->mode = NL80211_IFTYPE_MONITOR;
-       eth_zero_addr(priv->mac_addr);
-       eth_zero_addr(priv->bssid);
-       p54_setup_mac(priv);
-       mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_wait_for_stats(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       int ret;
-
-       priv->update_stats = true;
-       ret = p54_fetch_statistics(priv);
-       if (ret)
-               return ret;
-
-       ret = wait_for_completion_interruptible_timeout(&priv->stat_comp, HZ);
-       if (ret == 0)
-               return -ETIMEDOUT;
-
-       return 0;
-}
-
-static void p54_reset_stats(struct p54_common *priv)
-{
-       struct ieee80211_channel *chan = priv->curchan;
-
-       if (chan) {
-               struct survey_info *info = &priv->survey[chan->hw_value];
-
-               /* only reset channel statistics, don't touch .filled, etc. */
-               info->time = 0;
-               info->time_busy = 0;
-               info->time_tx = 0;
-       }
-
-       priv->update_stats = true;
-       priv->survey_raw.active = 0;
-       priv->survey_raw.cca = 0;
-       priv->survey_raw.tx = 0;
-}
-
-static int p54_config(struct ieee80211_hw *dev, u32 changed)
-{
-       int ret = 0;
-       struct p54_common *priv = dev->priv;
-       struct ieee80211_conf *conf = &dev->conf;
-
-       mutex_lock(&priv->conf_mutex);
-       if (changed & IEEE80211_CONF_CHANGE_POWER)
-               priv->output_power = conf->power_level << 2;
-       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-               struct ieee80211_channel *oldchan;
-               WARN_ON(p54_wait_for_stats(dev));
-               oldchan = priv->curchan;
-               priv->curchan = NULL;
-               ret = p54_scan(priv, P54_SCAN_EXIT, 0);
-               if (ret) {
-                       priv->curchan = oldchan;
-                       goto out;
-               }
-               /*
-                * TODO: Use the LM_SCAN_TRAP to determine the current
-                * operating channel.
-                */
-               priv->curchan = priv->hw->conf.chandef.chan;
-               p54_reset_stats(priv);
-               WARN_ON(p54_fetch_statistics(priv));
-       }
-       if (changed & IEEE80211_CONF_CHANGE_PS) {
-               WARN_ON(p54_wait_for_stats(dev));
-               ret = p54_set_ps(priv);
-               if (ret)
-                       goto out;
-               WARN_ON(p54_wait_for_stats(dev));
-       }
-       if (changed & IEEE80211_CONF_CHANGE_IDLE) {
-               WARN_ON(p54_wait_for_stats(dev));
-               ret = p54_setup_mac(priv);
-               if (ret)
-                       goto out;
-               WARN_ON(p54_wait_for_stats(dev));
-       }
-
-out:
-       mutex_unlock(&priv->conf_mutex);
-       return ret;
-}
-
-static u64 p54_prepare_multicast(struct ieee80211_hw *dev,
-                                struct netdev_hw_addr_list *mc_list)
-{
-       struct p54_common *priv = dev->priv;
-       struct netdev_hw_addr *ha;
-       int i;
-
-       BUILD_BUG_ON(ARRAY_SIZE(priv->mc_maclist) !=
-               ARRAY_SIZE(((struct p54_group_address_table *)NULL)->mac_list));
-       /*
-        * The first entry is reserved for the global broadcast MAC.
-        * Otherwise the firmware will drop it and ARP will no longer work.
-        */
-       i = 1;
-       priv->mc_maclist_num = netdev_hw_addr_list_count(mc_list) + i;
-       netdev_hw_addr_list_for_each(ha, mc_list) {
-               memcpy(&priv->mc_maclist[i], ha->addr, ETH_ALEN);
-               i++;
-               if (i >= ARRAY_SIZE(priv->mc_maclist))
-                       break;
-       }
-
-       return 1; /* update */
-}
-
-static void p54_configure_filter(struct ieee80211_hw *dev,
-                                unsigned int changed_flags,
-                                unsigned int *total_flags,
-                                u64 multicast)
-{
-       struct p54_common *priv = dev->priv;
-
-       *total_flags &= FIF_ALLMULTI | FIF_OTHER_BSS;
-
-       priv->filter_flags = *total_flags;
-
-       if (changed_flags & FIF_OTHER_BSS)
-               p54_setup_mac(priv);
-
-       if (changed_flags & FIF_ALLMULTI || multicast)
-               p54_set_groupfilter(priv);
-}
-
-static int p54_conf_tx(struct ieee80211_hw *dev,
-                      struct ieee80211_vif *vif, u16 queue,
-                      const struct ieee80211_tx_queue_params *params)
-{
-       struct p54_common *priv = dev->priv;
-       int ret;
-
-       mutex_lock(&priv->conf_mutex);
-       if (queue < dev->queues) {
-               P54_SET_QUEUE(priv->qos_params[queue], params->aifs,
-                       params->cw_min, params->cw_max, params->txop);
-               ret = p54_set_edcf(priv);
-       } else
-               ret = -EINVAL;
-       mutex_unlock(&priv->conf_mutex);
-       return ret;
-}
-
-static void p54_work(struct work_struct *work)
-{
-       struct p54_common *priv = container_of(work, struct p54_common,
-                                              work.work);
-
-       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
-               return ;
-
-       /*
-        * TODO: walk through tx_queue and do the following tasks
-        *      1. initiate bursts.
-        *      2. cancel stuck frames / reset the device if necessary.
-        */
-
-       mutex_lock(&priv->conf_mutex);
-       WARN_ON_ONCE(p54_fetch_statistics(priv));
-       mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_get_stats(struct ieee80211_hw *dev,
-                        struct ieee80211_low_level_stats *stats)
-{
-       struct p54_common *priv = dev->priv;
-
-       memcpy(stats, &priv->stats, sizeof(*stats));
-       return 0;
-}
-
-static void p54_bss_info_changed(struct ieee80211_hw *dev,
-                                struct ieee80211_vif *vif,
-                                struct ieee80211_bss_conf *info,
-                                u32 changed)
-{
-       struct p54_common *priv = dev->priv;
-
-       mutex_lock(&priv->conf_mutex);
-       if (changed & BSS_CHANGED_BSSID) {
-               memcpy(priv->bssid, info->bssid, ETH_ALEN);
-               p54_setup_mac(priv);
-       }
-
-       if (changed & BSS_CHANGED_BEACON) {
-               p54_scan(priv, P54_SCAN_EXIT, 0);
-               p54_setup_mac(priv);
-               p54_beacon_update(priv, vif);
-               p54_set_edcf(priv);
-       }
-
-       if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BEACON)) {
-               priv->use_short_slot = info->use_short_slot;
-               p54_set_edcf(priv);
-       }
-       if (changed & BSS_CHANGED_BASIC_RATES) {
-               if (dev->conf.chandef.chan->band == IEEE80211_BAND_5GHZ)
-                       priv->basic_rate_mask = (info->basic_rates << 4);
-               else
-                       priv->basic_rate_mask = info->basic_rates;
-               p54_setup_mac(priv);
-               if (priv->fw_var >= 0x500)
-                       p54_scan(priv, P54_SCAN_EXIT, 0);
-       }
-       if (changed & BSS_CHANGED_ASSOC) {
-               if (info->assoc) {
-                       priv->aid = info->aid;
-                       priv->wakeup_timer = info->beacon_int *
-                                            info->dtim_period * 5;
-                       p54_setup_mac(priv);
-               } else {
-                       priv->wakeup_timer = 500;
-                       priv->aid = 0;
-               }
-       }
-
-       mutex_unlock(&priv->conf_mutex);
-}
-
-static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
-                      struct ieee80211_vif *vif, struct ieee80211_sta *sta,
-                      struct ieee80211_key_conf *key)
-{
-       struct p54_common *priv = dev->priv;
-       int slot, ret = 0;
-       u8 algo = 0;
-       u8 *addr = NULL;
-
-       if (modparam_nohwcrypt)
-               return -EOPNOTSUPP;
-
-       if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) {
-               /*
-                * Unfortunately most/all firmwares are trying to decrypt
-                * incoming management frames if a suitable key can be found.
-                * However, in doing so the data in these frames gets
-                * corrupted. So, we can't have firmware supported crypto
-                * offload in this case.
-                */
-               return -EOPNOTSUPP;
-       }
-
-       mutex_lock(&priv->conf_mutex);
-       if (cmd == SET_KEY) {
-               switch (key->cipher) {
-               case WLAN_CIPHER_SUITE_TKIP:
-                       if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL |
-                             BR_DESC_PRIV_CAP_TKIP))) {
-                               ret = -EOPNOTSUPP;
-                               goto out_unlock;
-                       }
-                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-                       algo = P54_CRYPTO_TKIPMICHAEL;
-                       break;
-               case WLAN_CIPHER_SUITE_WEP40:
-               case WLAN_CIPHER_SUITE_WEP104:
-                       if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) {
-                               ret = -EOPNOTSUPP;
-                               goto out_unlock;
-                       }
-                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-                       algo = P54_CRYPTO_WEP;
-                       break;
-               case WLAN_CIPHER_SUITE_CCMP:
-                       if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) {
-                               ret = -EOPNOTSUPP;
-                               goto out_unlock;
-                       }
-                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-                       algo = P54_CRYPTO_AESCCMP;
-                       break;
-               default:
-                       ret = -EOPNOTSUPP;
-                       goto out_unlock;
-               }
-               slot = bitmap_find_free_region(priv->used_rxkeys,
-                                              priv->rx_keycache_size, 0);
-
-               if (slot < 0) {
-                       /*
-                        * The device supports the chosen algorithm, but the
-                        * firmware does not provide enough key slots to store
-                        * all of them.
-                        * But encryption offload for outgoing frames is always
-                        * possible, so we just pretend that the upload was
-                        * successful and do the decryption in software.
-                        */
-
-                       /* mark the key as invalid. */
-                       key->hw_key_idx = 0xff;
-                       goto out_unlock;
-               }
-
-               key->flags |= IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
-       } else {
-               slot = key->hw_key_idx;
-
-               if (slot == 0xff) {
-                       /* This key was not uploaded into the rx key cache. */
-
-                       goto out_unlock;
-               }
-
-               bitmap_release_region(priv->used_rxkeys, slot, 0);
-               algo = 0;
-       }
-
-       if (sta)
-               addr = sta->addr;
-
-       ret = p54_upload_key(priv, algo, slot, key->keyidx,
-                            key->keylen, addr, key->key);
-       if (ret) {
-               bitmap_release_region(priv->used_rxkeys, slot, 0);
-               ret = -EOPNOTSUPP;
-               goto out_unlock;
-       }
-
-       key->hw_key_idx = slot;
-
-out_unlock:
-       mutex_unlock(&priv->conf_mutex);
-       return ret;
-}
-
-static int p54_get_survey(struct ieee80211_hw *dev, int idx,
-                               struct survey_info *survey)
-{
-       struct p54_common *priv = dev->priv;
-       struct ieee80211_channel *chan;
-       int err, tries;
-       bool in_use = false;
-
-       if (idx >= priv->chan_num)
-               return -ENOENT;
-
-#define MAX_TRIES 1
-       for (tries = 0; tries < MAX_TRIES; tries++) {
-               chan = priv->curchan;
-               if (chan && chan->hw_value == idx) {
-                       mutex_lock(&priv->conf_mutex);
-                       err = p54_wait_for_stats(dev);
-                       mutex_unlock(&priv->conf_mutex);
-                       if (err)
-                               return err;
-
-                       in_use = true;
-               }
-
-               memcpy(survey, &priv->survey[idx], sizeof(*survey));
-
-               if (in_use) {
-                       /* test if the reported statistics are valid. */
-                       if  (survey->time != 0) {
-                               survey->filled |= SURVEY_INFO_IN_USE;
-                       } else {
-                               /*
-                                * hw/fw has not accumulated enough sample sets.
-                                * Wait for 100ms, this ought to be enough to
-                                * to get at least one non-null set of channel
-                                * usage statistics.
-                                */
-                               msleep(100);
-                               continue;
-                       }
-               }
-               return 0;
-       }
-       return -ETIMEDOUT;
-#undef MAX_TRIES
-}
-
-static unsigned int p54_flush_count(struct p54_common *priv)
-{
-       unsigned int total = 0, i;
-
-       BUILD_BUG_ON(P54_QUEUE_NUM > ARRAY_SIZE(priv->tx_stats));
-
-       /*
-        * Because the firmware has the sole control over any frames
-        * in the P54_QUEUE_BEACON or P54_QUEUE_SCAN queues, they
-        * don't really count as pending or active.
-        */
-       for (i = P54_QUEUE_MGMT; i < P54_QUEUE_NUM; i++)
-               total += priv->tx_stats[i].len;
-       return total;
-}
-
-static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif,
-                     u32 queues, bool drop)
-{
-       struct p54_common *priv = dev->priv;
-       unsigned int total, i;
-
-       /*
-        * Currently, it wouldn't really matter if we wait for one second
-        * or 15 minutes. But once someone gets around and completes the
-        * TODOs [ancel stuck frames / reset device] in p54_work, it will
-        * suddenly make sense to wait that long.
-        */
-       i = P54_STATISTICS_UPDATE * 2 / 20;
-
-       /*
-        * In this case no locking is required because as we speak the
-        * queues have already been stopped and no new frames can sneak
-        * up from behind.
-        */
-       while ((total = p54_flush_count(priv) && i--)) {
-               /* waste time */
-               msleep(20);
-       }
-
-       WARN(total, "tx flush timeout, unresponsive firmware");
-}
-
-static void p54_set_coverage_class(struct ieee80211_hw *dev,
-                                  s16 coverage_class)
-{
-       struct p54_common *priv = dev->priv;
-
-       mutex_lock(&priv->conf_mutex);
-       /* support all coverage class values as in 802.11-2007 Table 7-27 */
-       priv->coverage_class = clamp_t(u8, coverage_class, 0, 31);
-       p54_set_edcf(priv);
-       mutex_unlock(&priv->conf_mutex);
-}
-
-static const struct ieee80211_ops p54_ops = {
-       .tx                     = p54_tx_80211,
-       .start                  = p54_start,
-       .stop                   = p54_stop,
-       .add_interface          = p54_add_interface,
-       .remove_interface       = p54_remove_interface,
-       .set_tim                = p54_set_tim,
-       .sta_notify             = p54_sta_notify,
-       .sta_add                = p54_sta_add_remove,
-       .sta_remove             = p54_sta_add_remove,
-       .set_key                = p54_set_key,
-       .config                 = p54_config,
-       .flush                  = p54_flush,
-       .bss_info_changed       = p54_bss_info_changed,
-       .prepare_multicast      = p54_prepare_multicast,
-       .configure_filter       = p54_configure_filter,
-       .conf_tx                = p54_conf_tx,
-       .get_stats              = p54_get_stats,
-       .get_survey             = p54_get_survey,
-       .set_coverage_class     = p54_set_coverage_class,
-};
-
-struct ieee80211_hw *p54_init_common(size_t priv_data_len)
-{
-       struct ieee80211_hw *dev;
-       struct p54_common *priv;
-
-       dev = ieee80211_alloc_hw(priv_data_len, &p54_ops);
-       if (!dev)
-               return NULL;
-
-       priv = dev->priv;
-       priv->hw = dev;
-       priv->mode = NL80211_IFTYPE_UNSPECIFIED;
-       priv->basic_rate_mask = 0x15f;
-       spin_lock_init(&priv->tx_stats_lock);
-       skb_queue_head_init(&priv->tx_queue);
-       skb_queue_head_init(&priv->tx_pending);
-       ieee80211_hw_set(dev, REPORTS_TX_ACK_STATUS);
-       ieee80211_hw_set(dev, MFP_CAPABLE);
-       ieee80211_hw_set(dev, PS_NULLFUNC_STACK);
-       ieee80211_hw_set(dev, SUPPORTS_PS);
-       ieee80211_hw_set(dev, RX_INCLUDES_FCS);
-       ieee80211_hw_set(dev, SIGNAL_DBM);
-
-       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-                                     BIT(NL80211_IFTYPE_ADHOC) |
-                                     BIT(NL80211_IFTYPE_AP) |
-                                     BIT(NL80211_IFTYPE_MESH_POINT);
-
-       priv->beacon_req_id = cpu_to_le32(0);
-       priv->tx_stats[P54_QUEUE_BEACON].limit = 1;
-       priv->tx_stats[P54_QUEUE_FWSCAN].limit = 1;
-       priv->tx_stats[P54_QUEUE_MGMT].limit = 3;
-       priv->tx_stats[P54_QUEUE_CAB].limit = 3;
-       priv->tx_stats[P54_QUEUE_DATA].limit = 5;
-       dev->queues = 1;
-       priv->noise = -94;
-       /*
-        * We support at most 8 tries no matter which rate they're at,
-        * we cannot support max_rates * max_rate_tries as we set it
-        * here, but setting it correctly to 4/2 or so would limit us
-        * artificially if the RC algorithm wants just two rates, so
-        * let's say 4/7, we'll redistribute it at TX time, see the
-        * comments there.
-        */
-       dev->max_rates = 4;
-       dev->max_rate_tries = 7;
-       dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 +
-                                sizeof(struct p54_tx_data);
-
-       /*
-        * For now, disable PS by default because it affects
-        * link stability significantly.
-        */
-       dev->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
-
-       mutex_init(&priv->conf_mutex);
-       mutex_init(&priv->eeprom_mutex);
-       init_completion(&priv->stat_comp);
-       init_completion(&priv->eeprom_comp);
-       init_completion(&priv->beacon_comp);
-       INIT_DELAYED_WORK(&priv->work, p54_work);
-
-       eth_broadcast_addr(priv->mc_maclist[0]);
-       priv->curchan = NULL;
-       p54_reset_stats(priv);
-       return dev;
-}
-EXPORT_SYMBOL_GPL(p54_init_common);
-
-int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
-{
-       struct p54_common __maybe_unused *priv = dev->priv;
-       int err;
-
-       err = ieee80211_register_hw(dev);
-       if (err) {
-               dev_err(pdev, "Cannot register device (%d).\n", err);
-               return err;
-       }
-       priv->registered = true;
-
-#ifdef CONFIG_P54_LEDS
-       err = p54_init_leds(priv);
-       if (err) {
-               p54_unregister_common(dev);
-               return err;
-       }
-#endif /* CONFIG_P54_LEDS */
-
-       dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
-       return 0;
-}
-EXPORT_SYMBOL_GPL(p54_register_common);
-
-void p54_free_common(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-       unsigned int i;
-
-       for (i = 0; i < IEEE80211_NUM_BANDS; i++)
-               kfree(priv->band_table[i]);
-
-       kfree(priv->iq_autocal);
-       kfree(priv->output_limit);
-       kfree(priv->curve_data);
-       kfree(priv->rssi_db);
-       kfree(priv->used_rxkeys);
-       kfree(priv->survey);
-       priv->iq_autocal = NULL;
-       priv->output_limit = NULL;
-       priv->curve_data = NULL;
-       priv->rssi_db = NULL;
-       priv->used_rxkeys = NULL;
-       priv->survey = NULL;
-       ieee80211_free_hw(dev);
-}
-EXPORT_SYMBOL_GPL(p54_free_common);
-
-void p54_unregister_common(struct ieee80211_hw *dev)
-{
-       struct p54_common *priv = dev->priv;
-
-#ifdef CONFIG_P54_LEDS
-       p54_unregister_leds(priv);
-#endif /* CONFIG_P54_LEDS */
-
-       if (priv->registered) {
-               priv->registered = false;
-               ieee80211_unregister_hw(dev);
-       }
-
-       mutex_destroy(&priv->conf_mutex);
-       mutex_destroy(&priv->eeprom_mutex);
-}
-EXPORT_SYMBOL_GPL(p54_unregister_common);
diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h
deleted file mode 100644 (file)
index 40b401e..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Shared defines for all mac80211 Prism54 code
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- *
- * Based on the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef P54_H
-#define P54_H
-
-#ifdef CONFIG_P54_LEDS
-#include <linux/leds.h>
-#endif /* CONFIG_P54_LEDS */
-
-#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000
-
-#define BR_CODE_MIN                    0x80000000
-#define BR_CODE_COMPONENT_ID           0x80000001
-#define BR_CODE_COMPONENT_VERSION      0x80000002
-#define BR_CODE_DEPENDENT_IF           0x80000003
-#define BR_CODE_EXPOSED_IF             0x80000004
-#define BR_CODE_DESCR                  0x80000101
-#define BR_CODE_MAX                    0x8FFFFFFF
-#define BR_CODE_END_OF_BRA             0xFF0000FF
-#define LEGACY_BR_CODE_END_OF_BRA      0xFFFFFFFF
-
-struct bootrec {
-       __le32 code;
-       __le32 len;
-       u32 data[10];
-} __packed;
-
-/* Interface role definitions */
-#define BR_INTERFACE_ROLE_SERVER       0x0000
-#define BR_INTERFACE_ROLE_CLIENT       0x8000
-
-#define BR_DESC_PRIV_CAP_WEP           BIT(0)
-#define BR_DESC_PRIV_CAP_TKIP          BIT(1)
-#define BR_DESC_PRIV_CAP_MICHAEL       BIT(2)
-#define BR_DESC_PRIV_CAP_CCX_CP                BIT(3)
-#define BR_DESC_PRIV_CAP_CCX_MIC       BIT(4)
-#define BR_DESC_PRIV_CAP_AESCCMP       BIT(5)
-
-struct bootrec_desc {
-       __le16 modes;
-       __le16 flags;
-       __le32 rx_start;
-       __le32 rx_end;
-       u8 headroom;
-       u8 tailroom;
-       u8 tx_queues;
-       u8 tx_depth;
-       u8 privacy_caps;
-       u8 rx_keycache_size;
-       u8 time_size;
-       u8 padding;
-       u8 rates[16];
-       u8 padding2[4];
-       __le16 rx_mtu;
-} __packed;
-
-#define FW_FMAC 0x464d4143
-#define FW_LM86 0x4c4d3836
-#define FW_LM87 0x4c4d3837
-#define FW_LM20 0x4c4d3230
-
-struct bootrec_comp_id {
-       __le32 fw_variant;
-} __packed;
-
-struct bootrec_comp_ver {
-       char fw_version[24];
-} __packed;
-
-struct bootrec_end {
-       __le16 crc;
-       u8 padding[2];
-       u8 md5[16];
-} __packed;
-
-/* provide 16 bytes for the transport back-end */
-#define P54_TX_INFO_DATA_SIZE          16
-
-/* stored in ieee80211_tx_info's rate_driver_data */
-struct p54_tx_info {
-       u32 start_addr;
-       u32 end_addr;
-       union {
-               void *data[P54_TX_INFO_DATA_SIZE / sizeof(void *)];
-               struct {
-                       u32 extra_len;
-               };
-       };
-};
-
-#define P54_MAX_CTRL_FRAME_LEN         0x1000
-
-#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop)     \
-do {                                                           \
-       queue.aifs = cpu_to_le16(ai_fs);                        \
-       queue.cwmin = cpu_to_le16(cw_min);                      \
-       queue.cwmax = cpu_to_le16(cw_max);                      \
-       queue.txop = cpu_to_le16(_txop);                        \
-} while (0)
-
-struct p54_edcf_queue_param {
-       __le16 aifs;
-       __le16 cwmin;
-       __le16 cwmax;
-       __le16 txop;
-} __packed;
-
-struct p54_rssi_db_entry {
-       u16 freq;
-       s16 mul;
-       s16 add;
-       s16 longbow_unkn;
-       s16 longbow_unk2;
-};
-
-struct p54_cal_database {
-       size_t entries;
-       size_t entry_size;
-       size_t offset;
-       size_t len;
-       u8 data[0];
-};
-
-#define EEPROM_READBACK_LEN 0x3fc
-
-enum fw_state {
-       FW_STATE_OFF,
-       FW_STATE_BOOTING,
-       FW_STATE_READY,
-       FW_STATE_RESET,
-       FW_STATE_RESETTING,
-};
-
-#ifdef CONFIG_P54_LEDS
-
-#define P54_LED_MAX_NAME_LEN 31
-
-struct p54_led_dev {
-       struct ieee80211_hw *hw_dev;
-       struct led_classdev led_dev;
-       char name[P54_LED_MAX_NAME_LEN + 1];
-
-       unsigned int toggled;
-       unsigned int index;
-       unsigned int registered;
-};
-
-#endif /* CONFIG_P54_LEDS */
-
-struct p54_tx_queue_stats {
-       unsigned int len;
-       unsigned int limit;
-       unsigned int count;
-};
-
-struct p54_common {
-       struct ieee80211_hw *hw;
-       struct ieee80211_vif *vif;
-       void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb);
-       int (*open)(struct ieee80211_hw *dev);
-       void (*stop)(struct ieee80211_hw *dev);
-       struct sk_buff_head tx_pending;
-       struct sk_buff_head tx_queue;
-       struct mutex conf_mutex;
-       bool registered;
-
-       /* memory management (as seen by the firmware) */
-       u32 rx_start;
-       u32 rx_end;
-       u16 rx_mtu;
-       u8 headroom;
-       u8 tailroom;
-
-       /* firmware/hardware info */
-       unsigned int tx_hdr_len;
-       unsigned int fw_var;
-       unsigned int fw_interface;
-       u8 version;
-
-       /* (e)DCF / QOS state */
-       bool use_short_slot;
-       spinlock_t tx_stats_lock;
-       struct p54_tx_queue_stats tx_stats[8];
-       struct p54_edcf_queue_param qos_params[8];
-
-       /* Radio data */
-       u16 rxhw;
-       u8 rx_diversity_mask;
-       u8 tx_diversity_mask;
-       unsigned int output_power;
-       struct p54_rssi_db_entry *cur_rssi;
-       struct ieee80211_channel *curchan;
-       struct survey_info *survey;
-       unsigned int chan_num;
-       struct completion stat_comp;
-       bool update_stats;
-       struct {
-               unsigned int timestamp;
-               unsigned int cached_cca;
-               unsigned int cached_tx;
-               unsigned int cached_rssi;
-               u64 active;
-               u64 cca;
-               u64 tx;
-               u64 rssi;
-       } survey_raw;
-
-       int noise;
-       /* calibration, output power limit and rssi<->dBm conversation data */
-       struct pda_iq_autocal_entry *iq_autocal;
-       unsigned int iq_autocal_len;
-       struct p54_cal_database *curve_data;
-       struct p54_cal_database *output_limit;
-       struct p54_cal_database *rssi_db;
-       struct ieee80211_supported_band *band_table[IEEE80211_NUM_BANDS];
-
-       /* BBP/MAC state */
-       u8 mac_addr[ETH_ALEN];
-       u8 bssid[ETH_ALEN];
-       u8 mc_maclist[4][ETH_ALEN];
-       u16 wakeup_timer;
-       unsigned int filter_flags;
-       int mc_maclist_num;
-       int mode;
-       u32 tsf_low32, tsf_high32;
-       u32 basic_rate_mask;
-       u16 aid;
-       u8 coverage_class;
-       bool phy_idle;
-       bool phy_ps;
-       bool powersave_override;
-       __le32 beacon_req_id;
-       struct completion beacon_comp;
-
-       /* cryptographic engine information */
-       u8 privacy_caps;
-       u8 rx_keycache_size;
-       unsigned long *used_rxkeys;
-
-       /* LED management */
-#ifdef CONFIG_P54_LEDS
-       struct p54_led_dev leds[4];
-       struct delayed_work led_work;
-#endif /* CONFIG_P54_LEDS */
-       u16 softled_state;              /* bit field of glowing LEDs */
-
-       /* statistics */
-       struct ieee80211_low_level_stats stats;
-       struct delayed_work work;
-
-       /* eeprom handling */
-       void *eeprom;
-       struct completion eeprom_comp;
-       struct mutex eeprom_mutex;
-};
-
-/* interfaces for the drivers */
-int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
-void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb);
-int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
-int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
-int p54_read_eeprom(struct ieee80211_hw *dev);
-
-struct ieee80211_hw *p54_init_common(size_t priv_data_len);
-int p54_register_common(struct ieee80211_hw *dev, struct device *pdev);
-void p54_free_common(struct ieee80211_hw *dev);
-
-void p54_unregister_common(struct ieee80211_hw *dev);
-
-#endif /* P54_H */
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
deleted file mode 100644 (file)
index 27a4906..0000000
+++ /dev/null
@@ -1,703 +0,0 @@
-
-/*
- * Linux device driver for PCI based Prism54
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2008, Christian Lamparter <chunkeey@web.de>
- *
- * Based on the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jean-baptiste.note@m4x.org>, et al.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/completion.h>
-#include <linux/module.h>
-#include <net/mac80211.h>
-
-#include "p54.h"
-#include "lmac.h"
-#include "p54pci.h"
-
-MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
-MODULE_DESCRIPTION("Prism54 PCI wireless driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54pci");
-MODULE_FIRMWARE("isl3886pci");
-
-static const struct pci_device_id p54p_table[] = {
-       /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */
-       { PCI_DEVICE(0x1260, 0x3890) },
-       /* 3COM 3CRWE154G72 Wireless LAN adapter */
-       { PCI_DEVICE(0x10b7, 0x6001) },
-       /* Intersil PRISM Indigo Wireless LAN adapter */
-       { PCI_DEVICE(0x1260, 0x3877) },
-       /* Intersil PRISM Javelin/Xbow Wireless LAN adapter */
-       { PCI_DEVICE(0x1260, 0x3886) },
-       /* Intersil PRISM Xbow Wireless LAN adapter (Symbol AP-300) */
-       { PCI_DEVICE(0x1260, 0xffff) },
-       { },
-};
-
-MODULE_DEVICE_TABLE(pci, p54p_table);
-
-static int p54p_upload_firmware(struct ieee80211_hw *dev)
-{
-       struct p54p_priv *priv = dev->priv;
-       __le32 reg;
-       int err;
-       __le32 *data;
-       u32 remains, left, device_addr;
-
-       P54P_WRITE(int_enable, cpu_to_le32(0));
-       P54P_READ(int_enable);
-       udelay(10);
-
-       reg = P54P_READ(ctrl_stat);
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
-       P54P_WRITE(ctrl_stat, reg);
-       P54P_READ(ctrl_stat);
-       udelay(10);
-
-       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
-       P54P_WRITE(ctrl_stat, reg);
-       wmb();
-       udelay(10);
-
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
-       P54P_WRITE(ctrl_stat, reg);
-       wmb();
-
-       /* wait for the firmware to reset properly */
-       mdelay(10);
-
-       err = p54_parse_firmware(dev, priv->firmware);
-       if (err)
-               return err;
-
-       if (priv->common.fw_interface != FW_LM86) {
-               dev_err(&priv->pdev->dev, "wrong firmware, "
-                       "please get a LM86(PCI) firmware a try again.\n");
-               return -EINVAL;
-       }
-
-       data = (__le32 *) priv->firmware->data;
-       remains = priv->firmware->size;
-       device_addr = ISL38XX_DEV_FIRMWARE_ADDR;
-       while (remains) {
-               u32 i = 0;
-               left = min((u32)0x1000, remains);
-               P54P_WRITE(direct_mem_base, cpu_to_le32(device_addr));
-               P54P_READ(int_enable);
-
-               device_addr += 0x1000;
-               while (i < left) {
-                       P54P_WRITE(direct_mem_win[i], *data++);
-                       i += sizeof(u32);
-               }
-
-               remains -= left;
-               P54P_READ(int_enable);
-       }
-
-       reg = P54P_READ(ctrl_stat);
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
-       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
-       P54P_WRITE(ctrl_stat, reg);
-       P54P_READ(ctrl_stat);
-       udelay(10);
-
-       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
-       P54P_WRITE(ctrl_stat, reg);
-       wmb();
-       udelay(10);
-
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
-       P54P_WRITE(ctrl_stat, reg);
-       wmb();
-       udelay(10);
-
-       /* wait for the firmware to boot properly */
-       mdelay(100);
-
-       return 0;
-}
-
-static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
-       int ring_index, struct p54p_desc *ring, u32 ring_limit,
-       struct sk_buff **rx_buf, u32 index)
-{
-       struct p54p_priv *priv = dev->priv;
-       struct p54p_ring_control *ring_control = priv->ring_control;
-       u32 limit, idx, i;
-
-       idx = le32_to_cpu(ring_control->host_idx[ring_index]);
-       limit = idx;
-       limit -= index;
-       limit = ring_limit - limit;
-
-       i = idx % ring_limit;
-       while (limit-- > 1) {
-               struct p54p_desc *desc = &ring[i];
-
-               if (!desc->host_addr) {
-                       struct sk_buff *skb;
-                       dma_addr_t mapping;
-                       skb = dev_alloc_skb(priv->common.rx_mtu + 32);
-                       if (!skb)
-                               break;
-
-                       mapping = pci_map_single(priv->pdev,
-                                                skb_tail_pointer(skb),
-                                                priv->common.rx_mtu + 32,
-                                                PCI_DMA_FROMDEVICE);
-
-                       if (pci_dma_mapping_error(priv->pdev, mapping)) {
-                               dev_kfree_skb_any(skb);
-                               dev_err(&priv->pdev->dev,
-                                       "RX DMA Mapping error\n");
-                               break;
-                       }
-
-                       desc->host_addr = cpu_to_le32(mapping);
-                       desc->device_addr = 0;  // FIXME: necessary?
-                       desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
-                       desc->flags = 0;
-                       rx_buf[i] = skb;
-               }
-
-               i++;
-               idx++;
-               i %= ring_limit;
-       }
-
-       wmb();
-       ring_control->host_idx[ring_index] = cpu_to_le32(idx);
-}
-
-static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
-       int ring_index, struct p54p_desc *ring, u32 ring_limit,
-       struct sk_buff **rx_buf)
-{
-       struct p54p_priv *priv = dev->priv;
-       struct p54p_ring_control *ring_control = priv->ring_control;
-       struct p54p_desc *desc;
-       u32 idx, i;
-
-       i = (*index) % ring_limit;
-       (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
-       idx %= ring_limit;
-       while (i != idx) {
-               u16 len;
-               struct sk_buff *skb;
-               dma_addr_t dma_addr;
-               desc = &ring[i];
-               len = le16_to_cpu(desc->len);
-               skb = rx_buf[i];
-
-               if (!skb) {
-                       i++;
-                       i %= ring_limit;
-                       continue;
-               }
-
-               if (unlikely(len > priv->common.rx_mtu)) {
-                       if (net_ratelimit())
-                               dev_err(&priv->pdev->dev, "rx'd frame size "
-                                       "exceeds length threshold.\n");
-
-                       len = priv->common.rx_mtu;
-               }
-               dma_addr = le32_to_cpu(desc->host_addr);
-               pci_dma_sync_single_for_cpu(priv->pdev, dma_addr,
-                       priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
-               skb_put(skb, len);
-
-               if (p54_rx(dev, skb)) {
-                       pci_unmap_single(priv->pdev, dma_addr,
-                               priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
-                       rx_buf[i] = NULL;
-                       desc->host_addr = cpu_to_le32(0);
-               } else {
-                       skb_trim(skb, 0);
-                       pci_dma_sync_single_for_device(priv->pdev, dma_addr,
-                               priv->common.rx_mtu + 32, PCI_DMA_FROMDEVICE);
-                       desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
-               }
-
-               i++;
-               i %= ring_limit;
-       }
-
-       p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf, *index);
-}
-
-static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index,
-       int ring_index, struct p54p_desc *ring, u32 ring_limit,
-       struct sk_buff **tx_buf)
-{
-       struct p54p_priv *priv = dev->priv;
-       struct p54p_ring_control *ring_control = priv->ring_control;
-       struct p54p_desc *desc;
-       struct sk_buff *skb;
-       u32 idx, i;
-
-       i = (*index) % ring_limit;
-       (*index) = idx = le32_to_cpu(ring_control->device_idx[ring_index]);
-       idx %= ring_limit;
-
-       while (i != idx) {
-               desc = &ring[i];
-
-               skb = tx_buf[i];
-               tx_buf[i] = NULL;
-
-               pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr),
-                                le16_to_cpu(desc->len), PCI_DMA_TODEVICE);
-
-               desc->host_addr = 0;
-               desc->device_addr = 0;
-               desc->len = 0;
-               desc->flags = 0;
-
-               if (skb && FREE_AFTER_TX(skb))
-                       p54_free_skb(dev, skb);
-
-               i++;
-               i %= ring_limit;
-       }
-}
-
-static void p54p_tasklet(unsigned long dev_id)
-{
-       struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id;
-       struct p54p_priv *priv = dev->priv;
-       struct p54p_ring_control *ring_control = priv->ring_control;
-
-       p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt,
-                          ARRAY_SIZE(ring_control->tx_mgmt),
-                          priv->tx_buf_mgmt);
-
-       p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data,
-                          ARRAY_SIZE(ring_control->tx_data),
-                          priv->tx_buf_data);
-
-       p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt,
-               ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt);
-
-       p54p_check_rx_ring(dev, &priv->rx_idx_data, 0, ring_control->rx_data,
-               ARRAY_SIZE(ring_control->rx_data), priv->rx_buf_data);
-
-       wmb();
-       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
-}
-
-static irqreturn_t p54p_interrupt(int irq, void *dev_id)
-{
-       struct ieee80211_hw *dev = dev_id;
-       struct p54p_priv *priv = dev->priv;
-       __le32 reg;
-
-       reg = P54P_READ(int_ident);
-       if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) {
-               goto out;
-       }
-       P54P_WRITE(int_ack, reg);
-
-       reg &= P54P_READ(int_enable);
-
-       if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE))
-               tasklet_schedule(&priv->tasklet);
-       else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT))
-               complete(&priv->boot_comp);
-
-out:
-       return reg ? IRQ_HANDLED : IRQ_NONE;
-}
-
-static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       unsigned long flags;
-       struct p54p_priv *priv = dev->priv;
-       struct p54p_ring_control *ring_control = priv->ring_control;
-       struct p54p_desc *desc;
-       dma_addr_t mapping;
-       u32 idx, i;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       idx = le32_to_cpu(ring_control->host_idx[1]);
-       i = idx % ARRAY_SIZE(ring_control->tx_data);
-
-       mapping = pci_map_single(priv->pdev, skb->data, skb->len,
-                                PCI_DMA_TODEVICE);
-       if (pci_dma_mapping_error(priv->pdev, mapping)) {
-               spin_unlock_irqrestore(&priv->lock, flags);
-               p54_free_skb(dev, skb);
-               dev_err(&priv->pdev->dev, "TX DMA mapping error\n");
-               return ;
-       }
-       priv->tx_buf_data[i] = skb;
-
-       desc = &ring_control->tx_data[i];
-       desc->host_addr = cpu_to_le32(mapping);
-       desc->device_addr = ((struct p54_hdr *)skb->data)->req_id;
-       desc->len = cpu_to_le16(skb->len);
-       desc->flags = 0;
-
-       wmb();
-       ring_control->host_idx[1] = cpu_to_le32(idx + 1);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
-       P54P_READ(dev_int);
-}
-
-static void p54p_stop(struct ieee80211_hw *dev)
-{
-       struct p54p_priv *priv = dev->priv;
-       struct p54p_ring_control *ring_control = priv->ring_control;
-       unsigned int i;
-       struct p54p_desc *desc;
-
-       P54P_WRITE(int_enable, cpu_to_le32(0));
-       P54P_READ(int_enable);
-       udelay(10);
-
-       free_irq(priv->pdev->irq, dev);
-
-       tasklet_kill(&priv->tasklet);
-
-       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
-
-       for (i = 0; i < ARRAY_SIZE(priv->rx_buf_data); i++) {
-               desc = &ring_control->rx_data[i];
-               if (desc->host_addr)
-                       pci_unmap_single(priv->pdev,
-                                        le32_to_cpu(desc->host_addr),
-                                        priv->common.rx_mtu + 32,
-                                        PCI_DMA_FROMDEVICE);
-               kfree_skb(priv->rx_buf_data[i]);
-               priv->rx_buf_data[i] = NULL;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(priv->rx_buf_mgmt); i++) {
-               desc = &ring_control->rx_mgmt[i];
-               if (desc->host_addr)
-                       pci_unmap_single(priv->pdev,
-                                        le32_to_cpu(desc->host_addr),
-                                        priv->common.rx_mtu + 32,
-                                        PCI_DMA_FROMDEVICE);
-               kfree_skb(priv->rx_buf_mgmt[i]);
-               priv->rx_buf_mgmt[i] = NULL;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(priv->tx_buf_data); i++) {
-               desc = &ring_control->tx_data[i];
-               if (desc->host_addr)
-                       pci_unmap_single(priv->pdev,
-                                        le32_to_cpu(desc->host_addr),
-                                        le16_to_cpu(desc->len),
-                                        PCI_DMA_TODEVICE);
-
-               p54_free_skb(dev, priv->tx_buf_data[i]);
-               priv->tx_buf_data[i] = NULL;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(priv->tx_buf_mgmt); i++) {
-               desc = &ring_control->tx_mgmt[i];
-               if (desc->host_addr)
-                       pci_unmap_single(priv->pdev,
-                                        le32_to_cpu(desc->host_addr),
-                                        le16_to_cpu(desc->len),
-                                        PCI_DMA_TODEVICE);
-
-               p54_free_skb(dev, priv->tx_buf_mgmt[i]);
-               priv->tx_buf_mgmt[i] = NULL;
-       }
-
-       memset(ring_control, 0, sizeof(*ring_control));
-}
-
-static int p54p_open(struct ieee80211_hw *dev)
-{
-       struct p54p_priv *priv = dev->priv;
-       int err;
-       long timeout;
-
-       init_completion(&priv->boot_comp);
-       err = request_irq(priv->pdev->irq, p54p_interrupt,
-                         IRQF_SHARED, "p54pci", dev);
-       if (err) {
-               dev_err(&priv->pdev->dev, "failed to register IRQ handler\n");
-               return err;
-       }
-
-       memset(priv->ring_control, 0, sizeof(*priv->ring_control));
-       err = p54p_upload_firmware(dev);
-       if (err) {
-               free_irq(priv->pdev->irq, dev);
-               return err;
-       }
-       priv->rx_idx_data = priv->tx_idx_data = 0;
-       priv->rx_idx_mgmt = priv->tx_idx_mgmt = 0;
-
-       p54p_refill_rx_ring(dev, 0, priv->ring_control->rx_data,
-               ARRAY_SIZE(priv->ring_control->rx_data), priv->rx_buf_data, 0);
-
-       p54p_refill_rx_ring(dev, 2, priv->ring_control->rx_mgmt,
-               ARRAY_SIZE(priv->ring_control->rx_mgmt), priv->rx_buf_mgmt, 0);
-
-       P54P_WRITE(ring_control_base, cpu_to_le32(priv->ring_control_dma));
-       P54P_READ(ring_control_base);
-       wmb();
-       udelay(10);
-
-       P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_INIT));
-       P54P_READ(int_enable);
-       wmb();
-       udelay(10);
-
-       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
-       P54P_READ(dev_int);
-
-       timeout = wait_for_completion_interruptible_timeout(
-                       &priv->boot_comp, HZ);
-       if (timeout <= 0) {
-               wiphy_err(dev->wiphy, "Cannot boot firmware!\n");
-               p54p_stop(dev);
-               return timeout ? -ERESTARTSYS : -ETIMEDOUT;
-       }
-
-       P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
-       P54P_READ(int_enable);
-       wmb();
-       udelay(10);
-
-       P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE));
-       P54P_READ(dev_int);
-       wmb();
-       udelay(10);
-
-       return 0;
-}
-
-static void p54p_firmware_step2(const struct firmware *fw,
-                               void *context)
-{
-       struct p54p_priv *priv = context;
-       struct ieee80211_hw *dev = priv->common.hw;
-       struct pci_dev *pdev = priv->pdev;
-       int err;
-
-       if (!fw) {
-               dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
-               err = -ENOENT;
-               goto out;
-       }
-
-       priv->firmware = fw;
-
-       err = p54p_open(dev);
-       if (err)
-               goto out;
-       err = p54_read_eeprom(dev);
-       p54p_stop(dev);
-       if (err)
-               goto out;
-
-       err = p54_register_common(dev, &pdev->dev);
-       if (err)
-               goto out;
-
-out:
-
-       complete(&priv->fw_loaded);
-
-       if (err) {
-               struct device *parent = pdev->dev.parent;
-
-               if (parent)
-                       device_lock(parent);
-
-               /*
-                * This will indirectly result in a call to p54p_remove.
-                * Hence, we don't need to bother with freeing any
-                * allocated ressources at all.
-                */
-               device_release_driver(&pdev->dev);
-
-               if (parent)
-                       device_unlock(parent);
-       }
-
-       pci_dev_put(pdev);
-}
-
-static int p54p_probe(struct pci_dev *pdev,
-                               const struct pci_device_id *id)
-{
-       struct p54p_priv *priv;
-       struct ieee80211_hw *dev;
-       unsigned long mem_addr, mem_len;
-       int err;
-
-       pci_dev_get(pdev);
-       err = pci_enable_device(pdev);
-       if (err) {
-               dev_err(&pdev->dev, "Cannot enable new PCI device\n");
-               return err;
-       }
-
-       mem_addr = pci_resource_start(pdev, 0);
-       mem_len = pci_resource_len(pdev, 0);
-       if (mem_len < sizeof(struct p54p_csr)) {
-               dev_err(&pdev->dev, "Too short PCI resources\n");
-               err = -ENODEV;
-               goto err_disable_dev;
-       }
-
-       err = pci_request_regions(pdev, "p54pci");
-       if (err) {
-               dev_err(&pdev->dev, "Cannot obtain PCI resources\n");
-               goto err_disable_dev;
-       }
-
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-       if (!err)
-               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
-       if (err) {
-               dev_err(&pdev->dev, "No suitable DMA available\n");
-               goto err_free_reg;
-       }
-
-       pci_set_master(pdev);
-       pci_try_set_mwi(pdev);
-
-       pci_write_config_byte(pdev, 0x40, 0);
-       pci_write_config_byte(pdev, 0x41, 0);
-
-       dev = p54_init_common(sizeof(*priv));
-       if (!dev) {
-               dev_err(&pdev->dev, "ieee80211 alloc failed\n");
-               err = -ENOMEM;
-               goto err_free_reg;
-       }
-
-       priv = dev->priv;
-       priv->pdev = pdev;
-
-       init_completion(&priv->fw_loaded);
-       SET_IEEE80211_DEV(dev, &pdev->dev);
-       pci_set_drvdata(pdev, dev);
-
-       priv->map = ioremap(mem_addr, mem_len);
-       if (!priv->map) {
-               dev_err(&pdev->dev, "Cannot map device memory\n");
-               err = -ENOMEM;
-               goto err_free_dev;
-       }
-
-       priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control),
-                                                 &priv->ring_control_dma);
-       if (!priv->ring_control) {
-               dev_err(&pdev->dev, "Cannot allocate rings\n");
-               err = -ENOMEM;
-               goto err_iounmap;
-       }
-       priv->common.open = p54p_open;
-       priv->common.stop = p54p_stop;
-       priv->common.tx = p54p_tx;
-
-       spin_lock_init(&priv->lock);
-       tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);
-
-       err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci",
-                                     &priv->pdev->dev, GFP_KERNEL,
-                                     priv, p54p_firmware_step2);
-       if (!err)
-               return 0;
-
-       pci_free_consistent(pdev, sizeof(*priv->ring_control),
-                           priv->ring_control, priv->ring_control_dma);
-
- err_iounmap:
-       iounmap(priv->map);
-
- err_free_dev:
-       p54_free_common(dev);
-
- err_free_reg:
-       pci_release_regions(pdev);
- err_disable_dev:
-       pci_disable_device(pdev);
-       pci_dev_put(pdev);
-       return err;
-}
-
-static void p54p_remove(struct pci_dev *pdev)
-{
-       struct ieee80211_hw *dev = pci_get_drvdata(pdev);
-       struct p54p_priv *priv;
-
-       if (!dev)
-               return;
-
-       priv = dev->priv;
-       wait_for_completion(&priv->fw_loaded);
-       p54_unregister_common(dev);
-       release_firmware(priv->firmware);
-       pci_free_consistent(pdev, sizeof(*priv->ring_control),
-                           priv->ring_control, priv->ring_control_dma);
-       iounmap(priv->map);
-       pci_release_regions(pdev);
-       pci_disable_device(pdev);
-       p54_free_common(dev);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int p54p_suspend(struct device *device)
-{
-       struct pci_dev *pdev = to_pci_dev(device);
-
-       pci_save_state(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
-       pci_disable_device(pdev);
-       return 0;
-}
-
-static int p54p_resume(struct device *device)
-{
-       struct pci_dev *pdev = to_pci_dev(device);
-       int err;
-
-       err = pci_reenable_device(pdev);
-       if (err)
-               return err;
-       return pci_set_power_state(pdev, PCI_D0);
-}
-
-static SIMPLE_DEV_PM_OPS(p54pci_pm_ops, p54p_suspend, p54p_resume);
-
-#define P54P_PM_OPS (&p54pci_pm_ops)
-#else
-#define P54P_PM_OPS (NULL)
-#endif /* CONFIG_PM_SLEEP */
-
-static struct pci_driver p54p_driver = {
-       .name           = "p54pci",
-       .id_table       = p54p_table,
-       .probe          = p54p_probe,
-       .remove         = p54p_remove,
-       .driver.pm      = P54P_PM_OPS,
-};
-
-module_pci_driver(p54p_driver);
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
deleted file mode 100644 (file)
index 68405c1..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef P54PCI_H
-#define P54PCI_H
-#include <linux/interrupt.h>
-
-/*
- * Defines for PCI based mac80211 Prism54 driver
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- *
- * Based on the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* Device Interrupt register bits */
-#define ISL38XX_DEV_INT_RESET                   0x0001
-#define ISL38XX_DEV_INT_UPDATE                  0x0002
-#define ISL38XX_DEV_INT_WAKEUP                  0x0008
-#define ISL38XX_DEV_INT_SLEEP                   0x0010
-#define ISL38XX_DEV_INT_ABORT                   0x0020
-/* these two only used in USB */
-#define ISL38XX_DEV_INT_DATA                    0x0040
-#define ISL38XX_DEV_INT_MGMT                    0x0080
-
-#define ISL38XX_DEV_INT_PCIUART_CTS             0x4000
-#define ISL38XX_DEV_INT_PCIUART_DR              0x8000
-
-/* Interrupt Identification/Acknowledge/Enable register bits */
-#define ISL38XX_INT_IDENT_UPDATE               0x0002
-#define ISL38XX_INT_IDENT_INIT                 0x0004
-#define ISL38XX_INT_IDENT_WAKEUP               0x0008
-#define ISL38XX_INT_IDENT_SLEEP                        0x0010
-#define ISL38XX_INT_IDENT_PCIUART_CTS          0x4000
-#define ISL38XX_INT_IDENT_PCIUART_DR           0x8000
-
-/* Control/Status register bits */
-#define ISL38XX_CTRL_STAT_SLEEPMODE            0x00000200
-#define ISL38XX_CTRL_STAT_CLKRUN               0x00800000
-#define ISL38XX_CTRL_STAT_RESET                        0x10000000
-#define ISL38XX_CTRL_STAT_RAMBOOT              0x20000000
-#define ISL38XX_CTRL_STAT_STARTHALTED          0x40000000
-#define ISL38XX_CTRL_STAT_HOST_OVERRIDE                0x80000000
-
-struct p54p_csr {
-       __le32 dev_int;
-       u8 unused_1[12];
-       __le32 int_ident;
-       __le32 int_ack;
-       __le32 int_enable;
-       u8 unused_2[4];
-       union {
-               __le32 ring_control_base;
-               __le32 gen_purp_com[2];
-       };
-       u8 unused_3[8];
-       __le32 direct_mem_base;
-       u8 unused_4[44];
-       __le32 dma_addr;
-       __le32 dma_len;
-       __le32 dma_ctrl;
-       u8 unused_5[12];
-       __le32 ctrl_stat;
-       u8 unused_6[1924];
-       u8 cardbus_cis[0x800];
-       u8 direct_mem_win[0x1000];
-} __packed;
-
-/* usb backend only needs the register defines above */
-#ifndef P54USB_H
-struct p54p_desc {
-       __le32 host_addr;
-       __le32 device_addr;
-       __le16 len;
-       __le16 flags;
-} __packed;
-
-struct p54p_ring_control {
-       __le32 host_idx[4];
-       __le32 device_idx[4];
-       struct p54p_desc rx_data[8];
-       struct p54p_desc tx_data[32];
-       struct p54p_desc rx_mgmt[4];
-       struct p54p_desc tx_mgmt[4];
-} __packed;
-
-#define P54P_READ(r) (__force __le32)__raw_readl(&priv->map->r)
-#define P54P_WRITE(r, val) __raw_writel((__force u32)(__le32)(val), &priv->map->r)
-
-struct p54p_priv {
-       struct p54_common common;
-       struct pci_dev *pdev;
-       struct p54p_csr __iomem *map;
-       struct tasklet_struct tasklet;
-       const struct firmware *firmware;
-       spinlock_t lock;
-       struct p54p_ring_control *ring_control;
-       dma_addr_t ring_control_dma;
-       u32 rx_idx_data, tx_idx_data;
-       u32 rx_idx_mgmt, tx_idx_mgmt;
-       struct sk_buff *rx_buf_data[8];
-       struct sk_buff *rx_buf_mgmt[4];
-       struct sk_buff *tx_buf_data[32];
-       struct sk_buff *tx_buf_mgmt[4];
-       struct completion boot_comp;
-       struct completion fw_loaded;
-};
-
-#endif /* P54USB_H */
-#endif /* P54PCI_H */
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
deleted file mode 100644 (file)
index 7ab2f43..0000000
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
- * Copyright (C) 2008 Christian Lamparter <chunkeey@web.de>
- * Copyright 2008       Johannes Berg <johannes@sipsolutions.net>
- *
- * This driver is a port from stlc45xx:
- *     Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/firmware.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/spi/spi.h>
-#include <linux/etherdevice.h>
-#include <linux/gpio.h>
-#include <linux/slab.h>
-
-#include "p54spi.h"
-#include "p54.h"
-
-#include "lmac.h"
-
-#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
-#include "p54spi_eeprom.h"
-#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
-
-MODULE_FIRMWARE("3826.arm");
-
-/* gpios should be handled in board files and provided via platform data,
- * but because it's currently impossible for p54spi to have a header file
- * in include/linux, let's use module paramaters for now
- */
-
-static int p54spi_gpio_power = 97;
-module_param(p54spi_gpio_power, int, 0444);
-MODULE_PARM_DESC(p54spi_gpio_power, "gpio number for power line");
-
-static int p54spi_gpio_irq = 87;
-module_param(p54spi_gpio_irq, int, 0444);
-MODULE_PARM_DESC(p54spi_gpio_irq, "gpio number for irq line");
-
-static void p54spi_spi_read(struct p54s_priv *priv, u8 address,
-                             void *buf, size_t len)
-{
-       struct spi_transfer t[2];
-       struct spi_message m;
-       __le16 addr;
-
-       /* We first push the address */
-       addr = cpu_to_le16(address << 8 | SPI_ADRS_READ_BIT_15);
-
-       spi_message_init(&m);
-       memset(t, 0, sizeof(t));
-
-       t[0].tx_buf = &addr;
-       t[0].len = sizeof(addr);
-       spi_message_add_tail(&t[0], &m);
-
-       t[1].rx_buf = buf;
-       t[1].len = len;
-       spi_message_add_tail(&t[1], &m);
-
-       spi_sync(priv->spi, &m);
-}
-
-
-static void p54spi_spi_write(struct p54s_priv *priv, u8 address,
-                            const void *buf, size_t len)
-{
-       struct spi_transfer t[3];
-       struct spi_message m;
-       __le16 addr;
-
-       /* We first push the address */
-       addr = cpu_to_le16(address << 8);
-
-       spi_message_init(&m);
-       memset(t, 0, sizeof(t));
-
-       t[0].tx_buf = &addr;
-       t[0].len = sizeof(addr);
-       spi_message_add_tail(&t[0], &m);
-
-       t[1].tx_buf = buf;
-       t[1].len = len & ~1;
-       spi_message_add_tail(&t[1], &m);
-
-       if (len % 2) {
-               __le16 last_word;
-               last_word = cpu_to_le16(((u8 *)buf)[len - 1]);
-
-               t[2].tx_buf = &last_word;
-               t[2].len = sizeof(last_word);
-               spi_message_add_tail(&t[2], &m);
-       }
-
-       spi_sync(priv->spi, &m);
-}
-
-static u32 p54spi_read32(struct p54s_priv *priv, u8 addr)
-{
-       __le32 val;
-
-       p54spi_spi_read(priv, addr, &val, sizeof(val));
-
-       return le32_to_cpu(val);
-}
-
-static inline void p54spi_write16(struct p54s_priv *priv, u8 addr, __le16 val)
-{
-       p54spi_spi_write(priv, addr, &val, sizeof(val));
-}
-
-static inline void p54spi_write32(struct p54s_priv *priv, u8 addr, __le32 val)
-{
-       p54spi_spi_write(priv, addr, &val, sizeof(val));
-}
-
-static int p54spi_wait_bit(struct p54s_priv *priv, u16 reg, u32 bits)
-{
-       int i;
-
-       for (i = 0; i < 2000; i++) {
-               u32 buffer = p54spi_read32(priv, reg);
-               if ((buffer & bits) == bits)
-                       return 1;
-       }
-       return 0;
-}
-
-static int p54spi_spi_write_dma(struct p54s_priv *priv, __le32 base,
-                               const void *buf, size_t len)
-{
-       if (!p54spi_wait_bit(priv, SPI_ADRS_DMA_WRITE_CTRL, HOST_ALLOWED)) {
-               dev_err(&priv->spi->dev, "spi_write_dma not allowed "
-                       "to DMA write.\n");
-               return -EAGAIN;
-       }
-
-       p54spi_write16(priv, SPI_ADRS_DMA_WRITE_CTRL,
-                      cpu_to_le16(SPI_DMA_WRITE_CTRL_ENABLE));
-
-       p54spi_write16(priv, SPI_ADRS_DMA_WRITE_LEN, cpu_to_le16(len));
-       p54spi_write32(priv, SPI_ADRS_DMA_WRITE_BASE, base);
-       p54spi_spi_write(priv, SPI_ADRS_DMA_DATA, buf, len);
-       return 0;
-}
-
-static int p54spi_request_firmware(struct ieee80211_hw *dev)
-{
-       struct p54s_priv *priv = dev->priv;
-       int ret;
-
-       /* FIXME: should driver use it's own struct device? */
-       ret = request_firmware(&priv->firmware, "3826.arm", &priv->spi->dev);
-
-       if (ret < 0) {
-               dev_err(&priv->spi->dev, "request_firmware() failed: %d", ret);
-               return ret;
-       }
-
-       ret = p54_parse_firmware(dev, priv->firmware);
-       if (ret) {
-               release_firmware(priv->firmware);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int p54spi_request_eeprom(struct ieee80211_hw *dev)
-{
-       struct p54s_priv *priv = dev->priv;
-       const struct firmware *eeprom;
-       int ret;
-
-       /* allow users to customize their eeprom.
-        */
-
-       ret = request_firmware_direct(&eeprom, "3826.eeprom", &priv->spi->dev);
-       if (ret < 0) {
-#ifdef CONFIG_P54_SPI_DEFAULT_EEPROM
-               dev_info(&priv->spi->dev, "loading default eeprom...\n");
-               ret = p54_parse_eeprom(dev, (void *) p54spi_eeprom,
-                                      sizeof(p54spi_eeprom));
-#else
-               dev_err(&priv->spi->dev, "Failed to request user eeprom\n");
-#endif /* CONFIG_P54_SPI_DEFAULT_EEPROM */
-       } else {
-               dev_info(&priv->spi->dev, "loading user eeprom...\n");
-               ret = p54_parse_eeprom(dev, (void *) eeprom->data,
-                                      (int)eeprom->size);
-               release_firmware(eeprom);
-       }
-       return ret;
-}
-
-static int p54spi_upload_firmware(struct ieee80211_hw *dev)
-{
-       struct p54s_priv *priv = dev->priv;
-       unsigned long fw_len, _fw_len;
-       unsigned int offset = 0;
-       int err = 0;
-       u8 *fw;
-
-       fw_len = priv->firmware->size;
-       fw = kmemdup(priv->firmware->data, fw_len, GFP_KERNEL);
-       if (!fw)
-               return -ENOMEM;
-
-       /* stop the device */
-       p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
-                      SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET |
-                      SPI_CTRL_STAT_START_HALTED));
-
-       msleep(TARGET_BOOT_SLEEP);
-
-       p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
-                      SPI_CTRL_STAT_HOST_OVERRIDE |
-                      SPI_CTRL_STAT_START_HALTED));
-
-       msleep(TARGET_BOOT_SLEEP);
-
-       while (fw_len > 0) {
-               _fw_len = min_t(long, fw_len, SPI_MAX_PACKET_SIZE);
-
-               err = p54spi_spi_write_dma(priv, cpu_to_le32(
-                                          ISL38XX_DEV_FIRMWARE_ADDR + offset),
-                                          (fw + offset), _fw_len);
-               if (err < 0)
-                       goto out;
-
-               fw_len -= _fw_len;
-               offset += _fw_len;
-       }
-
-       BUG_ON(fw_len != 0);
-
-       /* enable host interrupts */
-       p54spi_write32(priv, SPI_ADRS_HOST_INT_EN,
-                      cpu_to_le32(SPI_HOST_INTS_DEFAULT));
-
-       /* boot the device */
-       p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
-                      SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_HOST_RESET |
-                      SPI_CTRL_STAT_RAM_BOOT));
-
-       msleep(TARGET_BOOT_SLEEP);
-
-       p54spi_write16(priv, SPI_ADRS_DEV_CTRL_STAT, cpu_to_le16(
-                      SPI_CTRL_STAT_HOST_OVERRIDE | SPI_CTRL_STAT_RAM_BOOT));
-       msleep(TARGET_BOOT_SLEEP);
-
-out:
-       kfree(fw);
-       return err;
-}
-
-static void p54spi_power_off(struct p54s_priv *priv)
-{
-       disable_irq(gpio_to_irq(p54spi_gpio_irq));
-       gpio_set_value(p54spi_gpio_power, 0);
-}
-
-static void p54spi_power_on(struct p54s_priv *priv)
-{
-       gpio_set_value(p54spi_gpio_power, 1);
-       enable_irq(gpio_to_irq(p54spi_gpio_irq));
-
-       /* need to wait a while before device can be accessed, the length
-        * is just a guess
-        */
-       msleep(10);
-}
-
-static inline void p54spi_int_ack(struct p54s_priv *priv, u32 val)
-{
-       p54spi_write32(priv, SPI_ADRS_HOST_INT_ACK, cpu_to_le32(val));
-}
-
-static int p54spi_wakeup(struct p54s_priv *priv)
-{
-       /* wake the chip */
-       p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS,
-                      cpu_to_le32(SPI_TARGET_INT_WAKEUP));
-
-       /* And wait for the READY interrupt */
-       if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
-                            SPI_HOST_INT_READY)) {
-               dev_err(&priv->spi->dev, "INT_READY timeout\n");
-               return -EBUSY;
-       }
-
-       p54spi_int_ack(priv, SPI_HOST_INT_READY);
-       return 0;
-}
-
-static inline void p54spi_sleep(struct p54s_priv *priv)
-{
-       p54spi_write32(priv, SPI_ADRS_ARM_INTERRUPTS,
-                      cpu_to_le32(SPI_TARGET_INT_SLEEP));
-}
-
-static void p54spi_int_ready(struct p54s_priv *priv)
-{
-       p54spi_write32(priv, SPI_ADRS_HOST_INT_EN, cpu_to_le32(
-                      SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE));
-
-       switch (priv->fw_state) {
-       case FW_STATE_BOOTING:
-               priv->fw_state = FW_STATE_READY;
-               complete(&priv->fw_comp);
-               break;
-       case FW_STATE_RESETTING:
-               priv->fw_state = FW_STATE_READY;
-               /* TODO: reinitialize state */
-               break;
-       default:
-               break;
-       }
-}
-
-static int p54spi_rx(struct p54s_priv *priv)
-{
-       struct sk_buff *skb;
-       u16 len;
-       u16 rx_head[2];
-#define READAHEAD_SZ (sizeof(rx_head)-sizeof(u16))
-
-       if (p54spi_wakeup(priv) < 0)
-               return -EBUSY;
-
-       /* Read data size and first data word in one SPI transaction
-        * This is workaround for firmware/DMA bug,
-        * when first data word gets lost under high load.
-        */
-       p54spi_spi_read(priv, SPI_ADRS_DMA_DATA, rx_head, sizeof(rx_head));
-       len = rx_head[0];
-
-       if (len == 0) {
-               p54spi_sleep(priv);
-               dev_err(&priv->spi->dev, "rx request of zero bytes\n");
-               return 0;
-       }
-
-       /* Firmware may insert up to 4 padding bytes after the lmac header,
-        * but it does not amend the size of SPI data transfer.
-        * Such packets has correct data size in header, thus referencing
-        * past the end of allocated skb. Reserve extra 4 bytes for this case
-        */
-       skb = dev_alloc_skb(len + 4);
-       if (!skb) {
-               p54spi_sleep(priv);
-               dev_err(&priv->spi->dev, "could not alloc skb");
-               return -ENOMEM;
-       }
-
-       if (len <= READAHEAD_SZ) {
-               memcpy(skb_put(skb, len), rx_head + 1, len);
-       } else {
-               memcpy(skb_put(skb, READAHEAD_SZ), rx_head + 1, READAHEAD_SZ);
-               p54spi_spi_read(priv, SPI_ADRS_DMA_DATA,
-                               skb_put(skb, len - READAHEAD_SZ),
-                               len - READAHEAD_SZ);
-       }
-       p54spi_sleep(priv);
-       /* Put additional bytes to compensate for the possible
-        * alignment-caused truncation
-        */
-       skb_put(skb, 4);
-
-       if (p54_rx(priv->hw, skb) == 0)
-               dev_kfree_skb(skb);
-
-       return 0;
-}
-
-
-static irqreturn_t p54spi_interrupt(int irq, void *config)
-{
-       struct spi_device *spi = config;
-       struct p54s_priv *priv = spi_get_drvdata(spi);
-
-       ieee80211_queue_work(priv->hw, &priv->work);
-
-       return IRQ_HANDLED;
-}
-
-static int p54spi_tx_frame(struct p54s_priv *priv, struct sk_buff *skb)
-{
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-       int ret = 0;
-
-       if (p54spi_wakeup(priv) < 0)
-               return -EBUSY;
-
-       ret = p54spi_spi_write_dma(priv, hdr->req_id, skb->data, skb->len);
-       if (ret < 0)
-               goto out;
-
-       if (!p54spi_wait_bit(priv, SPI_ADRS_HOST_INTERRUPTS,
-                            SPI_HOST_INT_WR_READY)) {
-               dev_err(&priv->spi->dev, "WR_READY timeout\n");
-               ret = -EAGAIN;
-               goto out;
-       }
-
-       p54spi_int_ack(priv, SPI_HOST_INT_WR_READY);
-
-       if (FREE_AFTER_TX(skb))
-               p54_free_skb(priv->hw, skb);
-out:
-       p54spi_sleep(priv);
-       return ret;
-}
-
-static int p54spi_wq_tx(struct p54s_priv *priv)
-{
-       struct p54s_tx_info *entry;
-       struct sk_buff *skb;
-       struct ieee80211_tx_info *info;
-       struct p54_tx_info *minfo;
-       struct p54s_tx_info *dinfo;
-       unsigned long flags;
-       int ret = 0;
-
-       spin_lock_irqsave(&priv->tx_lock, flags);
-
-       while (!list_empty(&priv->tx_pending)) {
-               entry = list_entry(priv->tx_pending.next,
-                                  struct p54s_tx_info, tx_list);
-
-               list_del_init(&entry->tx_list);
-
-               spin_unlock_irqrestore(&priv->tx_lock, flags);
-
-               dinfo = container_of((void *) entry, struct p54s_tx_info,
-                                    tx_list);
-               minfo = container_of((void *) dinfo, struct p54_tx_info,
-                                    data);
-               info = container_of((void *) minfo, struct ieee80211_tx_info,
-                                   rate_driver_data);
-               skb = container_of((void *) info, struct sk_buff, cb);
-
-               ret = p54spi_tx_frame(priv, skb);
-
-               if (ret < 0) {
-                       p54_free_skb(priv->hw, skb);
-                       return ret;
-               }
-
-               spin_lock_irqsave(&priv->tx_lock, flags);
-       }
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
-       return ret;
-}
-
-static void p54spi_op_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54s_priv *priv = dev->priv;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct p54_tx_info *mi = (struct p54_tx_info *) info->rate_driver_data;
-       struct p54s_tx_info *di = (struct p54s_tx_info *) mi->data;
-       unsigned long flags;
-
-       BUILD_BUG_ON(sizeof(*di) > sizeof((mi->data)));
-
-       spin_lock_irqsave(&priv->tx_lock, flags);
-       list_add_tail(&di->tx_list, &priv->tx_pending);
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
-
-       ieee80211_queue_work(priv->hw, &priv->work);
-}
-
-static void p54spi_work(struct work_struct *work)
-{
-       struct p54s_priv *priv = container_of(work, struct p54s_priv, work);
-       u32 ints;
-       int ret;
-
-       mutex_lock(&priv->mutex);
-
-       if (priv->fw_state == FW_STATE_OFF)
-               goto out;
-
-       ints = p54spi_read32(priv, SPI_ADRS_HOST_INTERRUPTS);
-
-       if (ints & SPI_HOST_INT_READY) {
-               p54spi_int_ready(priv);
-               p54spi_int_ack(priv, SPI_HOST_INT_READY);
-       }
-
-       if (priv->fw_state != FW_STATE_READY)
-               goto out;
-
-       if (ints & SPI_HOST_INT_UPDATE) {
-               p54spi_int_ack(priv, SPI_HOST_INT_UPDATE);
-               ret = p54spi_rx(priv);
-               if (ret < 0)
-                       goto out;
-       }
-       if (ints & SPI_HOST_INT_SW_UPDATE) {
-               p54spi_int_ack(priv, SPI_HOST_INT_SW_UPDATE);
-               ret = p54spi_rx(priv);
-               if (ret < 0)
-                       goto out;
-       }
-
-       ret = p54spi_wq_tx(priv);
-out:
-       mutex_unlock(&priv->mutex);
-}
-
-static int p54spi_op_start(struct ieee80211_hw *dev)
-{
-       struct p54s_priv *priv = dev->priv;
-       unsigned long timeout;
-       int ret = 0;
-
-       if (mutex_lock_interruptible(&priv->mutex)) {
-               ret = -EINTR;
-               goto out;
-       }
-
-       priv->fw_state = FW_STATE_BOOTING;
-
-       p54spi_power_on(priv);
-
-       ret = p54spi_upload_firmware(dev);
-       if (ret < 0) {
-               p54spi_power_off(priv);
-               goto out_unlock;
-       }
-
-       mutex_unlock(&priv->mutex);
-
-       timeout = msecs_to_jiffies(2000);
-       timeout = wait_for_completion_interruptible_timeout(&priv->fw_comp,
-                                                           timeout);
-       if (!timeout) {
-               dev_err(&priv->spi->dev, "firmware boot failed");
-               p54spi_power_off(priv);
-               ret = -1;
-               goto out;
-       }
-
-       if (mutex_lock_interruptible(&priv->mutex)) {
-               ret = -EINTR;
-               p54spi_power_off(priv);
-               goto out;
-       }
-
-       WARN_ON(priv->fw_state != FW_STATE_READY);
-
-out_unlock:
-       mutex_unlock(&priv->mutex);
-
-out:
-       return ret;
-}
-
-static void p54spi_op_stop(struct ieee80211_hw *dev)
-{
-       struct p54s_priv *priv = dev->priv;
-       unsigned long flags;
-
-       mutex_lock(&priv->mutex);
-       WARN_ON(priv->fw_state != FW_STATE_READY);
-
-       p54spi_power_off(priv);
-       spin_lock_irqsave(&priv->tx_lock, flags);
-       INIT_LIST_HEAD(&priv->tx_pending);
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
-
-       priv->fw_state = FW_STATE_OFF;
-       mutex_unlock(&priv->mutex);
-
-       cancel_work_sync(&priv->work);
-}
-
-static int p54spi_probe(struct spi_device *spi)
-{
-       struct p54s_priv *priv = NULL;
-       struct ieee80211_hw *hw;
-       int ret = -EINVAL;
-
-       hw = p54_init_common(sizeof(*priv));
-       if (!hw) {
-               dev_err(&spi->dev, "could not alloc ieee80211_hw");
-               return -ENOMEM;
-       }
-
-       priv = hw->priv;
-       priv->hw = hw;
-       spi_set_drvdata(spi, priv);
-       priv->spi = spi;
-
-       spi->bits_per_word = 16;
-       spi->max_speed_hz = 24000000;
-
-       ret = spi_setup(spi);
-       if (ret < 0) {
-               dev_err(&priv->spi->dev, "spi_setup failed");
-               goto err_free;
-       }
-
-       ret = gpio_request(p54spi_gpio_power, "p54spi power");
-       if (ret < 0) {
-               dev_err(&priv->spi->dev, "power GPIO request failed: %d", ret);
-               goto err_free;
-       }
-
-       ret = gpio_request(p54spi_gpio_irq, "p54spi irq");
-       if (ret < 0) {
-               dev_err(&priv->spi->dev, "irq GPIO request failed: %d", ret);
-               goto err_free_gpio_power;
-       }
-
-       gpio_direction_output(p54spi_gpio_power, 0);
-       gpio_direction_input(p54spi_gpio_irq);
-
-       ret = request_irq(gpio_to_irq(p54spi_gpio_irq),
-                         p54spi_interrupt, 0, "p54spi",
-                         priv->spi);
-       if (ret < 0) {
-               dev_err(&priv->spi->dev, "request_irq() failed");
-               goto err_free_gpio_irq;
-       }
-
-       irq_set_irq_type(gpio_to_irq(p54spi_gpio_irq), IRQ_TYPE_EDGE_RISING);
-
-       disable_irq(gpio_to_irq(p54spi_gpio_irq));
-
-       INIT_WORK(&priv->work, p54spi_work);
-       init_completion(&priv->fw_comp);
-       INIT_LIST_HEAD(&priv->tx_pending);
-       mutex_init(&priv->mutex);
-       spin_lock_init(&priv->tx_lock);
-       SET_IEEE80211_DEV(hw, &spi->dev);
-       priv->common.open = p54spi_op_start;
-       priv->common.stop = p54spi_op_stop;
-       priv->common.tx = p54spi_op_tx;
-
-       ret = p54spi_request_firmware(hw);
-       if (ret < 0)
-               goto err_free_common;
-
-       ret = p54spi_request_eeprom(hw);
-       if (ret)
-               goto err_free_common;
-
-       ret = p54_register_common(hw, &priv->spi->dev);
-       if (ret)
-               goto err_free_common;
-
-       return 0;
-
-err_free_common:
-       free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
-err_free_gpio_irq:
-       gpio_free(p54spi_gpio_irq);
-err_free_gpio_power:
-       gpio_free(p54spi_gpio_power);
-err_free:
-       p54_free_common(priv->hw);
-       return ret;
-}
-
-static int p54spi_remove(struct spi_device *spi)
-{
-       struct p54s_priv *priv = spi_get_drvdata(spi);
-
-       p54_unregister_common(priv->hw);
-
-       free_irq(gpio_to_irq(p54spi_gpio_irq), spi);
-
-       gpio_free(p54spi_gpio_power);
-       gpio_free(p54spi_gpio_irq);
-       release_firmware(priv->firmware);
-
-       mutex_destroy(&priv->mutex);
-
-       p54_free_common(priv->hw);
-
-       return 0;
-}
-
-
-static struct spi_driver p54spi_driver = {
-       .driver = {
-               .name           = "p54spi",
-       },
-
-       .probe          = p54spi_probe,
-       .remove         = p54spi_remove,
-};
-
-module_spi_driver(p54spi_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
-MODULE_ALIAS("spi:cx3110x");
-MODULE_ALIAS("spi:p54spi");
-MODULE_ALIAS("spi:stlc45xx");
diff --git a/drivers/net/wireless/p54/p54spi.h b/drivers/net/wireless/p54/p54spi.h
deleted file mode 100644 (file)
index dfaa62a..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2008 Christian Lamparter <chunkeey@web.de>
- *
- * This driver is a port from stlc45xx:
- *     Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#ifndef P54SPI_H
-#define P54SPI_H
-
-#include <linux/mutex.h>
-#include <linux/list.h>
-#include <net/mac80211.h>
-
-#include "p54.h"
-
-/* Bit 15 is read/write bit; ON = READ, OFF = WRITE */
-#define SPI_ADRS_READ_BIT_15           0x8000
-
-#define SPI_ADRS_ARM_INTERRUPTS                0x00
-#define SPI_ADRS_ARM_INT_EN            0x04
-
-#define SPI_ADRS_HOST_INTERRUPTS       0x08
-#define SPI_ADRS_HOST_INT_EN           0x0c
-#define SPI_ADRS_HOST_INT_ACK          0x10
-
-#define SPI_ADRS_GEN_PURP_1            0x14
-#define SPI_ADRS_GEN_PURP_2            0x18
-
-#define SPI_ADRS_DEV_CTRL_STAT         0x26    /* high word */
-
-#define SPI_ADRS_DMA_DATA              0x28
-
-#define SPI_ADRS_DMA_WRITE_CTRL                0x2c
-#define SPI_ADRS_DMA_WRITE_LEN         0x2e
-#define SPI_ADRS_DMA_WRITE_BASE                0x30
-
-#define SPI_ADRS_DMA_READ_CTRL         0x34
-#define SPI_ADRS_DMA_READ_LEN          0x36
-#define SPI_ADRS_DMA_READ_BASE         0x38
-
-#define SPI_CTRL_STAT_HOST_OVERRIDE    0x8000
-#define SPI_CTRL_STAT_START_HALTED     0x4000
-#define SPI_CTRL_STAT_RAM_BOOT         0x2000
-#define SPI_CTRL_STAT_HOST_RESET       0x1000
-#define SPI_CTRL_STAT_HOST_CPU_EN      0x0800
-
-#define SPI_DMA_WRITE_CTRL_ENABLE      0x0001
-#define SPI_DMA_READ_CTRL_ENABLE       0x0001
-#define HOST_ALLOWED                   (1 << 7)
-
-#define SPI_TIMEOUT                    100         /* msec */
-
-#define SPI_MAX_TX_PACKETS             32
-
-#define SPI_MAX_PACKET_SIZE            32767
-
-#define SPI_TARGET_INT_WAKEUP          0x00000001
-#define SPI_TARGET_INT_SLEEP           0x00000002
-#define SPI_TARGET_INT_RDDONE          0x00000004
-
-#define SPI_TARGET_INT_CTS             0x00004000
-#define SPI_TARGET_INT_DR              0x00008000
-
-#define SPI_HOST_INT_READY             0x00000001
-#define SPI_HOST_INT_WR_READY          0x00000002
-#define SPI_HOST_INT_SW_UPDATE         0x00000004
-#define SPI_HOST_INT_UPDATE            0x10000000
-
-/* clear to send */
-#define SPI_HOST_INT_CR                        0x00004000
-
-/* data ready */
-#define SPI_HOST_INT_DR                        0x00008000
-
-#define SPI_HOST_INTS_DEFAULT                                              \
-       (SPI_HOST_INT_READY | SPI_HOST_INT_UPDATE | SPI_HOST_INT_SW_UPDATE)
-
-#define TARGET_BOOT_SLEEP 50
-
-struct p54s_dma_regs {
-       __le16 cmd;
-       __le16 len;
-       __le32 addr;
-} __packed;
-
-struct p54s_tx_info {
-       struct list_head tx_list;
-};
-
-struct p54s_priv {
-       /* p54_common has to be the first entry */
-       struct p54_common common;
-       struct ieee80211_hw *hw;
-       struct spi_device *spi;
-
-       struct work_struct work;
-
-       struct mutex mutex;
-       struct completion fw_comp;
-
-       spinlock_t tx_lock;
-
-       /* protected by tx_lock */
-       struct list_head tx_pending;
-
-       enum fw_state fw_state;
-       const struct firmware *firmware;
-};
-
-#endif /* P54SPI_H */
diff --git a/drivers/net/wireless/p54/p54spi_eeprom.h b/drivers/net/wireless/p54/p54spi_eeprom.h
deleted file mode 100644 (file)
index 0b7bfb0..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- * Copyright (C) 2003 Conexant Americas Inc. All Rights Reserved.
- * Copyright (C) 2004, 2005, 2006 Nokia Corporation
- * Copyright 2008 Johannes Berg <johannes@sipsolutions.net>
- * Copyright 2008 Christian Lamparter <chunkeey@web.de>
- *
- * based on:
- *  - cx3110x's pda.h from Nokia
- *  - cx3110-transfer.log by Johannes Berg
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#ifndef P54SPI_EEPROM_H
-#define P54SPI_EEPROM_H
-
-static unsigned char p54spi_eeprom[] = {
-
-/* struct eeprom_pda_wrap */
-0x47, 0x4d, 0x55, 0xaa,        /* magic */
-0x00, 0x00,            /* pad */
-0x00, 0x00,            /* eeprom_pda_data_wrap length */
-0x00, 0x00, 0x00, 0x00,        /* arm opcode */
-
-/* bogus MAC address */
-0x04, 0x00, 0x01, 0x01,                /* PDR_MAC_ADDRESS */
-       0x00, 0x02, 0xee, 0xc0, 0xff, 0xee,
-
-/* struct bootrec_exp_if */
-0x06, 0x00, 0x01, 0x10,                /* PDR_INTERFACE_LIST */
-       0x00, 0x00,                     /* role */
-       0x0f, 0x00,                     /* if_id */
-       0x85, 0x00,                     /* variant = Longbow RF, 2GHz */
-       0x01, 0x00,                     /* btm_compat */
-       0x1f, 0x00,                     /* top_compat */
-
-0x03, 0x00, 0x02, 0x10,                /* PDR_HARDWARE_PLATFORM_COMPONENT_ID */
-       0x03, 0x20, 0x00, 0x43,
-
-/* struct pda_country[6] */
-0x0d, 0x00, 0x07, 0x10,                /* PDR_COUNTRY_LIST */
-       0x10, 0x00, 0x00, 0x00,
-       0x20, 0x00, 0x00, 0x00,
-       0x30, 0x00, 0x00, 0x00,
-       0x31, 0x00, 0x00, 0x00,
-       0x32, 0x00, 0x00, 0x00,
-       0x40, 0x00, 0x00, 0x00,
-
-/* struct pda_country */
-0x03, 0x00, 0x08, 0x10,                /* PDR_DEFAULT_COUNTRY */
-       0x30, 0x00, 0x00, 0x00,         /* ETSI */
-
-0x03, 0x00, 0x00, 0x11,                /* PDR_ANTENNA_GAIN */
-       0x08, 0x08, 0x08, 0x08,
-
-0x0a, 0x00, 0xff, 0xca,                /* PDR_RSSI_LINEAR_APPROXIMATION_CUSTOMV2 */
-       0x01, 0x00, 0x0a, 0x00,
-       0x00, 0x00, 0x0a, 0x00,
-               0x85, 0x09, 0x0a, 0x01, 0x72, 0xfe, 0x1a, 0x00, 0x00, 0x00,
-
-/* struct pda_custom_wrapper */
-0x10, 0x06, 0x5d, 0xb0,                /* PDR_PRISM_PA_CAL_CURVE_DATA_CUSTOM */
-       0x0d, 0x00, 0xee, 0x00,         /* 13 entries, 238 bytes per entry */
-       0x00, 0x00, 0x16, 0x0c,         /* no offset, 3094 total len */
-               /* 2412 MHz */
-               0x6c, 0x09,
-                       0x10, 0x01, 0x9a, 0x84,
-                               0xaa, 0x8a, 0xaa, 0x8a, 0xaa, 0x8a, 0xaa, 0x8a,
-                               0x3c, 0xb6, 0x3c, 0xb6, 0x3c, 0xb6, 0x3c, 0xb6,
-                               0x3c, 0xb6, 0x3c, 0xb6, 0x3c, 0xb6, 0x3c, 0xb6,
-                       0xf0, 0x00, 0x94, 0x6c,
-                               0x99, 0x82, 0x99, 0x82, 0x99, 0x82, 0x99, 0x82,
-                               0x2b, 0xae, 0x2b, 0xae, 0x2b, 0xae, 0x2b, 0xae,
-                               0x2b, 0xae, 0x2b, 0xae, 0x2b, 0xae, 0x2b, 0xae,
-                       0xd0, 0x00, 0xaa, 0x5a,
-                               0x88, 0x7a, 0x88, 0x7a, 0x88, 0x7a, 0x88, 0x7a,
-                               0x1a, 0xa6, 0x1a, 0xa6, 0x1a, 0xa6, 0x1a, 0xa6,
-                               0x1a, 0xa6, 0x1a, 0xa6, 0x1a, 0xa6, 0x1a, 0xa6,
-                       0xa0, 0x00, 0xf3, 0x47,
-                               0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e, 0x6e,
-                               0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a,
-                               0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a, 0x00, 0x9a,
-                       0x50, 0x00, 0x59, 0x36,
-                               0x43, 0x5a, 0x43, 0x5a, 0x43, 0x5a, 0x43, 0x5a,
-                               0xd5, 0x85, 0xd5, 0x85, 0xd5, 0x85, 0xd5, 0x85,
-                               0xd5, 0x85, 0xd5, 0x85, 0xd5, 0x85, 0xd5, 0x85,
-                       0x00, 0x00, 0xe4, 0x2d,
-                               0x18, 0x46, 0x18, 0x46, 0x18, 0x46, 0x18, 0x46,
-                               0xaa, 0x71, 0xaa, 0x71, 0xaa, 0x71, 0xaa, 0x71,
-                               0xaa, 0x71, 0xaa, 0x71, 0xaa, 0x71, 0xaa, 0x71,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2417 MHz */
-               0x71, 0x09,
-                       0x10, 0x01, 0xb9, 0x83,
-                               0x7d, 0x8a, 0x7d, 0x8a, 0x7d, 0x8a, 0x7d, 0x8a,
-                               0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6,
-                               0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6,
-                       0xf0, 0x00, 0x2e, 0x6c,
-                               0x68, 0x82, 0x68, 0x82, 0x68, 0x82, 0x68, 0x82,
-                               0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad,
-                               0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad,
-                       0xd0, 0x00, 0x8d, 0x5a,
-                               0x52, 0x7a, 0x52, 0x7a, 0x52, 0x7a, 0x52, 0x7a,
-                               0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5,
-                               0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5,
-                       0xa0, 0x00, 0x0a, 0x48,
-                               0x32, 0x6e, 0x32, 0x6e, 0x32, 0x6e, 0x32, 0x6e,
-                               0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99,
-                               0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99,
-                       0x50, 0x00, 0x7c, 0x36,
-                               0xfc, 0x59, 0xfc, 0x59, 0xfc, 0x59, 0xfc, 0x59,
-                               0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85,
-                               0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85,
-                       0x00, 0x00, 0xf5, 0x2d,
-                               0xc6, 0x45, 0xc6, 0x45, 0xc6, 0x45, 0xc6, 0x45,
-                               0x58, 0x71, 0x58, 0x71, 0x58, 0x71, 0x58, 0x71,
-                               0x58, 0x71, 0x58, 0x71, 0x58, 0x71, 0x58, 0x71,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2422 MHz */
-               0x76, 0x09,
-                       0x10, 0x01, 0xb9, 0x83,
-                               0x7d, 0x8a, 0x7d, 0x8a, 0x7d, 0x8a, 0x7d, 0x8a,
-                               0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6,
-                               0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6, 0x0f, 0xb6,
-                       0xf0, 0x00, 0x2e, 0x6c,
-                               0x68, 0x82, 0x68, 0x82, 0x68, 0x82, 0x68, 0x82,
-                               0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad,
-                               0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad, 0xfa, 0xad,
-                       0xd0, 0x00, 0x8d, 0x5a,
-                               0x52, 0x7a, 0x52, 0x7a, 0x52, 0x7a, 0x52, 0x7a,
-                               0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5,
-                               0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5, 0xe4, 0xa5,
-                       0xa0, 0x00, 0x0a, 0x48,
-                               0x32, 0x6e, 0x32, 0x6e, 0x32, 0x6e, 0x32, 0x6e,
-                               0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99,
-                               0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99, 0xc4, 0x99,
-                       0x50, 0x00, 0x7c, 0x36,
-                               0xfc, 0x59, 0xfc, 0x59, 0xfc, 0x59, 0xfc, 0x59,
-                               0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85,
-                               0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85, 0x8e, 0x85,
-                       0x00, 0x00, 0xf5, 0x2d,
-                               0xc6, 0x45, 0xc6, 0x45, 0xc6, 0x45, 0xc6, 0x45,
-                               0x58, 0x71, 0x58, 0x71, 0x58, 0x71, 0x58, 0x71,
-                               0x58, 0x71, 0x58, 0x71, 0x58, 0x71, 0x58, 0x71,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2427 MHz */
-               0x7b, 0x09,
-                       0x10, 0x01, 0x48, 0x83,
-                               0x67, 0x8a, 0x67, 0x8a, 0x67, 0x8a, 0x67, 0x8a,
-                               0xf9, 0xb5, 0xf9, 0xb5, 0xf9, 0xb5, 0xf9, 0xb5,
-                               0xf9, 0xb5, 0xf9, 0xb5, 0xf9, 0xb5, 0xf9, 0xb5,
-                       0xf0, 0x00, 0xfb, 0x6b,
-                               0x50, 0x82, 0x50, 0x82, 0x50, 0x82, 0x50, 0x82,
-                               0xe2, 0xad, 0xe2, 0xad, 0xe2, 0xad, 0xe2, 0xad,
-                               0xe2, 0xad, 0xe2, 0xad, 0xe2, 0xad, 0xe2, 0xad,
-                       0xd0, 0x00, 0x7e, 0x5a,
-                               0x38, 0x7a, 0x38, 0x7a, 0x38, 0x7a, 0x38, 0x7a,
-                               0xca, 0xa5, 0xca, 0xa5, 0xca, 0xa5, 0xca, 0xa5,
-                               0xca, 0xa5, 0xca, 0xa5, 0xca, 0xa5, 0xca, 0xa5,
-                       0xa0, 0x00, 0x15, 0x48,
-                               0x14, 0x6e, 0x14, 0x6e, 0x14, 0x6e, 0x14, 0x6e,
-                               0xa6, 0x99, 0xa6, 0x99, 0xa6, 0x99, 0xa6, 0x99,
-                               0xa6, 0x99, 0xa6, 0x99, 0xa6, 0x99, 0xa6, 0x99,
-                       0x50, 0x00, 0x8e, 0x36,
-                               0xd9, 0x59, 0xd9, 0x59, 0xd9, 0x59, 0xd9, 0x59,
-                               0x6b, 0x85, 0x6b, 0x85, 0x6b, 0x85, 0x6b, 0x85,
-                               0x6b, 0x85, 0x6b, 0x85, 0x6b, 0x85, 0x6b, 0x85,
-                       0x00, 0x00, 0xfe, 0x2d,
-                               0x9d, 0x45, 0x9d, 0x45, 0x9d, 0x45, 0x9d, 0x45,
-                               0x2f, 0x71, 0x2f, 0x71, 0x2f, 0x71, 0x2f, 0x71,
-                               0x2f, 0x71, 0x2f, 0x71, 0x2f, 0x71, 0x2f, 0x71,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2432 MHz */
-               0x80, 0x09,
-                       0x10, 0x01, 0xd7, 0x82,
-                               0x51, 0x8a, 0x51, 0x8a, 0x51, 0x8a, 0x51, 0x8a,
-                               0xe3, 0xb5, 0xe3, 0xb5, 0xe3, 0xb5, 0xe3, 0xb5,
-                               0xe3, 0xb5, 0xe3, 0xb5, 0xe3, 0xb5, 0xe3, 0xb5,
-                       0xf0, 0x00, 0xc8, 0x6b,
-                               0x37, 0x82, 0x37, 0x82, 0x37, 0x82, 0x37, 0x82,
-                               0xc9, 0xad, 0xc9, 0xad, 0xc9, 0xad, 0xc9, 0xad,
-                               0xc9, 0xad, 0xc9, 0xad, 0xc9, 0xad, 0xc9, 0xad,
-                       0xd0, 0x00, 0x6f, 0x5a,
-                               0x1d, 0x7a, 0x1d, 0x7a, 0x1d, 0x7a, 0x1d, 0x7a,
-                               0xaf, 0xa5, 0xaf, 0xa5, 0xaf, 0xa5, 0xaf, 0xa5,
-                               0xaf, 0xa5, 0xaf, 0xa5, 0xaf, 0xa5, 0xaf, 0xa5,
-                       0xa0, 0x00, 0x20, 0x48,
-                               0xf6, 0x6d, 0xf6, 0x6d, 0xf6, 0x6d, 0xf6, 0x6d,
-                               0x88, 0x99, 0x88, 0x99, 0x88, 0x99, 0x88, 0x99,
-                               0x88, 0x99, 0x88, 0x99, 0x88, 0x99, 0x88, 0x99,
-                       0x50, 0x00, 0x9f, 0x36,
-                               0xb5, 0x59, 0xb5, 0x59, 0xb5, 0x59, 0xb5, 0x59,
-                               0x47, 0x85, 0x47, 0x85, 0x47, 0x85, 0x47, 0x85,
-                               0x47, 0x85, 0x47, 0x85, 0x47, 0x85, 0x47, 0x85,
-                       0x00, 0x00, 0x06, 0x2e,
-                               0x74, 0x45, 0x74, 0x45, 0x74, 0x45, 0x74, 0x45,
-                               0x06, 0x71, 0x06, 0x71, 0x06, 0x71, 0x06, 0x71,
-                               0x06, 0x71, 0x06, 0x71, 0x06, 0x71, 0x06, 0x71,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2437 MHz */
-               0x85, 0x09,
-                       0x10, 0x01, 0x67, 0x82,
-                               0x3a, 0x8a, 0x3a, 0x8a, 0x3a, 0x8a, 0x3a, 0x8a,
-                               0xcc, 0xb5, 0xcc, 0xb5, 0xcc, 0xb5, 0xcc, 0xb5,
-                               0xcc, 0xb5, 0xcc, 0xb5, 0xcc, 0xb5, 0xcc, 0xb5,
-                       0xf0, 0x00, 0x95, 0x6b,
-                               0x1f, 0x82, 0x1f, 0x82, 0x1f, 0x82, 0x1f, 0x82,
-                               0xb1, 0xad, 0xb1, 0xad, 0xb1, 0xad, 0xb1, 0xad,
-                               0xb1, 0xad, 0xb1, 0xad, 0xb1, 0xad, 0xb1, 0xad,
-                       0xd0, 0x00, 0x61, 0x5a,
-                               0x02, 0x7a, 0x02, 0x7a, 0x02, 0x7a, 0x02, 0x7a,
-                               0x94, 0xa5, 0x94, 0xa5, 0x94, 0xa5, 0x94, 0xa5,
-                               0x94, 0xa5, 0x94, 0xa5, 0x94, 0xa5, 0x94, 0xa5,
-                       0xa0, 0x00, 0x2c, 0x48,
-                               0xd8, 0x6d, 0xd8, 0x6d, 0xd8, 0x6d, 0xd8, 0x6d,
-                               0x6a, 0x99, 0x6a, 0x99, 0x6a, 0x99, 0x6a, 0x99,
-                               0x6a, 0x99, 0x6a, 0x99, 0x6a, 0x99, 0x6a, 0x99,
-                       0x50, 0x00, 0xb1, 0x36,
-                               0x92, 0x59, 0x92, 0x59, 0x92, 0x59, 0x92, 0x59,
-                               0x24, 0x85, 0x24, 0x85, 0x24, 0x85, 0x24, 0x85,
-                               0x24, 0x85, 0x24, 0x85, 0x24, 0x85, 0x24, 0x85,
-                       0x00, 0x00, 0x0f, 0x2e,
-                               0x4b, 0x45, 0x4b, 0x45, 0x4b, 0x45, 0x4b, 0x45,
-                               0xdd, 0x70, 0xdd, 0x70, 0xdd, 0x70, 0xdd, 0x70,
-                               0xdd, 0x70, 0xdd, 0x70, 0xdd, 0x70, 0xdd, 0x70,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2442 MHz */
-               0x8a, 0x09,
-                       0x10, 0x01, 0xf6, 0x81,
-                               0x24, 0x8a, 0x24, 0x8a, 0x24, 0x8a, 0x24, 0x8a,
-                               0xb6, 0xb5, 0xb6, 0xb5, 0xb6, 0xb5, 0xb6, 0xb5,
-                               0xb6, 0xb5, 0xb6, 0xb5, 0xb6, 0xb5, 0xb6, 0xb5,
-                       0xf0, 0x00, 0x62, 0x6b,
-                               0x06, 0x82, 0x06, 0x82, 0x06, 0x82, 0x06, 0x82,
-                               0x98, 0xad, 0x98, 0xad, 0x98, 0xad, 0x98, 0xad,
-                               0x98, 0xad, 0x98, 0xad, 0x98, 0xad, 0x98, 0xad,
-                       0xd0, 0x00, 0x52, 0x5a,
-                               0xe7, 0x79, 0xe7, 0x79, 0xe7, 0x79, 0xe7, 0x79,
-                               0x79, 0xa5, 0x79, 0xa5, 0x79, 0xa5, 0x79, 0xa5,
-                               0x79, 0xa5, 0x79, 0xa5, 0x79, 0xa5, 0x79, 0xa5,
-                       0xa0, 0x00, 0x37, 0x48,
-                               0xba, 0x6d, 0xba, 0x6d, 0xba, 0x6d, 0xba, 0x6d,
-                               0x4c, 0x99, 0x4c, 0x99, 0x4c, 0x99, 0x4c, 0x99,
-                               0x4c, 0x99, 0x4c, 0x99, 0x4c, 0x99, 0x4c, 0x99,
-                       0x50, 0x00, 0xc2, 0x36,
-                               0x6e, 0x59, 0x6e, 0x59, 0x6e, 0x59, 0x6e, 0x59,
-                               0x00, 0x85, 0x00, 0x85, 0x00, 0x85, 0x00, 0x85,
-                               0x00, 0x85, 0x00, 0x85, 0x00, 0x85, 0x00, 0x85,
-                       0x00, 0x00, 0x17, 0x2e,
-                               0x22, 0x45, 0x22, 0x45, 0x22, 0x45, 0x22, 0x45,
-                               0xb4, 0x70, 0xb4, 0x70, 0xb4, 0x70, 0xb4, 0x70,
-                               0xb4, 0x70, 0xb4, 0x70, 0xb4, 0x70, 0xb4, 0x70,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2447 MHz */
-               0x8f, 0x09,
-                       0x10, 0x01, 0x75, 0x83,
-                               0x61, 0x8a, 0x61, 0x8a, 0x61, 0x8a, 0x61, 0x8a,
-                               0xf3, 0xb5, 0xf3, 0xb5, 0xf3, 0xb5, 0xf3, 0xb5,
-                               0xf3, 0xb5, 0xf3, 0xb5, 0xf3, 0xb5, 0xf3, 0xb5,
-                       0xf0, 0x00, 0x4b, 0x6c,
-                               0x3f, 0x82, 0x3f, 0x82, 0x3f, 0x82, 0x3f, 0x82,
-                               0xd1, 0xad, 0xd1, 0xad, 0xd1, 0xad, 0xd1, 0xad,
-                               0xd1, 0xad, 0xd1, 0xad, 0xd1, 0xad, 0xd1, 0xad,
-                       0xd0, 0x00, 0xda, 0x5a,
-                               0x1c, 0x7a, 0x1c, 0x7a, 0x1c, 0x7a, 0x1c, 0x7a,
-                               0xae, 0xa5, 0xae, 0xa5, 0xae, 0xa5, 0xae, 0xa5,
-                               0xae, 0xa5, 0xae, 0xa5, 0xae, 0xa5, 0xae, 0xa5,
-                       0xa0, 0x00, 0x6d, 0x48,
-                               0xe9, 0x6d, 0xe9, 0x6d, 0xe9, 0x6d, 0xe9, 0x6d,
-                               0x7b, 0x99, 0x7b, 0x99, 0x7b, 0x99, 0x7b, 0x99,
-                               0x7b, 0x99, 0x7b, 0x99, 0x7b, 0x99, 0x7b, 0x99,
-                       0x50, 0x00, 0xc6, 0x36,
-                               0x92, 0x59, 0x92, 0x59, 0x92, 0x59, 0x92, 0x59,
-                               0x24, 0x85, 0x24, 0x85, 0x24, 0x85, 0x24, 0x85,
-                               0x24, 0x85, 0x24, 0x85, 0x24, 0x85, 0x24, 0x85,
-                       0x00, 0x00, 0x15, 0x2e,
-                               0x3c, 0x45, 0x3c, 0x45, 0x3c, 0x45, 0x3c, 0x45,
-                               0xce, 0x70, 0xce, 0x70, 0xce, 0x70, 0xce, 0x70,
-                               0xce, 0x70, 0xce, 0x70, 0xce, 0x70, 0xce, 0x70,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2452 MHz */
-               0x94, 0x09,
-                       0x10, 0x01, 0xf4, 0x84,
-                               0x9e, 0x8a, 0x9e, 0x8a, 0x9e, 0x8a, 0x9e, 0x8a,
-                               0x30, 0xb6, 0x30, 0xb6, 0x30, 0xb6, 0x30, 0xb6,
-                               0x30, 0xb6, 0x30, 0xb6, 0x30, 0xb6, 0x30, 0xb6,
-                       0xf0, 0x00, 0x34, 0x6d,
-                               0x77, 0x82, 0x77, 0x82, 0x77, 0x82, 0x77, 0x82,
-                               0x09, 0xae, 0x09, 0xae, 0x09, 0xae, 0x09, 0xae,
-                               0x09, 0xae, 0x09, 0xae, 0x09, 0xae, 0x09, 0xae,
-                       0xd0, 0x00, 0x62, 0x5b,
-                               0x50, 0x7a, 0x50, 0x7a, 0x50, 0x7a, 0x50, 0x7a,
-                               0xe2, 0xa5, 0xe2, 0xa5, 0xe2, 0xa5, 0xe2, 0xa5,
-                               0xe2, 0xa5, 0xe2, 0xa5, 0xe2, 0xa5, 0xe2, 0xa5,
-                       0xa0, 0x00, 0xa2, 0x48,
-                               0x17, 0x6e, 0x17, 0x6e, 0x17, 0x6e, 0x17, 0x6e,
-                               0xa9, 0x99, 0xa9, 0x99, 0xa9, 0x99, 0xa9, 0x99,
-                               0xa9, 0x99, 0xa9, 0x99, 0xa9, 0x99, 0xa9, 0x99,
-                       0x50, 0x00, 0xc9, 0x36,
-                               0xb7, 0x59, 0xb7, 0x59, 0xb7, 0x59, 0xb7, 0x59,
-                               0x49, 0x85, 0x49, 0x85, 0x49, 0x85, 0x49, 0x85,
-                               0x49, 0x85, 0x49, 0x85, 0x49, 0x85, 0x49, 0x85,
-                       0x00, 0x00, 0x12, 0x2e,
-                               0x57, 0x45, 0x57, 0x45, 0x57, 0x45, 0x57, 0x45,
-                               0xe9, 0x70, 0xe9, 0x70, 0xe9, 0x70, 0xe9, 0x70,
-                               0xe9, 0x70, 0xe9, 0x70, 0xe9, 0x70, 0xe9, 0x70,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2452 MHz */
-               0x99, 0x09,
-                       0x10, 0x01, 0x74, 0x86,
-                               0xdb, 0x8a, 0xdb, 0x8a, 0xdb, 0x8a, 0xdb, 0x8a,
-                               0x6d, 0xb6, 0x6d, 0xb6, 0x6d, 0xb6, 0x6d, 0xb6,
-                               0x6d, 0xb6, 0x6d, 0xb6, 0x6d, 0xb6, 0x6d, 0xb6,
-                       0xf0, 0x00, 0x1e, 0x6e,
-                               0xb0, 0x82, 0xb0, 0x82, 0xb0, 0x82, 0xb0, 0x82,
-                               0x42, 0xae, 0x42, 0xae, 0x42, 0xae, 0x42, 0xae,
-                               0x42, 0xae, 0x42, 0xae, 0x42, 0xae, 0x42, 0xae,
-                       0xd0, 0x00, 0xeb, 0x5b,
-                               0x85, 0x7a, 0x85, 0x7a, 0x85, 0x7a, 0x85, 0x7a,
-                               0x17, 0xa6, 0x17, 0xa6, 0x17, 0xa6, 0x17, 0xa6,
-                               0x17, 0xa6, 0x17, 0xa6, 0x17, 0xa6, 0x17, 0xa6,
-                       0xa0, 0x00, 0xd8, 0x48,
-                               0x46, 0x6e, 0x46, 0x6e, 0x46, 0x6e, 0x46, 0x6e,
-                               0xd8, 0x99, 0xd8, 0x99, 0xd8, 0x99, 0xd8, 0x99,
-                               0xd8, 0x99, 0xd8, 0x99, 0xd8, 0x99, 0xd8, 0x99,
-                       0x50, 0x00, 0xcd, 0x36,
-                               0xdb, 0x59, 0xdb, 0x59, 0xdb, 0x59, 0xdb, 0x59,
-                               0x6d, 0x85, 0x6d, 0x85, 0x6d, 0x85, 0x6d, 0x85,
-                               0x6d, 0x85, 0x6d, 0x85, 0x6d, 0x85, 0x6d, 0x85,
-                       0x00, 0x00, 0x10, 0x2e,
-                               0x71, 0x45, 0x71, 0x45, 0x71, 0x45, 0x71, 0x45,
-                               0x03, 0x71, 0x03, 0x71, 0x03, 0x71, 0x03, 0x71,
-                               0x03, 0x71, 0x03, 0x71, 0x03, 0x71, 0x03, 0x71,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2557 MHz */
-               0x9e, 0x09,
-                       0x10, 0x01, 0xf3, 0x87,
-                               0x17, 0x8b, 0x17, 0x8b, 0x17, 0x8b, 0x17, 0x8b,
-                               0xa9, 0xb6, 0xa9, 0xb6, 0xa9, 0xb6, 0xa9, 0xb6,
-                               0xa9, 0xb6, 0xa9, 0xb6, 0xa9, 0xb6, 0xa9, 0xb6,
-                       0xf0, 0x00, 0x07, 0x6f,
-                               0xe9, 0x82, 0xe9, 0x82, 0xe9, 0x82, 0xe9, 0x82,
-                               0x7b, 0xae, 0x7b, 0xae, 0x7b, 0xae, 0x7b, 0xae,
-                               0x7b, 0xae, 0x7b, 0xae, 0x7b, 0xae, 0x7b, 0xae,
-                       0xd0, 0x00, 0x73, 0x5c,
-                               0xba, 0x7a, 0xba, 0x7a, 0xba, 0x7a, 0xba, 0x7a,
-                               0x4c, 0xa6, 0x4c, 0xa6, 0x4c, 0xa6, 0x4c, 0xa6,
-                               0x4c, 0xa6, 0x4c, 0xa6, 0x4c, 0xa6, 0x4c, 0xa6,
-                       0xa0, 0x00, 0x0d, 0x49,
-                               0x74, 0x6e, 0x74, 0x6e, 0x74, 0x6e, 0x74, 0x6e,
-                               0x06, 0x9a, 0x06, 0x9a, 0x06, 0x9a, 0x06, 0x9a,
-                               0x06, 0x9a, 0x06, 0x9a, 0x06, 0x9a, 0x06, 0x9a,
-                       0x50, 0x00, 0xd1, 0x36,
-                               0xff, 0x59, 0xff, 0x59, 0xff, 0x59, 0xff, 0x59,
-                               0x91, 0x85, 0x91, 0x85, 0x91, 0x85, 0x91, 0x85,
-                               0x91, 0x85, 0x91, 0x85, 0x91, 0x85, 0x91, 0x85,
-                       0x00, 0x00, 0x0e, 0x2e,
-                               0x8b, 0x45, 0x8b, 0x45, 0x8b, 0x45, 0x8b, 0x45,
-                               0x1d, 0x71, 0x1d, 0x71, 0x1d, 0x71, 0x1d, 0x71,
-                               0x1d, 0x71, 0x1d, 0x71, 0x1d, 0x71, 0x1d, 0x71,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2562 MHz */
-               0xa3, 0x09,
-                       0x10, 0x01, 0x72, 0x89,
-                               0x54, 0x8b, 0x54, 0x8b, 0x54, 0x8b, 0x54, 0x8b,
-                               0xe6, 0xb6, 0xe6, 0xb6, 0xe6, 0xb6, 0xe6, 0xb6,
-                               0xe6, 0xb6, 0xe6, 0xb6, 0xe6, 0xb6, 0xe6, 0xb6,
-                       0xf0, 0x00, 0xf0, 0x6f,
-                               0x21, 0x83, 0x21, 0x83, 0x21, 0x83, 0x21, 0x83,
-                               0xb3, 0xae, 0xb3, 0xae, 0xb3, 0xae, 0xb3, 0xae,
-                               0xb3, 0xae, 0xb3, 0xae, 0xb3, 0xae, 0xb3, 0xae,
-                       0xd0, 0x00, 0xfb, 0x5c,
-                               0xee, 0x7a, 0xee, 0x7a, 0xee, 0x7a, 0xee, 0x7a,
-                               0x80, 0xa6, 0x80, 0xa6, 0x80, 0xa6, 0x80, 0xa6,
-                               0x80, 0xa6, 0x80, 0xa6, 0x80, 0xa6, 0x80, 0xa6,
-                       0xa0, 0x00, 0x43, 0x49,
-                               0xa3, 0x6e, 0xa3, 0x6e, 0xa3, 0x6e, 0xa3, 0x6e,
-                               0x35, 0x9a, 0x35, 0x9a, 0x35, 0x9a, 0x35, 0x9a,
-                               0x35, 0x9a, 0x35, 0x9a, 0x35, 0x9a, 0x35, 0x9a,
-                       0x50, 0x00, 0xd4, 0x36,
-                               0x24, 0x5a, 0x24, 0x5a, 0x24, 0x5a, 0x24, 0x5a,
-                               0xb6, 0x85, 0xb6, 0x85, 0xb6, 0x85, 0xb6, 0x85,
-                               0xb6, 0x85, 0xb6, 0x85, 0xb6, 0x85, 0xb6, 0x85,
-                       0x00, 0x00, 0x0b, 0x2e,
-                               0xa6, 0x45, 0xa6, 0x45, 0xa6, 0x45, 0xa6, 0x45,
-                               0x38, 0x71, 0x38, 0x71, 0x38, 0x71, 0x38, 0x71,
-                               0x38, 0x71, 0x38, 0x71, 0x38, 0x71, 0x38, 0x71,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-               /* 2572 MHz */
-               0xa8, 0x09,
-                       0x10, 0x01, 0xf1, 0x8a,
-                               0x91, 0x8b, 0x91, 0x8b, 0x91, 0x8b, 0x91, 0x8b,
-                               0x23, 0xb7, 0x23, 0xb7, 0x23, 0xb7, 0x23, 0xb7,
-                               0x23, 0xb7, 0x23, 0xb7, 0x23, 0xb7, 0x23, 0xb7,
-                       0xf0, 0x00, 0xd9, 0x70,
-                               0x5a, 0x83, 0x5a, 0x83, 0x5a, 0x83, 0x5a, 0x83,
-                               0xec, 0xae, 0xec, 0xae, 0xec, 0xae, 0xec, 0xae,
-                               0xec, 0xae, 0xec, 0xae, 0xec, 0xae, 0xec, 0xae,
-                       0xd0, 0x00, 0x83, 0x5d,
-                               0x23, 0x7b, 0x23, 0x7b, 0x23, 0x7b, 0x23, 0x7b,
-                               0xb5, 0xa6, 0xb5, 0xa6, 0xb5, 0xa6, 0xb5, 0xa6,
-                               0xb5, 0xa6, 0xb5, 0xa6, 0xb5, 0xa6, 0xb5, 0xa6,
-                       0xa0, 0x00, 0x78, 0x49,
-                               0xd1, 0x6e, 0xd1, 0x6e, 0xd1, 0x6e, 0xd1, 0x6e,
-                               0x63, 0x9a, 0x63, 0x9a, 0x63, 0x9a, 0x63, 0x9a,
-                               0x63, 0x9a, 0x63, 0x9a, 0x63, 0x9a, 0x63, 0x9a,
-                       0x50, 0x00, 0xd8, 0x36,
-                               0x48, 0x5a, 0x48, 0x5a, 0x48, 0x5a, 0x48, 0x5a,
-                               0xda, 0x85, 0xda, 0x85, 0xda, 0x85, 0xda, 0x85,
-                               0xda, 0x85, 0xda, 0x85, 0xda, 0x85, 0xda, 0x85,
-                       0x00, 0x00, 0x09, 0x2e,
-                               0xc0, 0x45, 0xc0, 0x45, 0xc0, 0x45, 0xc0, 0x45,
-                               0x52, 0x71, 0x52, 0x71, 0x52, 0x71, 0x52, 0x71,
-                               0x52, 0x71, 0x52, 0x71, 0x52, 0x71, 0x52, 0x71,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x80, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-                       0x00, 0x00, 0x00, 0x00,
-                               0x00, 0x00, 0x00, 0x00, 0x06, 0x80, 0x80, 0x00,
-
-/*
- * Not really sure if this is actually the power_limit database,
- * it looks a bit "related" to PDR_PRISM_ZIF_TX_IQ_CALIBRATION
- */
-/* struct pda_custom_wrapper */
-0xae, 0x00, 0xef, 0xbe,      /* PDR_PRISM_PA_CAL_OUTPUT_POWER_LIMITS_CUSTOM */
-       0x0d, 0x00, 0x1a, 0x00,         /* 13 entries, 26 bytes per entry */
-       0x00, 0x00, 0x52, 0x01,         /* no offset, 338 bytes total */
-
-               /* 2412 MHz */
-               0x6c, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00, 0xe0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2417 MHz */
-               0x71, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2422 MHz */
-               0x76, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2427 MHz */
-               0x7b, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2432 MHz */
-               0x80, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2437 MHz */
-               0x85, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2442 MHz */
-               0x8a, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2447 MHz */
-               0x8f, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2452 MHz */
-               0x94, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2457 MHz */
-               0x99, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2462 MHz */
-               0x9e, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2467 MHz */
-               0xa3, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-               /* 2472 MHz */
-               0xa8, 0x09,
-                       0x10, 0x01, 0x10, 0x01, 0x10, 0x01, 0x10, 0x01,
-                       0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00, 0xf0, 0x00,
-                       0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00, 0xd0, 0x00,
-
-/* struct pda_iq_autocal_entry[13] */
-0x42, 0x00, 0x06, 0x19,                /* PDR_PRISM_ZIF_TX_IQ_CALIBRATION */
-       /* 2412 MHz */
-       0x6c, 0x09, 0x26, 0x00, 0xf8, 0xff, 0xf7, 0xff, 0xff, 0x00,
-       /* 2417 MHz */
-       0x71, 0x09, 0x26, 0x00, 0xf8, 0xff, 0xf7, 0xff, 0xff, 0x00,
-       /* 2422 MHz */
-       0x76, 0x09, 0x26, 0x00, 0xf8, 0xff, 0xf7, 0xff, 0xff, 0x00,
-       /* 2427 MHz */
-       0x7b, 0x09, 0x26, 0x00, 0xf8, 0xff, 0xf7, 0xff, 0xff, 0x00,
-       /* 2432 MHz */
-       0x80, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
-       /* 2437 MHz */
-       0x85, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
-       /* 2442 MHz */
-       0x8a, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
-       /* 2447 MHz */
-       0x8f, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
-       /* 2452 MHz */
-       0x94, 0x09, 0x25, 0x00, 0xf7, 0xff, 0xf7, 0xff, 0xff, 0x00,
-       /* 2457 MHz */
-       0x99, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
-       /* 2462 MHz */
-       0x9e, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
-       /* 2467 MHz */
-       0xa3, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
-       /* 2472 MHz */
-       0xa8, 0x09, 0x25, 0x00, 0xf5, 0xff, 0xf9, 0xff, 0x00, 0x01,
-
-0x02, 0x00, 0x00, 0x00,                /* PDR_END */
-       0xb6, 0x04,
-};
-
-#endif /* P54SPI_EEPROM_H */
-
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
deleted file mode 100644 (file)
index 043bd1c..0000000
+++ /dev/null
@@ -1,1149 +0,0 @@
-
-/*
- * Linux device driver for USB based Prism54
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- *
- * Based on the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/usb.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-#include <linux/delay.h>
-#include <linux/crc32.h>
-#include <linux/module.h>
-#include <net/mac80211.h>
-
-#include "p54.h"
-#include "lmac.h"
-#include "p54usb.h"
-
-MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>");
-MODULE_DESCRIPTION("Prism54 USB wireless driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("prism54usb");
-MODULE_FIRMWARE("isl3886usb");
-MODULE_FIRMWARE("isl3887usb");
-
-/*
- * Note:
- *
- * Always update our wiki's device list (located at:
- * http://wireless.kernel.org/en/users/Drivers/p54/devices ),
- * whenever you add a new device.
- */
-
-static struct usb_device_id p54u_table[] = {
-       /* Version 1 devices (pci chip + net2280) */
-       {USB_DEVICE(0x0411, 0x0050)},   /* Buffalo WLI2-USB2-G54 */
-       {USB_DEVICE(0x045e, 0x00c2)},   /* Microsoft MN-710 */
-       {USB_DEVICE(0x0506, 0x0a11)},   /* 3COM 3CRWE254G72 */
-       {USB_DEVICE(0x0675, 0x0530)},   /* DrayTek Vigor 530 */
-       {USB_DEVICE(0x06b9, 0x0120)},   /* Thomson SpeedTouch 120g */
-       {USB_DEVICE(0x0707, 0xee06)},   /* SMC 2862W-G */
-       {USB_DEVICE(0x07aa, 0x001c)},   /* Corega CG-WLUSB2GT */
-       {USB_DEVICE(0x083a, 0x4501)},   /* Accton 802.11g WN4501 USB */
-       {USB_DEVICE(0x083a, 0x4502)},   /* Siemens Gigaset USB Adapter */
-       {USB_DEVICE(0x083a, 0x5501)},   /* Phillips CPWUA054 */
-       {USB_DEVICE(0x0846, 0x4200)},   /* Netgear WG121 */
-       {USB_DEVICE(0x0846, 0x4210)},   /* Netgear WG121 the second ? */
-       {USB_DEVICE(0x0846, 0x4220)},   /* Netgear WG111 */
-       {USB_DEVICE(0x09aa, 0x1000)},   /* Spinnaker Proto board */
-       {USB_DEVICE(0x0bf8, 0x1007)},   /* Fujitsu E-5400 USB */
-       {USB_DEVICE(0x0cde, 0x0006)},   /* Medion 40900, Roper Europe */
-       {USB_DEVICE(0x0db0, 0x6826)},   /* MSI UB54G (MS-6826) */
-       {USB_DEVICE(0x107b, 0x55f2)},   /* Gateway WGU-210 (Gemtek) */
-       {USB_DEVICE(0x124a, 0x4023)},   /* Shuttle PN15, Airvast WM168g, IOGear GWU513 */
-       {USB_DEVICE(0x1435, 0x0210)},   /* Inventel UR054G */
-       {USB_DEVICE(0x15a9, 0x0002)},   /* Gemtek WUBI-100GW 802.11g */
-       {USB_DEVICE(0x1630, 0x0005)},   /* 2Wire 802.11g USB (v1) / Z-Com */
-       {USB_DEVICE(0x182d, 0x096b)},   /* Sitecom WL-107 */
-       {USB_DEVICE(0x1915, 0x2234)},   /* Linksys WUSB54G OEM */
-       {USB_DEVICE(0x1915, 0x2235)},   /* Linksys WUSB54G Portable OEM */
-       {USB_DEVICE(0x2001, 0x3701)},   /* DLink DWL-G120 Spinnaker */
-       {USB_DEVICE(0x2001, 0x3703)},   /* DLink DWL-G122 */
-       {USB_DEVICE(0x2001, 0x3762)},   /* Conceptronic C54U */
-       {USB_DEVICE(0x5041, 0x2234)},   /* Linksys WUSB54G */
-       {USB_DEVICE(0x5041, 0x2235)},   /* Linksys WUSB54G Portable */
-
-       /* Version 2 devices (3887) */
-       {USB_DEVICE(0x0471, 0x1230)},   /* Philips CPWUA054/00 */
-       {USB_DEVICE(0x050d, 0x7050)},   /* Belkin F5D7050 ver 1000 */
-       {USB_DEVICE(0x0572, 0x2000)},   /* Cohiba Proto board */
-       {USB_DEVICE(0x0572, 0x2002)},   /* Cohiba Proto board */
-       {USB_DEVICE(0x06a9, 0x000e)},   /* Westell 802.11g USB (A90-211WG-01) */
-       {USB_DEVICE(0x06b9, 0x0121)},   /* Thomson SpeedTouch 121g */
-       {USB_DEVICE(0x0707, 0xee13)},   /* SMC 2862W-G version 2 */
-       {USB_DEVICE(0x07aa, 0x0020)},   /* Corega WLUSB2GTST USB */
-       {USB_DEVICE(0x0803, 0x4310)},   /* Zoom 4410a */
-       {USB_DEVICE(0x083a, 0x4521)},   /* Siemens Gigaset USB Adapter 54 version 2 */
-       {USB_DEVICE(0x083a, 0x4531)},   /* T-Com Sinus 154 data II */
-       {USB_DEVICE(0x083a, 0xc501)},   /* Zoom Wireless-G 4410 */
-       {USB_DEVICE(0x083a, 0xf503)},   /* Accton FD7050E ver 1010ec  */
-       {USB_DEVICE(0x0846, 0x4240)},   /* Netgear WG111 (v2) */
-       {USB_DEVICE(0x0915, 0x2000)},   /* Cohiba Proto board */
-       {USB_DEVICE(0x0915, 0x2002)},   /* Cohiba Proto board */
-       {USB_DEVICE(0x0baf, 0x0118)},   /* U.S. Robotics U5 802.11g Adapter*/
-       {USB_DEVICE(0x0bf8, 0x1009)},   /* FUJITSU E-5400 USB D1700*/
-       /* {USB_DEVICE(0x0cde, 0x0006)}, * Medion MD40900 already listed above,
-                                        * just noting it here for clarity */
-       {USB_DEVICE(0x0cde, 0x0008)},   /* Sagem XG703A */
-       {USB_DEVICE(0x0cde, 0x0015)},   /* Zcomax XG-705A */
-       {USB_DEVICE(0x0d8e, 0x3762)},   /* DLink DWL-G120 Cohiba */
-       {USB_DEVICE(0x124a, 0x4025)},   /* IOGear GWU513 (GW3887IK chip) */
-       {USB_DEVICE(0x1260, 0xee22)},   /* SMC 2862W-G version 2 */
-       {USB_DEVICE(0x13b1, 0x000a)},   /* Linksys WUSB54G ver 2 */
-       {USB_DEVICE(0x13B1, 0x000C)},   /* Linksys WUSB54AG */
-       {USB_DEVICE(0x1413, 0x5400)},   /* Telsey 802.11g USB2.0 Adapter */
-       {USB_DEVICE(0x1435, 0x0427)},   /* Inventel UR054G */
-       /* {USB_DEVICE(0x15a9, 0x0002)}, * Also SparkLAN WL-682 with 3887 */
-       {USB_DEVICE(0x1668, 0x1050)},   /* Actiontec 802UIG-1 */
-       {USB_DEVICE(0x1740, 0x1000)},   /* Senao NUB-350 */
-       {USB_DEVICE(0x2001, 0x3704)},   /* DLink DWL-G122 rev A2 */
-       {USB_DEVICE(0x2001, 0x3705)},   /* D-Link DWL-G120 rev C1 */
-       {USB_DEVICE(0x413c, 0x5513)},   /* Dell WLA3310 USB Wireless Adapter */
-       {USB_DEVICE(0x413c, 0x8102)},   /* Spinnaker DUT */
-       {USB_DEVICE(0x413c, 0x8104)},   /* Cohiba Proto board */
-       {}
-};
-
-MODULE_DEVICE_TABLE(usb, p54u_table);
-
-static const struct {
-       u32 intf;
-       enum p54u_hw_type type;
-       const char *fw;
-       char hw[20];
-} p54u_fwlist[__NUM_P54U_HWTYPES] = {
-       {
-               .type = P54U_NET2280,
-               .intf = FW_LM86,
-               .fw = "isl3886usb",
-               .hw = "ISL3886 + net2280",
-       },
-       {
-               .type = P54U_3887,
-               .intf = FW_LM87,
-               .fw = "isl3887usb",
-               .hw = "ISL3887",
-       },
-};
-
-static void p54u_rx_cb(struct urb *urb)
-{
-       struct sk_buff *skb = (struct sk_buff *) urb->context;
-       struct p54u_rx_info *info = (struct p54u_rx_info *)skb->cb;
-       struct ieee80211_hw *dev = info->dev;
-       struct p54u_priv *priv = dev->priv;
-
-       skb_unlink(skb, &priv->rx_queue);
-
-       if (unlikely(urb->status)) {
-               dev_kfree_skb_irq(skb);
-               return;
-       }
-
-       skb_put(skb, urb->actual_length);
-
-       if (priv->hw_type == P54U_NET2280)
-               skb_pull(skb, priv->common.tx_hdr_len);
-       if (priv->common.fw_interface == FW_LM87) {
-               skb_pull(skb, 4);
-               skb_put(skb, 4);
-       }
-
-       if (p54_rx(dev, skb)) {
-               skb = dev_alloc_skb(priv->common.rx_mtu + 32);
-               if (unlikely(!skb)) {
-                       /* TODO check rx queue length and refill *somewhere* */
-                       return;
-               }
-
-               info = (struct p54u_rx_info *) skb->cb;
-               info->urb = urb;
-               info->dev = dev;
-               urb->transfer_buffer = skb_tail_pointer(skb);
-               urb->context = skb;
-       } else {
-               if (priv->hw_type == P54U_NET2280)
-                       skb_push(skb, priv->common.tx_hdr_len);
-               if (priv->common.fw_interface == FW_LM87) {
-                       skb_push(skb, 4);
-                       skb_put(skb, 4);
-               }
-               skb_reset_tail_pointer(skb);
-               skb_trim(skb, 0);
-               urb->transfer_buffer = skb_tail_pointer(skb);
-       }
-       skb_queue_tail(&priv->rx_queue, skb);
-       usb_anchor_urb(urb, &priv->submitted);
-       if (usb_submit_urb(urb, GFP_ATOMIC)) {
-               skb_unlink(skb, &priv->rx_queue);
-               usb_unanchor_urb(urb);
-               dev_kfree_skb_irq(skb);
-       }
-}
-
-static void p54u_tx_cb(struct urb *urb)
-{
-       struct sk_buff *skb = urb->context;
-       struct ieee80211_hw *dev =
-               usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
-
-       p54_free_skb(dev, skb);
-}
-
-static void p54u_tx_dummy_cb(struct urb *urb) { }
-
-static void p54u_free_urbs(struct ieee80211_hw *dev)
-{
-       struct p54u_priv *priv = dev->priv;
-       usb_kill_anchored_urbs(&priv->submitted);
-}
-
-static void p54u_stop(struct ieee80211_hw *dev)
-{
-       /*
-        * TODO: figure out how to reliably stop the 3887 and net2280 so
-        * the hardware is still usable next time we want to start it.
-        * until then, we just stop listening to the hardware..
-        */
-       p54u_free_urbs(dev);
-}
-
-static int p54u_init_urbs(struct ieee80211_hw *dev)
-{
-       struct p54u_priv *priv = dev->priv;
-       struct urb *entry = NULL;
-       struct sk_buff *skb;
-       struct p54u_rx_info *info;
-       int ret = 0;
-
-       while (skb_queue_len(&priv->rx_queue) < 32) {
-               skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
-               if (!skb) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-               entry = usb_alloc_urb(0, GFP_KERNEL);
-               if (!entry) {
-                       ret = -ENOMEM;
-                       goto err;
-               }
-
-               usb_fill_bulk_urb(entry, priv->udev,
-                                 usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
-                                 skb_tail_pointer(skb),
-                                 priv->common.rx_mtu + 32, p54u_rx_cb, skb);
-               info = (struct p54u_rx_info *) skb->cb;
-               info->urb = entry;
-               info->dev = dev;
-               skb_queue_tail(&priv->rx_queue, skb);
-
-               usb_anchor_urb(entry, &priv->submitted);
-               ret = usb_submit_urb(entry, GFP_KERNEL);
-               if (ret) {
-                       skb_unlink(skb, &priv->rx_queue);
-                       usb_unanchor_urb(entry);
-                       goto err;
-               }
-               usb_free_urb(entry);
-               entry = NULL;
-       }
-
-       return 0;
-
- err:
-       usb_free_urb(entry);
-       kfree_skb(skb);
-       p54u_free_urbs(dev);
-       return ret;
-}
-
-static int p54u_open(struct ieee80211_hw *dev)
-{
-       /*
-        * TODO: Because we don't know how to reliably stop the 3887 and
-        * the isl3886+net2280, other than brutally cut off all
-        * communications. We have to reinitialize the urbs on every start.
-        */
-       return p54u_init_urbs(dev);
-}
-
-static __le32 p54u_lm87_chksum(const __le32 *data, size_t length)
-{
-       u32 chk = 0;
-
-       length >>= 2;
-       while (length--) {
-               chk ^= le32_to_cpu(*data++);
-               chk = (chk >> 5) ^ (chk << 3);
-       }
-
-       return cpu_to_le32(chk);
-}
-
-static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54u_priv *priv = dev->priv;
-       struct urb *data_urb;
-       struct lm87_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
-
-       data_urb = usb_alloc_urb(0, GFP_ATOMIC);
-       if (!data_urb) {
-               p54_free_skb(dev, skb);
-               return;
-       }
-
-       hdr->chksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len);
-       hdr->device_addr = ((struct p54_hdr *)skb->data)->req_id;
-
-       usb_fill_bulk_urb(data_urb, priv->udev,
-                         usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
-                         hdr, skb->len + sizeof(*hdr),  FREE_AFTER_TX(skb) ?
-                         p54u_tx_cb : p54u_tx_dummy_cb, skb);
-       data_urb->transfer_flags |= URB_ZERO_PACKET;
-
-       usb_anchor_urb(data_urb, &priv->submitted);
-       if (usb_submit_urb(data_urb, GFP_ATOMIC)) {
-               usb_unanchor_urb(data_urb);
-               p54_free_skb(dev, skb);
-       }
-       usb_free_urb(data_urb);
-}
-
-static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54u_priv *priv = dev->priv;
-       struct urb *int_urb = NULL, *data_urb = NULL;
-       struct net2280_tx_hdr *hdr = (void *)skb->data - sizeof(*hdr);
-       struct net2280_reg_write *reg = NULL;
-       int err = -ENOMEM;
-
-       reg = kmalloc(sizeof(*reg), GFP_ATOMIC);
-       if (!reg)
-               goto out;
-
-       int_urb = usb_alloc_urb(0, GFP_ATOMIC);
-       if (!int_urb)
-               goto out;
-
-       data_urb = usb_alloc_urb(0, GFP_ATOMIC);
-       if (!data_urb)
-               goto out;
-
-       reg->port = cpu_to_le16(NET2280_DEV_U32);
-       reg->addr = cpu_to_le32(P54U_DEV_BASE);
-       reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA);
-
-       memset(hdr, 0, sizeof(*hdr));
-       hdr->len = cpu_to_le16(skb->len);
-       hdr->device_addr = ((struct p54_hdr *) skb->data)->req_id;
-
-       usb_fill_bulk_urb(int_urb, priv->udev,
-               usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg),
-               p54u_tx_dummy_cb, dev);
-
-       /*
-        * URB_FREE_BUFFER triggers a code path in the USB subsystem that will
-        * free what is inside the transfer_buffer after the last reference to
-        * the int_urb is dropped.
-        */
-       int_urb->transfer_flags |= URB_FREE_BUFFER | URB_ZERO_PACKET;
-       reg = NULL;
-
-       usb_fill_bulk_urb(data_urb, priv->udev,
-                         usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA),
-                         hdr, skb->len + sizeof(*hdr), FREE_AFTER_TX(skb) ?
-                         p54u_tx_cb : p54u_tx_dummy_cb, skb);
-       data_urb->transfer_flags |= URB_ZERO_PACKET;
-
-       usb_anchor_urb(int_urb, &priv->submitted);
-       err = usb_submit_urb(int_urb, GFP_ATOMIC);
-       if (err) {
-               usb_unanchor_urb(int_urb);
-               goto out;
-       }
-
-       usb_anchor_urb(data_urb, &priv->submitted);
-       err = usb_submit_urb(data_urb, GFP_ATOMIC);
-       if (err) {
-               usb_unanchor_urb(data_urb);
-               goto out;
-       }
-out:
-       usb_free_urb(int_urb);
-       usb_free_urb(data_urb);
-
-       if (err) {
-               kfree(reg);
-               p54_free_skb(dev, skb);
-       }
-}
-
-static int p54u_write(struct p54u_priv *priv,
-                     struct net2280_reg_write *buf,
-                     enum net2280_op_type type,
-                     __le32 addr, __le32 val)
-{
-       unsigned int ep;
-       int alen;
-
-       if (type & 0x0800)
-               ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV);
-       else
-               ep = usb_sndbulkpipe(priv->udev, P54U_PIPE_BRG);
-
-       buf->port = cpu_to_le16(type);
-       buf->addr = addr;
-       buf->val = val;
-
-       return usb_bulk_msg(priv->udev, ep, buf, sizeof(*buf), &alen, 1000);
-}
-
-static int p54u_read(struct p54u_priv *priv, void *buf,
-                    enum net2280_op_type type,
-                    __le32 addr, __le32 *val)
-{
-       struct net2280_reg_read *read = buf;
-       __le32 *reg = buf;
-       unsigned int ep;
-       int alen, err;
-
-       if (type & 0x0800)
-               ep = P54U_PIPE_DEV;
-       else
-               ep = P54U_PIPE_BRG;
-
-       read->port = cpu_to_le16(type);
-       read->addr = addr;
-
-       err = usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
-                          read, sizeof(*read), &alen, 1000);
-       if (err)
-               return err;
-
-       err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, ep),
-                          reg, sizeof(*reg), &alen, 1000);
-       if (err)
-               return err;
-
-       *val = *reg;
-       return 0;
-}
-
-static int p54u_bulk_msg(struct p54u_priv *priv, unsigned int ep,
-                        void *data, size_t len)
-{
-       int alen;
-       return usb_bulk_msg(priv->udev, usb_sndbulkpipe(priv->udev, ep),
-                           data, len, &alen, 2000);
-}
-
-static int p54u_device_reset(struct ieee80211_hw *dev)
-{
-       struct p54u_priv *priv = dev->priv;
-       int ret, lock = (priv->intf->condition != USB_INTERFACE_BINDING);
-
-       if (lock) {
-               ret = usb_lock_device_for_reset(priv->udev, priv->intf);
-               if (ret < 0) {
-                       dev_err(&priv->udev->dev, "(p54usb) unable to lock "
-                               "device for reset (%d)!\n", ret);
-                       return ret;
-               }
-       }
-
-       ret = usb_reset_device(priv->udev);
-       if (lock)
-               usb_unlock_device(priv->udev);
-
-       if (ret)
-               dev_err(&priv->udev->dev, "(p54usb) unable to reset "
-                       "device (%d)!\n", ret);
-
-       return ret;
-}
-
-static const char p54u_romboot_3887[] = "~~~~";
-static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
-{
-       struct p54u_priv *priv = dev->priv;
-       u8 *buf;
-       int ret;
-
-       buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-       ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
-                           buf, 4);
-       kfree(buf);
-       if (ret)
-               dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
-                       "boot ROM (%d)!\n", ret);
-
-       return ret;
-}
-
-static const char p54u_firmware_upload_3887[] = "<\r";
-static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
-{
-       struct p54u_priv *priv = dev->priv;
-       int err, alen;
-       u8 carry = 0;
-       u8 *buf, *tmp;
-       const u8 *data;
-       unsigned int left, remains, block_size;
-       struct x2_header *hdr;
-       unsigned long timeout;
-
-       err = p54u_firmware_reset_3887(dev);
-       if (err)
-               return err;
-
-       tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       left = block_size = min_t(size_t, P54U_FW_BLOCK, priv->fw->size);
-       strcpy(buf, p54u_firmware_upload_3887);
-       left -= strlen(p54u_firmware_upload_3887);
-       tmp += strlen(p54u_firmware_upload_3887);
-
-       data = priv->fw->data;
-       remains = priv->fw->size;
-
-       hdr = (struct x2_header *)(buf + strlen(p54u_firmware_upload_3887));
-       memcpy(hdr->signature, X2_SIGNATURE, X2_SIGNATURE_SIZE);
-       hdr->fw_load_addr = cpu_to_le32(ISL38XX_DEV_FIRMWARE_ADDR);
-       hdr->fw_length = cpu_to_le32(priv->fw->size);
-       hdr->crc = cpu_to_le32(~crc32_le(~0, (void *)&hdr->fw_load_addr,
-                                        sizeof(u32)*2));
-       left -= sizeof(*hdr);
-       tmp += sizeof(*hdr);
-
-       while (remains) {
-               while (left--) {
-                       if (carry) {
-                               *tmp++ = carry;
-                               carry = 0;
-                               remains--;
-                               continue;
-                       }
-                       switch (*data) {
-                       case '~':
-                               *tmp++ = '}';
-                               carry = '^';
-                               break;
-                       case '}':
-                               *tmp++ = '}';
-                               carry = ']';
-                               break;
-                       default:
-                               *tmp++ = *data;
-                               remains--;
-                               break;
-                       }
-                       data++;
-               }
-
-               err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size);
-               if (err) {
-                       dev_err(&priv->udev->dev, "(p54usb) firmware "
-                                                 "upload failed!\n");
-                       goto err_upload_failed;
-               }
-
-               tmp = buf;
-               left = block_size = min((unsigned int)P54U_FW_BLOCK, remains);
-       }
-
-       *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, priv->fw->data,
-                                                priv->fw->size));
-       err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32));
-       if (err) {
-               dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
-               goto err_upload_failed;
-       }
-       timeout = jiffies + msecs_to_jiffies(1000);
-       while (!(err = usb_bulk_msg(priv->udev,
-               usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
-               if (alen > 2 && !memcmp(buf, "OK", 2))
-                       break;
-
-               if (alen > 5 && !memcmp(buf, "ERROR", 5)) {
-                       err = -EINVAL;
-                       break;
-               }
-
-               if (time_after(jiffies, timeout)) {
-                       dev_err(&priv->udev->dev, "(p54usb) firmware boot "
-                                                 "timed out!\n");
-                       err = -ETIMEDOUT;
-                       break;
-               }
-       }
-       if (err) {
-               dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n");
-               goto err_upload_failed;
-       }
-
-       buf[0] = 'g';
-       buf[1] = '\r';
-       err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2);
-       if (err) {
-               dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n");
-               goto err_upload_failed;
-       }
-
-       timeout = jiffies + msecs_to_jiffies(1000);
-       while (!(err = usb_bulk_msg(priv->udev,
-               usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) {
-               if (alen > 0 && buf[0] == 'g')
-                       break;
-
-               if (time_after(jiffies, timeout)) {
-                       err = -ETIMEDOUT;
-                       break;
-               }
-       }
-       if (err)
-               goto err_upload_failed;
-
-err_upload_failed:
-       kfree(buf);
-       return err;
-}
-
-static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
-{
-       struct p54u_priv *priv = dev->priv;
-       const struct p54p_csr *devreg = (const struct p54p_csr *) P54U_DEV_BASE;
-       int err, alen;
-       void *buf;
-       __le32 reg;
-       unsigned int remains, offset;
-       const u8 *data;
-
-       buf = kmalloc(512, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-#define P54U_WRITE(type, addr, data) \
-       do {\
-               err = p54u_write(priv, buf, type,\
-                                cpu_to_le32((u32)(unsigned long)addr), data);\
-               if (err) \
-                       goto fail;\
-       } while (0)
-
-#define P54U_READ(type, addr) \
-       do {\
-               err = p54u_read(priv, buf, type,\
-                               cpu_to_le32((u32)(unsigned long)addr), &reg);\
-               if (err)\
-                       goto fail;\
-       } while (0)
-
-       /* power down net2280 bridge */
-       P54U_READ(NET2280_BRG_U32, NET2280_GPIOCTL);
-       reg |= cpu_to_le32(P54U_BRG_POWER_DOWN);
-       reg &= cpu_to_le32(~P54U_BRG_POWER_UP);
-       P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
-
-       mdelay(100);
-
-       /* power up bridge */
-       reg |= cpu_to_le32(P54U_BRG_POWER_UP);
-       reg &= cpu_to_le32(~P54U_BRG_POWER_DOWN);
-       P54U_WRITE(NET2280_BRG_U32, NET2280_GPIOCTL, reg);
-
-       mdelay(100);
-
-       P54U_WRITE(NET2280_BRG_U32, NET2280_DEVINIT,
-                  cpu_to_le32(NET2280_CLK_30Mhz |
-                              NET2280_PCI_ENABLE |
-                              NET2280_PCI_SOFT_RESET));
-
-       mdelay(20);
-
-       P54U_WRITE(NET2280_BRG_CFG_U16, PCI_COMMAND,
-                  cpu_to_le32(PCI_COMMAND_MEMORY |
-                              PCI_COMMAND_MASTER));
-
-       P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_0,
-                  cpu_to_le32(NET2280_BASE));
-
-       P54U_READ(NET2280_BRG_CFG_U16, PCI_STATUS);
-       reg |= cpu_to_le32(PCI_STATUS_REC_MASTER_ABORT);
-       P54U_WRITE(NET2280_BRG_CFG_U16, PCI_STATUS, reg);
-
-       // TODO: we really need this?
-       P54U_READ(NET2280_BRG_U32, NET2280_RELNUM);
-
-       P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_RSP,
-                  cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
-       P54U_WRITE(NET2280_BRG_U32, NET2280_EPC_RSP,
-                  cpu_to_le32(NET2280_CLEAR_NAK_OUT_PACKETS_MODE));
-
-       P54U_WRITE(NET2280_BRG_CFG_U32, PCI_BASE_ADDRESS_2,
-                  cpu_to_le32(NET2280_BASE2));
-
-       /* finally done setting up the bridge */
-
-       P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | PCI_COMMAND,
-                  cpu_to_le32(PCI_COMMAND_MEMORY |
-                              PCI_COMMAND_MASTER));
-
-       P54U_WRITE(NET2280_DEV_CFG_U16, 0x10000 | 0x40 /* TRDY timeout */, 0);
-       P54U_WRITE(NET2280_DEV_CFG_U32, 0x10000 | PCI_BASE_ADDRESS_0,
-                  cpu_to_le32(P54U_DEV_BASE));
-
-       P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
-       P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
-                  cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
-
-       /* do romboot */
-       P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable, 0);
-
-       P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RAMBOOT);
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
-       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
-
-       mdelay(20);
-
-       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
-       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
-
-       mdelay(20);
-
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
-       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
-
-       mdelay(100);
-
-       P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
-       P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
-
-       /* finally, we can upload firmware now! */
-       remains = priv->fw->size;
-       data = priv->fw->data;
-       offset = ISL38XX_DEV_FIRMWARE_ADDR;
-
-       while (remains) {
-               unsigned int block_len = min(remains, (unsigned int)512);
-               memcpy(buf, data, block_len);
-
-               err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len);
-               if (err) {
-                       dev_err(&priv->udev->dev, "(p54usb) firmware block "
-                                                 "upload failed\n");
-                       goto fail;
-               }
-
-               P54U_WRITE(NET2280_DEV_U32, &devreg->direct_mem_base,
-                          cpu_to_le32(0xc0000f00));
-
-               P54U_WRITE(NET2280_DEV_U32,
-                          0x0020 | (unsigned long)&devreg->direct_mem_win, 0);
-               P54U_WRITE(NET2280_DEV_U32,
-                          0x0020 | (unsigned long)&devreg->direct_mem_win,
-                          cpu_to_le32(1));
-
-               P54U_WRITE(NET2280_DEV_U32,
-                          0x0024 | (unsigned long)&devreg->direct_mem_win,
-                          cpu_to_le32(block_len));
-               P54U_WRITE(NET2280_DEV_U32,
-                          0x0028 | (unsigned long)&devreg->direct_mem_win,
-                          cpu_to_le32(offset));
-
-               P54U_WRITE(NET2280_DEV_U32, &devreg->dma_addr,
-                          cpu_to_le32(NET2280_EPA_FIFO_PCI_ADDR));
-               P54U_WRITE(NET2280_DEV_U32, &devreg->dma_len,
-                          cpu_to_le32(block_len >> 2));
-               P54U_WRITE(NET2280_DEV_U32, &devreg->dma_ctrl,
-                          cpu_to_le32(ISL38XX_DMA_MASTER_CONTROL_TRIGGER));
-
-               mdelay(10);
-
-               P54U_READ(NET2280_DEV_U32,
-                         0x002C | (unsigned long)&devreg->direct_mem_win);
-               if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) ||
-                   !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) {
-                       dev_err(&priv->udev->dev, "(p54usb) firmware DMA "
-                                                 "transfer failed\n");
-                       goto fail;
-               }
-
-               P54U_WRITE(NET2280_BRG_U32, NET2280_EPA_STAT,
-                          cpu_to_le32(NET2280_FIFO_FLUSH));
-
-               remains -= block_len;
-               data += block_len;
-               offset += block_len;
-       }
-
-       /* do ramboot */
-       P54U_READ(NET2280_DEV_U32, &devreg->ctrl_stat);
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN);
-       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RAMBOOT);
-       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
-
-       mdelay(20);
-
-       reg |= cpu_to_le32(ISL38XX_CTRL_STAT_RESET);
-       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
-
-       reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET);
-       P54U_WRITE(NET2280_DEV_U32, &devreg->ctrl_stat, reg);
-
-       mdelay(100);
-
-       P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
-       P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
-
-       /* start up the firmware */
-       P54U_WRITE(NET2280_DEV_U32, &devreg->int_enable,
-                  cpu_to_le32(ISL38XX_INT_IDENT_INIT));
-
-       P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
-                  cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
-
-       P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1,
-                  cpu_to_le32(NET2280_PCI_INTA_INTERRUPT_ENABLE |
-                              NET2280_USB_INTERRUPT_ENABLE));
-
-       P54U_WRITE(NET2280_DEV_U32, &devreg->dev_int,
-                  cpu_to_le32(ISL38XX_DEV_INT_RESET));
-
-       err = usb_interrupt_msg(priv->udev,
-                               usb_rcvbulkpipe(priv->udev, P54U_PIPE_INT),
-                               buf, sizeof(__le32), &alen, 1000);
-       if (err || alen != sizeof(__le32))
-               goto fail;
-
-       P54U_READ(NET2280_DEV_U32, &devreg->int_ident);
-       P54U_WRITE(NET2280_DEV_U32, &devreg->int_ack, reg);
-
-       if (!(reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)))
-               err = -EINVAL;
-
-       P54U_WRITE(NET2280_BRG_U32, NET2280_USBIRQENB1, 0);
-       P54U_WRITE(NET2280_BRG_U32, NET2280_IRQSTAT1,
-                  cpu_to_le32(NET2280_PCI_INTA_INTERRUPT));
-
-#undef P54U_WRITE
-#undef P54U_READ
-
-fail:
-       kfree(buf);
-       return err;
-}
-
-static int p54_find_type(struct p54u_priv *priv)
-{
-       int i;
-
-       for (i = 0; i < __NUM_P54U_HWTYPES; i++)
-               if (p54u_fwlist[i].type == priv->hw_type)
-                       break;
-       if (i == __NUM_P54U_HWTYPES)
-               return -EOPNOTSUPP;
-
-       return i;
-}
-
-static int p54u_start_ops(struct p54u_priv *priv)
-{
-       struct ieee80211_hw *dev = priv->common.hw;
-       int ret;
-
-       ret = p54_parse_firmware(dev, priv->fw);
-       if (ret)
-               goto err_out;
-
-       ret = p54_find_type(priv);
-       if (ret < 0)
-               goto err_out;
-
-       if (priv->common.fw_interface != p54u_fwlist[ret].intf) {
-               dev_err(&priv->udev->dev, "wrong firmware, please get "
-                       "a firmware for \"%s\" and try again.\n",
-                       p54u_fwlist[ret].hw);
-               ret = -ENODEV;
-               goto err_out;
-       }
-
-       ret = priv->upload_fw(dev);
-       if (ret)
-               goto err_out;
-
-       ret = p54u_open(dev);
-       if (ret)
-               goto err_out;
-
-       ret = p54_read_eeprom(dev);
-       if (ret)
-               goto err_stop;
-
-       p54u_stop(dev);
-
-       ret = p54_register_common(dev, &priv->udev->dev);
-       if (ret)
-               goto err_stop;
-
-       return 0;
-
-err_stop:
-       p54u_stop(dev);
-
-err_out:
-       /*
-        * p54u_disconnect will do the rest of the
-        * cleanup
-        */
-       return ret;
-}
-
-static void p54u_load_firmware_cb(const struct firmware *firmware,
-                                 void *context)
-{
-       struct p54u_priv *priv = context;
-       struct usb_device *udev = priv->udev;
-       int err;
-
-       complete(&priv->fw_wait_load);
-       if (firmware) {
-               priv->fw = firmware;
-               err = p54u_start_ops(priv);
-       } else {
-               err = -ENOENT;
-               dev_err(&udev->dev, "Firmware not found.\n");
-       }
-
-       if (err) {
-               struct device *parent = priv->udev->dev.parent;
-
-               dev_err(&udev->dev, "failed to initialize device (%d)\n", err);
-
-               if (parent)
-                       device_lock(parent);
-
-               device_release_driver(&udev->dev);
-               /*
-                * At this point p54u_disconnect has already freed
-                * the "priv" context. Do not use it anymore!
-                */
-               priv = NULL;
-
-               if (parent)
-                       device_unlock(parent);
-       }
-
-       usb_put_dev(udev);
-}
-
-static int p54u_load_firmware(struct ieee80211_hw *dev,
-                             struct usb_interface *intf)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct p54u_priv *priv = dev->priv;
-       struct device *device = &udev->dev;
-       int err, i;
-
-       BUILD_BUG_ON(ARRAY_SIZE(p54u_fwlist) != __NUM_P54U_HWTYPES);
-
-       init_completion(&priv->fw_wait_load);
-       i = p54_find_type(priv);
-       if (i < 0)
-               return i;
-
-       dev_info(&priv->udev->dev, "Loading firmware file %s\n",
-              p54u_fwlist[i].fw);
-
-       usb_get_dev(udev);
-       err = request_firmware_nowait(THIS_MODULE, 1, p54u_fwlist[i].fw,
-                                     device, GFP_KERNEL, priv,
-                                     p54u_load_firmware_cb);
-       if (err) {
-               dev_err(&priv->udev->dev, "(p54usb) cannot load firmware %s "
-                                         "(%d)!\n", p54u_fwlist[i].fw, err);
-               usb_put_dev(udev);
-       }
-
-       return err;
-}
-
-static int p54u_probe(struct usb_interface *intf,
-                               const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-       struct ieee80211_hw *dev;
-       struct p54u_priv *priv;
-       int err;
-       unsigned int i, recognized_pipes;
-
-       dev = p54_init_common(sizeof(*priv));
-
-       if (!dev) {
-               dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n");
-               return -ENOMEM;
-       }
-
-       priv = dev->priv;
-       priv->hw_type = P54U_INVALID_HW;
-
-       SET_IEEE80211_DEV(dev, &intf->dev);
-       usb_set_intfdata(intf, dev);
-       priv->udev = udev;
-       priv->intf = intf;
-       skb_queue_head_init(&priv->rx_queue);
-       init_usb_anchor(&priv->submitted);
-
-       usb_get_dev(udev);
-
-       /* really lazy and simple way of figuring out if we're a 3887 */
-       /* TODO: should just stick the identification in the device table */
-       i = intf->altsetting->desc.bNumEndpoints;
-       recognized_pipes = 0;
-       while (i--) {
-               switch (intf->altsetting->endpoint[i].desc.bEndpointAddress) {
-               case P54U_PIPE_DATA:
-               case P54U_PIPE_MGMT:
-               case P54U_PIPE_BRG:
-               case P54U_PIPE_DEV:
-               case P54U_PIPE_DATA | USB_DIR_IN:
-               case P54U_PIPE_MGMT | USB_DIR_IN:
-               case P54U_PIPE_BRG | USB_DIR_IN:
-               case P54U_PIPE_DEV | USB_DIR_IN:
-               case P54U_PIPE_INT | USB_DIR_IN:
-                       recognized_pipes++;
-               }
-       }
-       priv->common.open = p54u_open;
-       priv->common.stop = p54u_stop;
-       if (recognized_pipes < P54U_PIPE_NUMBER) {
-#ifdef CONFIG_PM
-               /* ISL3887 needs a full reset on resume */
-               udev->reset_resume = 1;
-#endif /* CONFIG_PM */
-               err = p54u_device_reset(dev);
-
-               priv->hw_type = P54U_3887;
-               dev->extra_tx_headroom += sizeof(struct lm87_tx_hdr);
-               priv->common.tx_hdr_len = sizeof(struct lm87_tx_hdr);
-               priv->common.tx = p54u_tx_lm87;
-               priv->upload_fw = p54u_upload_firmware_3887;
-       } else {
-               priv->hw_type = P54U_NET2280;
-               dev->extra_tx_headroom += sizeof(struct net2280_tx_hdr);
-               priv->common.tx_hdr_len = sizeof(struct net2280_tx_hdr);
-               priv->common.tx = p54u_tx_net2280;
-               priv->upload_fw = p54u_upload_firmware_net2280;
-       }
-       err = p54u_load_firmware(dev, intf);
-       if (err) {
-               usb_put_dev(udev);
-               p54_free_common(dev);
-       }
-       return err;
-}
-
-static void p54u_disconnect(struct usb_interface *intf)
-{
-       struct ieee80211_hw *dev = usb_get_intfdata(intf);
-       struct p54u_priv *priv;
-
-       if (!dev)
-               return;
-
-       priv = dev->priv;
-       wait_for_completion(&priv->fw_wait_load);
-       p54_unregister_common(dev);
-
-       usb_put_dev(interface_to_usbdev(intf));
-       release_firmware(priv->fw);
-       p54_free_common(dev);
-}
-
-static int p54u_pre_reset(struct usb_interface *intf)
-{
-       struct ieee80211_hw *dev = usb_get_intfdata(intf);
-
-       if (!dev)
-               return -ENODEV;
-
-       p54u_stop(dev);
-       return 0;
-}
-
-static int p54u_resume(struct usb_interface *intf)
-{
-       struct ieee80211_hw *dev = usb_get_intfdata(intf);
-       struct p54u_priv *priv;
-
-       if (!dev)
-               return -ENODEV;
-
-       priv = dev->priv;
-       if (unlikely(!(priv->upload_fw && priv->fw)))
-               return 0;
-
-       return priv->upload_fw(dev);
-}
-
-static int p54u_post_reset(struct usb_interface *intf)
-{
-       struct ieee80211_hw *dev = usb_get_intfdata(intf);
-       struct p54u_priv *priv;
-       int err;
-
-       err = p54u_resume(intf);
-       if (err)
-               return err;
-
-       /* reinitialize old device state */
-       priv = dev->priv;
-       if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED)
-               ieee80211_restart_hw(dev);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM
-
-static int p54u_suspend(struct usb_interface *intf, pm_message_t message)
-{
-       return p54u_pre_reset(intf);
-}
-
-#endif /* CONFIG_PM */
-
-static struct usb_driver p54u_driver = {
-       .name   = "p54usb",
-       .id_table = p54u_table,
-       .probe = p54u_probe,
-       .disconnect = p54u_disconnect,
-       .pre_reset = p54u_pre_reset,
-       .post_reset = p54u_post_reset,
-#ifdef CONFIG_PM
-       .suspend = p54u_suspend,
-       .resume = p54u_resume,
-       .reset_resume = p54u_resume,
-#endif /* CONFIG_PM */
-       .soft_unbind = 1,
-       .disable_hub_initiated_lpm = 1,
-};
-
-module_usb_driver(p54u_driver);
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
deleted file mode 100644 (file)
index a5f5f0f..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-#ifndef P54USB_H
-#define P54USB_H
-
-/*
- * Defines for USB based mac80211 Prism54 driver
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- *
- * Based on the islsm (softmac prism54) driver, which is:
- * Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/* for isl3886 register definitions used on ver 1 devices */
-#include "p54pci.h"
-#include <linux/usb/net2280.h>
-
-/* pci */
-#define NET2280_BASE           0x10000000
-#define NET2280_BASE2          0x20000000
-
-/* gpio */
-#define P54U_BRG_POWER_UP      (1 << GPIO0_DATA)
-#define P54U_BRG_POWER_DOWN    (1 << GPIO1_DATA)
-
-/* devinit */
-#define NET2280_CLK_4Mhz       (15 << LOCAL_CLOCK_FREQUENCY)
-#define NET2280_CLK_30Mhz      (2 << LOCAL_CLOCK_FREQUENCY)
-#define NET2280_CLK_60Mhz      (1 << LOCAL_CLOCK_FREQUENCY)
-#define NET2280_CLK_STOP       (0 << LOCAL_CLOCK_FREQUENCY)
-#define NET2280_PCI_ENABLE     (1 << PCI_ENABLE)
-#define NET2280_PCI_SOFT_RESET (1 << PCI_SOFT_RESET)
-
-/* endpoints */
-#define NET2280_CLEAR_NAK_OUT_PACKETS_MODE     (1 << CLEAR_NAK_OUT_PACKETS_MODE)
-#define NET2280_FIFO_FLUSH                     (1 << FIFO_FLUSH)
-
-/* irq */
-#define NET2280_USB_INTERRUPT_ENABLE           (1 << USB_INTERRUPT_ENABLE)
-#define NET2280_PCI_INTA_INTERRUPT             (1 << PCI_INTA_INTERRUPT)
-#define NET2280_PCI_INTA_INTERRUPT_ENABLE      (1 << PCI_INTA_INTERRUPT_ENABLE)
-
-/* registers */
-#define NET2280_DEVINIT                0x00
-#define NET2280_USBIRQENB1     0x24
-#define NET2280_IRQSTAT1       0x2c
-#define NET2280_FIFOCTL         0x38
-#define NET2280_GPIOCTL                0x50
-#define NET2280_RELNUM         0x88
-#define NET2280_EPA_RSP                0x324
-#define NET2280_EPA_STAT       0x32c
-#define NET2280_EPB_STAT       0x34c
-#define NET2280_EPC_RSP                0x364
-#define NET2280_EPC_STAT       0x36c
-#define NET2280_EPD_STAT       0x38c
-
-#define NET2280_EPA_CFG     0x320
-#define NET2280_EPB_CFG     0x340
-#define NET2280_EPC_CFG     0x360
-#define NET2280_EPD_CFG     0x380
-#define NET2280_EPE_CFG     0x3A0
-#define NET2280_EPF_CFG     0x3C0
-#define P54U_DEV_BASE 0x40000000
-
-struct net2280_tx_hdr {
-       __le32 device_addr;
-       __le16 len;
-       __le16 follower;        /* ? */
-       u8 padding[8];
-} __packed;
-
-struct lm87_tx_hdr {
-       __le32 device_addr;
-       __le32 chksum;
-} __packed;
-
-/* Some flags for the isl hardware registers controlling DMA inside the
- * chip */
-#define ISL38XX_DMA_STATUS_DONE                        0x00000001
-#define ISL38XX_DMA_STATUS_READY               0x00000002
-#define NET2280_EPA_FIFO_PCI_ADDR              0x20000000
-#define ISL38XX_DMA_MASTER_CONTROL_TRIGGER     0x00000004
-
-enum net2280_op_type {
-       NET2280_BRG_U32         = 0x001F,
-       NET2280_BRG_CFG_U32     = 0x000F,
-       NET2280_BRG_CFG_U16     = 0x0003,
-       NET2280_DEV_U32         = 0x080F,
-       NET2280_DEV_CFG_U32     = 0x088F,
-       NET2280_DEV_CFG_U16     = 0x0883
-};
-
-struct net2280_reg_write {
-       __le16 port;
-       __le32 addr;
-       __le32 val;
-} __packed;
-
-struct net2280_reg_read {
-       __le16 port;
-       __le32 addr;
-} __packed;
-
-#define P54U_FW_BLOCK 2048
-
-#define X2_SIGNATURE "x2  "
-#define X2_SIGNATURE_SIZE 4
-
-struct x2_header {
-       u8 signature[X2_SIGNATURE_SIZE];
-       __le32 fw_load_addr;
-       __le32 fw_length;
-       __le32 crc;
-} __packed;
-
-/* pipes 3 and 4 are not used by the driver */
-#define P54U_PIPE_NUMBER 9
-
-enum p54u_pipe_addr {
-        P54U_PIPE_DATA = 0x01,
-        P54U_PIPE_MGMT = 0x02,
-        P54U_PIPE_3 = 0x03,
-        P54U_PIPE_4 = 0x04,
-        P54U_PIPE_BRG = 0x0d,
-        P54U_PIPE_DEV = 0x0e,
-        P54U_PIPE_INT = 0x0f
-};
-
-struct p54u_rx_info {
-       struct urb *urb;
-       struct ieee80211_hw *dev;
-};
-
-enum p54u_hw_type {
-       P54U_INVALID_HW,
-       P54U_NET2280,
-       P54U_3887,
-
-       /* keep last */
-       __NUM_P54U_HWTYPES,
-};
-
-struct p54u_priv {
-       struct p54_common common;
-       struct usb_device *udev;
-       struct usb_interface *intf;
-       int (*upload_fw)(struct ieee80211_hw *dev);
-
-       enum p54u_hw_type hw_type;
-       spinlock_t lock;
-       struct sk_buff_head rx_queue;
-       struct usb_anchor submitted;
-       const struct firmware *fw;
-
-       /* asynchronous firmware callback */
-       struct completion fw_wait_load;
-};
-
-#endif /* P54USB_H */
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
deleted file mode 100644 (file)
index 24e5ff9..0000000
+++ /dev/null
@@ -1,940 +0,0 @@
-/*
- * Common code for mac80211 Prism54 drivers
- *
- * Copyright (c) 2006, Michael Wu <flamingice@sourmilk.net>
- * Copyright (c) 2007-2009, Christian Lamparter <chunkeey@web.de>
- * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
- *
- * Based on:
- * - the islsm (softmac prism54) driver, which is:
- *   Copyright 2004-2006 Jean-Baptiste Note <jbnote@gmail.com>, et al.
- * - stlc45xx driver
- *   Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/export.h>
-#include <linux/firmware.h>
-#include <linux/etherdevice.h>
-#include <asm/div64.h>
-
-#include <net/mac80211.h>
-
-#include "p54.h"
-#include "lmac.h"
-
-#ifdef P54_MM_DEBUG
-static void p54_dump_tx_queue(struct p54_common *priv)
-{
-       unsigned long flags;
-       struct ieee80211_tx_info *info;
-       struct p54_tx_info *range;
-       struct sk_buff *skb;
-       struct p54_hdr *hdr;
-       unsigned int i = 0;
-       u32 prev_addr;
-       u32 largest_hole = 0, free;
-
-       spin_lock_irqsave(&priv->tx_queue.lock, flags);
-       wiphy_debug(priv->hw->wiphy, "/ --- tx queue dump (%d entries) ---\n",
-                   skb_queue_len(&priv->tx_queue));
-
-       prev_addr = priv->rx_start;
-       skb_queue_walk(&priv->tx_queue, skb) {
-               info = IEEE80211_SKB_CB(skb);
-               range = (void *) info->rate_driver_data;
-               hdr = (void *) skb->data;
-
-               free = range->start_addr - prev_addr;
-               wiphy_debug(priv->hw->wiphy,
-                           "| [%02d] => [skb:%p skb_len:0x%04x "
-                           "hdr:{flags:%02x len:%04x req_id:%04x type:%02x} "
-                           "mem:{start:%04x end:%04x, free:%d}]\n",
-                           i++, skb, skb->len,
-                           le16_to_cpu(hdr->flags), le16_to_cpu(hdr->len),
-                           le32_to_cpu(hdr->req_id), le16_to_cpu(hdr->type),
-                           range->start_addr, range->end_addr, free);
-
-               prev_addr = range->end_addr;
-               largest_hole = max(largest_hole, free);
-       }
-       free = priv->rx_end - prev_addr;
-       largest_hole = max(largest_hole, free);
-       wiphy_debug(priv->hw->wiphy,
-                   "\\ --- [free: %d], largest free block: %d ---\n",
-                   free, largest_hole);
-       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-}
-#endif /* P54_MM_DEBUG */
-
-/*
- * So, the firmware is somewhat stupid and doesn't know what places in its
- * memory incoming data should go to. By poking around in the firmware, we
- * can find some unused memory to upload our packets to. However, data that we
- * want the card to TX needs to stay intact until the card has told us that
- * it is done with it. This function finds empty places we can upload to and
- * marks allocated areas as reserved if necessary. p54_find_and_unlink_skb or
- * p54_free_skb frees allocated areas.
- */
-static int p54_assign_address(struct p54_common *priv, struct sk_buff *skb)
-{
-       struct sk_buff *entry, *target_skb = NULL;
-       struct ieee80211_tx_info *info;
-       struct p54_tx_info *range;
-       struct p54_hdr *data = (void *) skb->data;
-       unsigned long flags;
-       u32 last_addr = priv->rx_start;
-       u32 target_addr = priv->rx_start;
-       u16 len = priv->headroom + skb->len + priv->tailroom + 3;
-
-       info = IEEE80211_SKB_CB(skb);
-       range = (void *) info->rate_driver_data;
-       len = (range->extra_len + len) & ~0x3;
-
-       spin_lock_irqsave(&priv->tx_queue.lock, flags);
-       if (unlikely(skb_queue_len(&priv->tx_queue) == 32)) {
-               /*
-                * The tx_queue is now really full.
-                *
-                * TODO: check if the device has crashed and reset it.
-                */
-               spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-               return -EBUSY;
-       }
-
-       skb_queue_walk(&priv->tx_queue, entry) {
-               u32 hole_size;
-               info = IEEE80211_SKB_CB(entry);
-               range = (void *) info->rate_driver_data;
-               hole_size = range->start_addr - last_addr;
-
-               if (!target_skb && hole_size >= len) {
-                       target_skb = entry->prev;
-                       hole_size -= len;
-                       target_addr = last_addr;
-                       break;
-               }
-               last_addr = range->end_addr;
-       }
-       if (unlikely(!target_skb)) {
-               if (priv->rx_end - last_addr >= len) {
-                       target_skb = priv->tx_queue.prev;
-                       if (!skb_queue_empty(&priv->tx_queue)) {
-                               info = IEEE80211_SKB_CB(target_skb);
-                               range = (void *)info->rate_driver_data;
-                               target_addr = range->end_addr;
-                       }
-               } else {
-                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-                       return -ENOSPC;
-               }
-       }
-
-       info = IEEE80211_SKB_CB(skb);
-       range = (void *) info->rate_driver_data;
-       range->start_addr = target_addr;
-       range->end_addr = target_addr + len;
-       data->req_id = cpu_to_le32(target_addr + priv->headroom);
-       if (IS_DATA_FRAME(skb) &&
-           unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON))
-               priv->beacon_req_id = data->req_id;
-
-       __skb_queue_after(&priv->tx_queue, target_skb, skb);
-       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-       return 0;
-}
-
-static void p54_tx_pending(struct p54_common *priv)
-{
-       struct sk_buff *skb;
-       int ret;
-
-       skb = skb_dequeue(&priv->tx_pending);
-       if (unlikely(!skb))
-               return ;
-
-       ret = p54_assign_address(priv, skb);
-       if (unlikely(ret))
-               skb_queue_head(&priv->tx_pending, skb);
-       else
-               priv->tx(priv->hw, skb);
-}
-
-static void p54_wake_queues(struct p54_common *priv)
-{
-       unsigned long flags;
-       unsigned int i;
-
-       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
-               return ;
-
-       p54_tx_pending(priv);
-
-       spin_lock_irqsave(&priv->tx_stats_lock, flags);
-       for (i = 0; i < priv->hw->queues; i++) {
-               if (priv->tx_stats[i + P54_QUEUE_DATA].len <
-                   priv->tx_stats[i + P54_QUEUE_DATA].limit)
-                       ieee80211_wake_queue(priv->hw, i);
-       }
-       spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
-}
-
-static int p54_tx_qos_accounting_alloc(struct p54_common *priv,
-                                      struct sk_buff *skb,
-                                      const u16 p54_queue)
-{
-       struct p54_tx_queue_stats *queue;
-       unsigned long flags;
-
-       if (WARN_ON(p54_queue >= P54_QUEUE_NUM))
-               return -EINVAL;
-
-       queue = &priv->tx_stats[p54_queue];
-
-       spin_lock_irqsave(&priv->tx_stats_lock, flags);
-       if (unlikely(queue->len >= queue->limit && IS_QOS_QUEUE(p54_queue))) {
-               spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
-               return -ENOSPC;
-       }
-
-       queue->len++;
-       queue->count++;
-
-       if (unlikely(queue->len == queue->limit && IS_QOS_QUEUE(p54_queue))) {
-               u16 ac_queue = p54_queue - P54_QUEUE_DATA;
-               ieee80211_stop_queue(priv->hw, ac_queue);
-       }
-
-       spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
-       return 0;
-}
-
-static void p54_tx_qos_accounting_free(struct p54_common *priv,
-                                      struct sk_buff *skb)
-{
-       if (IS_DATA_FRAME(skb)) {
-               unsigned long flags;
-
-               spin_lock_irqsave(&priv->tx_stats_lock, flags);
-               priv->tx_stats[GET_HW_QUEUE(skb)].len--;
-               spin_unlock_irqrestore(&priv->tx_stats_lock, flags);
-
-               if (unlikely(GET_HW_QUEUE(skb) == P54_QUEUE_BEACON)) {
-                       if (priv->beacon_req_id == GET_REQ_ID(skb)) {
-                               /* this is the  active beacon set anymore */
-                               priv->beacon_req_id = 0;
-                       }
-                       complete(&priv->beacon_comp);
-               }
-       }
-       p54_wake_queues(priv);
-}
-
-void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54_common *priv = dev->priv;
-       if (unlikely(!skb))
-               return ;
-
-       skb_unlink(skb, &priv->tx_queue);
-       p54_tx_qos_accounting_free(priv, skb);
-       ieee80211_free_txskb(dev, skb);
-}
-EXPORT_SYMBOL_GPL(p54_free_skb);
-
-static struct sk_buff *p54_find_and_unlink_skb(struct p54_common *priv,
-                                              const __le32 req_id)
-{
-       struct sk_buff *entry;
-       unsigned long flags;
-
-       spin_lock_irqsave(&priv->tx_queue.lock, flags);
-       skb_queue_walk(&priv->tx_queue, entry) {
-               struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
-
-               if (hdr->req_id == req_id) {
-                       __skb_unlink(entry, &priv->tx_queue);
-                       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-                       p54_tx_qos_accounting_free(priv, entry);
-                       return entry;
-               }
-       }
-       spin_unlock_irqrestore(&priv->tx_queue.lock, flags);
-       return NULL;
-}
-
-void p54_tx(struct p54_common *priv, struct sk_buff *skb)
-{
-       skb_queue_tail(&priv->tx_pending, skb);
-       p54_tx_pending(priv);
-}
-
-static int p54_rssi_to_dbm(struct p54_common *priv, int rssi)
-{
-       if (priv->rxhw != 5) {
-               return ((rssi * priv->cur_rssi->mul) / 64 +
-                        priv->cur_rssi->add) / 4;
-       } else {
-               /*
-                * TODO: find the correct formula
-                */
-               return rssi / 2 - 110;
-       }
-}
-
-/*
- * Even if the firmware is capable of dealing with incoming traffic,
- * while dozing, we have to prepared in case mac80211 uses PS-POLL
- * to retrieve outstanding frames from our AP.
- * (see comment in net/mac80211/mlme.c @ line 1993)
- */
-static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
-{
-       struct ieee80211_hdr *hdr = (void *) skb->data;
-       struct ieee80211_tim_ie *tim_ie;
-       u8 *tim;
-       u8 tim_len;
-       bool new_psm;
-
-       /* only beacons have a TIM IE */
-       if (!ieee80211_is_beacon(hdr->frame_control))
-               return;
-
-       if (!priv->aid)
-               return;
-
-       /* only consider beacons from the associated BSSID */
-       if (!ether_addr_equal_64bits(hdr->addr3, priv->bssid))
-               return;
-
-       tim = p54_find_ie(skb, WLAN_EID_TIM);
-       if (!tim)
-               return;
-
-       tim_len = tim[1];
-       tim_ie = (struct ieee80211_tim_ie *) &tim[2];
-
-       new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid);
-       if (new_psm != priv->powersave_override) {
-               priv->powersave_override = new_psm;
-               p54_set_ps(priv);
-       }
-}
-
-static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
-{
-       struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data;
-       struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
-       u16 freq = le16_to_cpu(hdr->freq);
-       size_t header_len = sizeof(*hdr);
-       u32 tsf32;
-       u8 rate = hdr->rate & 0xf;
-
-       /*
-        * If the device is in a unspecified state we have to
-        * ignore all data frames. Else we could end up with a
-        * nasty crash.
-        */
-       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
-               return 0;
-
-       if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD)))
-               return 0;
-
-       if (hdr->decrypt_status == P54_DECRYPT_OK)
-               rx_status->flag |= RX_FLAG_DECRYPTED;
-       if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) ||
-           (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP))
-               rx_status->flag |= RX_FLAG_MMIC_ERROR;
-
-       rx_status->signal = p54_rssi_to_dbm(priv, hdr->rssi);
-       if (hdr->rate & 0x10)
-               rx_status->flag |= RX_FLAG_SHORTPRE;
-       if (priv->hw->conf.chandef.chan->band == IEEE80211_BAND_5GHZ)
-               rx_status->rate_idx = (rate < 4) ? 0 : rate - 4;
-       else
-               rx_status->rate_idx = rate;
-
-       rx_status->freq = freq;
-       rx_status->band =  priv->hw->conf.chandef.chan->band;
-       rx_status->antenna = hdr->antenna;
-
-       tsf32 = le32_to_cpu(hdr->tsf32);
-       if (tsf32 < priv->tsf_low32)
-               priv->tsf_high32++;
-       rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
-       priv->tsf_low32 = tsf32;
-
-       /* LMAC API Page 10/29 - s_lm_data_in - clock
-        * "usec accurate timestamp of hardware clock
-        * at end of frame (before OFDM SIFS EOF padding"
-        */
-       rx_status->flag |= RX_FLAG_MACTIME_END;
-
-       if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
-               header_len += hdr->align[0];
-
-       skb_pull(skb, header_len);
-       skb_trim(skb, le16_to_cpu(hdr->len));
-       if (unlikely(priv->hw->conf.flags & IEEE80211_CONF_PS))
-               p54_pspoll_workaround(priv, skb);
-
-       ieee80211_rx_irqsafe(priv->hw, skb);
-
-       ieee80211_queue_delayed_work(priv->hw, &priv->work,
-                          msecs_to_jiffies(P54_STATISTICS_UPDATE));
-
-       return -1;
-}
-
-static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb)
-{
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-       struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
-       struct ieee80211_tx_info *info;
-       struct p54_hdr *entry_hdr;
-       struct p54_tx_data *entry_data;
-       struct sk_buff *entry;
-       unsigned int pad = 0, frame_len;
-       int count, idx;
-
-       entry = p54_find_and_unlink_skb(priv, hdr->req_id);
-       if (unlikely(!entry))
-               return ;
-
-       frame_len = entry->len;
-       info = IEEE80211_SKB_CB(entry);
-       entry_hdr = (struct p54_hdr *) entry->data;
-       entry_data = (struct p54_tx_data *) entry_hdr->data;
-       priv->stats.dot11ACKFailureCount += payload->tries - 1;
-
-       /*
-        * Frames in P54_QUEUE_FWSCAN and P54_QUEUE_BEACON are
-        * generated by the driver. Therefore tx_status is bogus
-        * and we don't want to confuse the mac80211 stack.
-        */
-       if (unlikely(entry_data->hw_queue < P54_QUEUE_FWSCAN)) {
-               dev_kfree_skb_any(entry);
-               return ;
-       }
-
-       /*
-        * Clear manually, ieee80211_tx_info_clear_status would
-        * clear the counts too and we need them.
-        */
-       memset(&info->status.ack_signal, 0,
-              sizeof(struct ieee80211_tx_info) -
-              offsetof(struct ieee80211_tx_info, status.ack_signal));
-       BUILD_BUG_ON(offsetof(struct ieee80211_tx_info,
-                             status.ack_signal) != 20);
-
-       if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
-               pad = entry_data->align[0];
-
-       /* walk through the rates array and adjust the counts */
-       count = payload->tries;
-       for (idx = 0; idx < 4; idx++) {
-               if (count >= info->status.rates[idx].count) {
-                       count -= info->status.rates[idx].count;
-               } else if (count > 0) {
-                       info->status.rates[idx].count = count;
-                       count = 0;
-               } else {
-                       info->status.rates[idx].idx = -1;
-                       info->status.rates[idx].count = 0;
-               }
-       }
-
-       if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
-            !(payload->status & P54_TX_FAILED))
-               info->flags |= IEEE80211_TX_STAT_ACK;
-       if (payload->status & P54_TX_PSM_CANCELLED)
-               info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
-       info->status.ack_signal = p54_rssi_to_dbm(priv,
-                                                 (int)payload->ack_rssi);
-
-       /* Undo all changes to the frame. */
-       switch (entry_data->key_type) {
-       case P54_CRYPTO_TKIPMICHAEL: {
-               u8 *iv = (u8 *)(entry_data->align + pad +
-                               entry_data->crypt_offset);
-
-               /* Restore the original TKIP IV. */
-               iv[2] = iv[0];
-               iv[0] = iv[1];
-               iv[1] = (iv[0] | 0x20) & 0x7f;  /* WEPSeed - 8.3.2.2 */
-
-               frame_len -= 12; /* remove TKIP_MMIC + TKIP_ICV */
-               break;
-               }
-       case P54_CRYPTO_AESCCMP:
-               frame_len -= 8; /* remove CCMP_MIC */
-               break;
-       case P54_CRYPTO_WEP:
-               frame_len -= 4; /* remove WEP_ICV */
-               break;
-       }
-
-       skb_trim(entry, frame_len);
-       skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data));
-       ieee80211_tx_status_irqsafe(priv->hw, entry);
-}
-
-static void p54_rx_eeprom_readback(struct p54_common *priv,
-                                  struct sk_buff *skb)
-{
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-       struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data;
-       struct sk_buff *tmp;
-
-       if (!priv->eeprom)
-               return ;
-
-       if (priv->fw_var >= 0x509) {
-               memcpy(priv->eeprom, eeprom->v2.data,
-                      le16_to_cpu(eeprom->v2.len));
-       } else {
-               memcpy(priv->eeprom, eeprom->v1.data,
-                      le16_to_cpu(eeprom->v1.len));
-       }
-
-       priv->eeprom = NULL;
-       tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
-       dev_kfree_skb_any(tmp);
-       complete(&priv->eeprom_comp);
-}
-
-static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
-{
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-       struct p54_statistics *stats = (struct p54_statistics *) hdr->data;
-       struct sk_buff *tmp;
-       struct ieee80211_channel *chan;
-       unsigned int i, rssi, tx, cca, dtime, dtotal, dcca, dtx, drssi, unit;
-       u32 tsf32;
-
-       if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED))
-               return ;
-
-       tsf32 = le32_to_cpu(stats->tsf32);
-       if (tsf32 < priv->tsf_low32)
-               priv->tsf_high32++;
-       priv->tsf_low32 = tsf32;
-
-       priv->stats.dot11RTSFailureCount = le32_to_cpu(stats->rts_fail);
-       priv->stats.dot11RTSSuccessCount = le32_to_cpu(stats->rts_success);
-       priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs);
-
-       priv->noise = p54_rssi_to_dbm(priv, le32_to_cpu(stats->noise));
-
-       /*
-        * STSW450X LMAC API page 26 - 3.8 Statistics
-        * "The exact measurement period can be derived from the
-        * timestamp member".
-        */
-       dtime = tsf32 - priv->survey_raw.timestamp;
-
-       /*
-        * STSW450X LMAC API page 26 - 3.8.1 Noise histogram
-        * The LMAC samples RSSI, CCA and transmit state at regular
-        * periods (typically 8 times per 1k [as in 1024] usec).
-        */
-       cca = le32_to_cpu(stats->sample_cca);
-       tx = le32_to_cpu(stats->sample_tx);
-       rssi = 0;
-       for (i = 0; i < ARRAY_SIZE(stats->sample_noise); i++)
-               rssi += le32_to_cpu(stats->sample_noise[i]);
-
-       dcca = cca - priv->survey_raw.cached_cca;
-       drssi = rssi - priv->survey_raw.cached_rssi;
-       dtx = tx - priv->survey_raw.cached_tx;
-       dtotal = dcca + drssi + dtx;
-
-       /*
-        * update statistics when more than a second is over since the
-        * last call, or when a update is badly needed.
-        */
-       if (dtotal && (priv->update_stats || dtime >= USEC_PER_SEC) &&
-           dtime >= dtotal) {
-               priv->survey_raw.timestamp = tsf32;
-               priv->update_stats = false;
-               unit = dtime / dtotal;
-
-               if (dcca) {
-                       priv->survey_raw.cca += dcca * unit;
-                       priv->survey_raw.cached_cca = cca;
-               }
-               if (dtx) {
-                       priv->survey_raw.tx += dtx * unit;
-                       priv->survey_raw.cached_tx = tx;
-               }
-               if (drssi) {
-                       priv->survey_raw.rssi += drssi * unit;
-                       priv->survey_raw.cached_rssi = rssi;
-               }
-
-               /* 1024 usec / 8 times = 128 usec / time */
-               if (!(priv->phy_ps || priv->phy_idle))
-                       priv->survey_raw.active += dtotal * unit;
-               else
-                       priv->survey_raw.active += (dcca + dtx) * unit;
-       }
-
-       chan = priv->curchan;
-       if (chan) {
-               struct survey_info *survey = &priv->survey[chan->hw_value];
-               survey->noise = clamp(priv->noise, -128, 127);
-               survey->time = priv->survey_raw.active;
-               survey->time_tx = priv->survey_raw.tx;
-               survey->time_busy = priv->survey_raw.tx +
-                       priv->survey_raw.cca;
-               do_div(survey->time, 1024);
-               do_div(survey->time_tx, 1024);
-               do_div(survey->time_busy, 1024);
-       }
-
-       tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
-       dev_kfree_skb_any(tmp);
-       complete(&priv->stat_comp);
-}
-
-static void p54_rx_trap(struct p54_common *priv, struct sk_buff *skb)
-{
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-       struct p54_trap *trap = (struct p54_trap *) hdr->data;
-       u16 event = le16_to_cpu(trap->event);
-       u16 freq = le16_to_cpu(trap->frequency);
-
-       switch (event) {
-       case P54_TRAP_BEACON_TX:
-               break;
-       case P54_TRAP_RADAR:
-               wiphy_info(priv->hw->wiphy, "radar (freq:%d MHz)\n", freq);
-               break;
-       case P54_TRAP_NO_BEACON:
-               if (priv->vif)
-                       ieee80211_beacon_loss(priv->vif);
-               break;
-       case P54_TRAP_SCAN:
-               break;
-       case P54_TRAP_TBTT:
-               break;
-       case P54_TRAP_TIMER:
-               break;
-       case P54_TRAP_FAA_RADIO_OFF:
-               wiphy_rfkill_set_hw_state(priv->hw->wiphy, true);
-               break;
-       case P54_TRAP_FAA_RADIO_ON:
-               wiphy_rfkill_set_hw_state(priv->hw->wiphy, false);
-               break;
-       default:
-               wiphy_info(priv->hw->wiphy, "received event:%x freq:%d\n",
-                          event, freq);
-               break;
-       }
-}
-
-static int p54_rx_control(struct p54_common *priv, struct sk_buff *skb)
-{
-       struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
-
-       switch (le16_to_cpu(hdr->type)) {
-       case P54_CONTROL_TYPE_TXDONE:
-               p54_rx_frame_sent(priv, skb);
-               break;
-       case P54_CONTROL_TYPE_TRAP:
-               p54_rx_trap(priv, skb);
-               break;
-       case P54_CONTROL_TYPE_BBP:
-               break;
-       case P54_CONTROL_TYPE_STAT_READBACK:
-               p54_rx_stats(priv, skb);
-               break;
-       case P54_CONTROL_TYPE_EEPROM_READBACK:
-               p54_rx_eeprom_readback(priv, skb);
-               break;
-       default:
-               wiphy_debug(priv->hw->wiphy,
-                           "not handling 0x%02x type control frame\n",
-                           le16_to_cpu(hdr->type));
-               break;
-       }
-       return 0;
-}
-
-/* returns zero if skb can be reused */
-int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
-       struct p54_common *priv = dev->priv;
-       u16 type = le16_to_cpu(*((__le16 *)skb->data));
-
-       if (type & P54_HDR_FLAG_CONTROL)
-               return p54_rx_control(priv, skb);
-       else
-               return p54_rx_data(priv, skb);
-}
-EXPORT_SYMBOL_GPL(p54_rx);
-
-static void p54_tx_80211_header(struct p54_common *priv, struct sk_buff *skb,
-                               struct ieee80211_tx_info *info,
-                               struct ieee80211_sta *sta,
-                               u8 *queue, u32 *extra_len, u16 *flags, u16 *aid,
-                               bool *burst_possible)
-{
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-
-       if (ieee80211_is_data_qos(hdr->frame_control))
-               *burst_possible = true;
-       else
-               *burst_possible = false;
-
-       if (!(info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
-               *flags |= P54_HDR_FLAG_DATA_OUT_SEQNR;
-
-       if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER)
-               *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
-
-       if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT)
-               *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL;
-
-       *queue = skb_get_queue_mapping(skb) + P54_QUEUE_DATA;
-
-       switch (priv->mode) {
-       case NL80211_IFTYPE_MONITOR:
-               /*
-                * We have to set P54_HDR_FLAG_DATA_OUT_PROMISC for
-                * every frame in promiscuous/monitor mode.
-                * see STSW45x0C LMAC API - page 12.
-                */
-               *aid = 0;
-               *flags |= P54_HDR_FLAG_DATA_OUT_PROMISC;
-               break;
-       case NL80211_IFTYPE_STATION:
-               *aid = 1;
-               break;
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_ADHOC:
-       case NL80211_IFTYPE_MESH_POINT:
-               if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
-                       *aid = 0;
-                       *queue = P54_QUEUE_CAB;
-                       return;
-               }
-
-               if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) {
-                       if (ieee80211_is_probe_resp(hdr->frame_control)) {
-                               *aid = 0;
-                               *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP |
-                                         P54_HDR_FLAG_DATA_OUT_NOCANCEL;
-                               return;
-                       } else if (ieee80211_is_beacon(hdr->frame_control)) {
-                               *aid = 0;
-
-                               if (info->flags & IEEE80211_TX_CTL_INJECTED) {
-                                       /*
-                                        * Injecting beacons on top of a AP is
-                                        * not a good idea... nevertheless,
-                                        * it should be doable.
-                                        */
-
-                                       return;
-                               }
-
-                               *flags |= P54_HDR_FLAG_DATA_OUT_TIMESTAMP;
-                               *queue = P54_QUEUE_BEACON;
-                               *extra_len = IEEE80211_MAX_TIM_LEN;
-                               return;
-                       }
-               }
-
-               if (sta)
-                       *aid = sta->aid;
-               break;
-       }
-}
-
-static u8 p54_convert_algo(u32 cipher)
-{
-       switch (cipher) {
-       case WLAN_CIPHER_SUITE_WEP40:
-       case WLAN_CIPHER_SUITE_WEP104:
-               return P54_CRYPTO_WEP;
-       case WLAN_CIPHER_SUITE_TKIP:
-               return P54_CRYPTO_TKIPMICHAEL;
-       case WLAN_CIPHER_SUITE_CCMP:
-               return P54_CRYPTO_AESCCMP;
-       default:
-               return 0;
-       }
-}
-
-void p54_tx_80211(struct ieee80211_hw *dev,
-                 struct ieee80211_tx_control *control,
-                 struct sk_buff *skb)
-{
-       struct p54_common *priv = dev->priv;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct p54_tx_info *p54info;
-       struct p54_hdr *hdr;
-       struct p54_tx_data *txhdr;
-       unsigned int padding, len, extra_len = 0;
-       int i, j, ridx;
-       u16 hdr_flags = 0, aid = 0;
-       u8 rate, queue = 0, crypt_offset = 0;
-       u8 cts_rate = 0x20;
-       u8 rc_flags;
-       u8 calculated_tries[4];
-       u8 nrates = 0, nremaining = 8;
-       bool burst_allowed = false;
-
-       p54_tx_80211_header(priv, skb, info, control->sta, &queue, &extra_len,
-                           &hdr_flags, &aid, &burst_allowed);
-
-       if (p54_tx_qos_accounting_alloc(priv, skb, queue)) {
-               ieee80211_free_txskb(dev, skb);
-               return;
-       }
-
-       padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3;
-       len = skb->len;
-
-       if (info->control.hw_key) {
-               crypt_offset = ieee80211_get_hdrlen_from_skb(skb);
-               if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
-                       u8 *iv = (u8 *)(skb->data + crypt_offset);
-                       /*
-                        * The firmware excepts that the IV has to have
-                        * this special format
-                        */
-                       iv[1] = iv[0];
-                       iv[0] = iv[2];
-                       iv[2] = 0;
-               }
-       }
-
-       txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding);
-       hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr));
-
-       if (padding)
-               hdr_flags |= P54_HDR_FLAG_DATA_ALIGN;
-       hdr->type = cpu_to_le16(aid);
-       hdr->rts_tries = info->control.rates[0].count;
-
-       /*
-        * we register the rates in perfect order, and
-        * RTS/CTS won't happen on 5 GHz
-        */
-       cts_rate = info->control.rts_cts_rate_idx;
-
-       memset(&txhdr->rateset, 0, sizeof(txhdr->rateset));
-
-       /* see how many rates got used */
-       for (i = 0; i < dev->max_rates; i++) {
-               if (info->control.rates[i].idx < 0)
-                       break;
-               nrates++;
-       }
-
-       /* limit tries to 8/nrates per rate */
-       for (i = 0; i < nrates; i++) {
-               /*
-                * The magic expression here is equivalent to 8/nrates for
-                * all values that matter, but avoids division and jumps.
-                * Note that nrates can only take the values 1 through 4.
-                */
-               calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1,
-                                                info->control.rates[i].count);
-               nremaining -= calculated_tries[i];
-       }
-
-       /* if there are tries left, distribute from back to front */
-       for (i = nrates - 1; nremaining > 0 && i >= 0; i--) {
-               int tmp = info->control.rates[i].count - calculated_tries[i];
-
-               if (tmp <= 0)
-                       continue;
-               /* RC requested more tries at this rate */
-
-               tmp = min_t(int, tmp, nremaining);
-               calculated_tries[i] += tmp;
-               nremaining -= tmp;
-       }
-
-       ridx = 0;
-       for (i = 0; i < nrates && ridx < 8; i++) {
-               /* we register the rates in perfect order */
-               rate = info->control.rates[i].idx;
-               if (info->band == IEEE80211_BAND_5GHZ)
-                       rate += 4;
-
-               /* store the count we actually calculated for TX status */
-               info->control.rates[i].count = calculated_tries[i];
-
-               rc_flags = info->control.rates[i].flags;
-               if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) {
-                       rate |= 0x10;
-                       cts_rate |= 0x10;
-               }
-               if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
-                       burst_allowed = false;
-                       rate |= 0x40;
-               } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
-                       rate |= 0x20;
-                       burst_allowed = false;
-               }
-               for (j = 0; j < calculated_tries[i] && ridx < 8; j++) {
-                       txhdr->rateset[ridx] = rate;
-                       ridx++;
-               }
-       }
-
-       if (burst_allowed)
-               hdr_flags |= P54_HDR_FLAG_DATA_OUT_BURST;
-
-       /* TODO: enable bursting */
-       hdr->flags = cpu_to_le16(hdr_flags);
-       hdr->tries = ridx;
-       txhdr->rts_rate_idx = 0;
-       if (info->control.hw_key) {
-               txhdr->key_type = p54_convert_algo(info->control.hw_key->cipher);
-               txhdr->key_len = min((u8)16, info->control.hw_key->keylen);
-               memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len);
-               if (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
-                       /* reserve space for the MIC key */
-                       len += 8;
-                       memcpy(skb_put(skb, 8), &(info->control.hw_key->key
-                               [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8);
-               }
-               /* reserve some space for ICV */
-               len += info->control.hw_key->icv_len;
-               memset(skb_put(skb, info->control.hw_key->icv_len), 0,
-                      info->control.hw_key->icv_len);
-       } else {
-               txhdr->key_type = 0;
-               txhdr->key_len = 0;
-       }
-       txhdr->crypt_offset = crypt_offset;
-       txhdr->hw_queue = queue;
-       txhdr->backlog = priv->tx_stats[queue].len - 1;
-       memset(txhdr->durations, 0, sizeof(txhdr->durations));
-       txhdr->tx_antenna = 2 & priv->tx_diversity_mask;
-       if (priv->rxhw == 5) {
-               txhdr->longbow.cts_rate = cts_rate;
-               txhdr->longbow.output_power = cpu_to_le16(priv->output_power);
-       } else {
-               txhdr->normal.output_power = priv->output_power;
-               txhdr->normal.cts_rate = cts_rate;
-       }
-       if (padding)
-               txhdr->align[0] = padding;
-
-       hdr->len = cpu_to_le16(len);
-       /* modifies skb->cb and with it info, so must be last! */
-       p54info = (void *) info->rate_driver_data;
-       p54info->extra_len = extra_len;
-
-       p54_tx(priv, skb);
-}