staging: brcm80211: removed log after kzalloc()/kmalloc() failure
[pandora-kernel.git] / drivers / staging / brcm80211 / brcmsmac / mac80211_if.c
index d6de44e..32d7abf 100644 (file)
 #define INT_LOCK(wl, flags)    spin_lock_irqsave(&(wl)->isr_lock, flags)
 #define INT_UNLOCK(wl, flags)  spin_unlock_irqrestore(&(wl)->isr_lock, flags)
 
-static void brcms_timer(unsigned long data);
-static void _brcms_timer(struct brcms_timer *t);
-
-
-static int ieee_hw_init(struct ieee80211_hw *hw);
-static int ieee_hw_rate_init(struct ieee80211_hw *hw);
-
-static int wl_linux_watchdog(void *ctx);
-
 /* Flags we support */
 #define MAC_FILTERS (FIF_PROMISC_IN_BSS | \
        FIF_ALLMULTI | \
@@ -72,20 +63,42 @@ static int wl_linux_watchdog(void *ctx);
        FIF_OTHER_BSS | \
        FIF_BCN_PRBRESP_PROMISC)
 
-static int n_adapters_found;
+#define CHAN2GHZ(channel, freqency, chflags)  { \
+       .band = IEEE80211_BAND_2GHZ, \
+       .center_freq = (freqency), \
+       .hw_value = (channel), \
+       .flags = chflags, \
+       .max_antenna_gain = 0, \
+       .max_power = 19, \
+}
+
+#define CHAN5GHZ(channel, chflags)  { \
+       .band = IEEE80211_BAND_5GHZ, \
+       .center_freq = 5000 + 5*(channel), \
+       .hw_value = (channel), \
+       .flags = chflags, \
+       .max_antenna_gain = 0, \
+       .max_power = 21, \
+}
+
+#define RATE(rate100m, _flags) { \
+       .bitrate = (rate100m), \
+       .flags = (_flags), \
+       .hw_value = (rate100m / 5), \
+}
 
-static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev);
-static void brcms_release_fw(struct brcms_info *wl);
+struct firmware_hdr {
+       u32 offset;
+       u32 len;
+       u32 idx;
+};
 
-/* local prototypes */
-static void brcms_dpc(unsigned long data);
-static irqreturn_t brcms_isr(int irq, void *dev_id);
+static const char * const brcms_firmwares[MAX_FW_IMAGES] = {
+       "brcm/bcm43xx",
+       NULL
+};
 
-static int __devinit brcms_pci_probe(struct pci_dev *pdev,
-                                 const struct pci_device_id *ent);
-static void brcms_remove(struct pci_dev *pdev);
-static void brcms_free(struct brcms_info *wl);
-static void brcms_set_basic_rate(struct wl_rateset *rs, u16 rate, bool is_br);
+static int n_adapters_found;
 
 MODULE_AUTHOR("Broadcom Corporation");
 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
@@ -94,11 +107,10 @@ MODULE_LICENSE("Dual BSD/GPL");
 
 /* recognized PCI IDs */
 static DEFINE_PCI_DEVICE_TABLE(brcms_pci_id_table) = {
-       {PCI_VENDOR_ID_BROADCOM, 0x4357, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},      /* 43225 2G */
-       {PCI_VENDOR_ID_BROADCOM, 0x4353, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},      /* 43224 DUAL */
-       {PCI_VENDOR_ID_BROADCOM, 0x4727, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},      /* 4313 DUAL */
-       /* 43224 Ven */
-       {PCI_VENDOR_ID_BROADCOM, 0x0576, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, /* 43225 2G */
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, /* 43224 DUAL */
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) }, /* 4313 DUAL */
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, /* 43224 Ven */
        {0}
 };
 
@@ -107,54 +119,172 @@ MODULE_DEVICE_TABLE(pci, brcms_pci_id_table);
 #ifdef BCMDBG
 static int msglevel = 0xdeadbeef;
 module_param(msglevel, int, 0);
-static int phymsglevel = 0xdeadbeef;
-module_param(phymsglevel, int, 0);
 #endif                         /* BCMDBG */
 
-#define HW_TO_WL(hw)    (hw->priv)
-#define WL_TO_HW(wl)     (wl->pub->ieee_hw)
-
-/* MAC80211 callback functions */
-static int brcms_ops_start(struct ieee80211_hw *hw);
-static void brcms_ops_stop(struct ieee80211_hw *hw);
-static int brcms_ops_add_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif);
-static void brcms_ops_remove_interface(struct ieee80211_hw *hw,
-                                   struct ieee80211_vif *vif);
-static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed);
-static void brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
-                                   struct ieee80211_vif *vif,
-                                   struct ieee80211_bss_conf *info,
-                                   u32 changed);
-static void brcms_ops_configure_filter(struct ieee80211_hw *hw,
-                                   unsigned int changed_flags,
-                                   unsigned int *total_flags, u64 multicast);
-static int brcms_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
-                         bool set);
-static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw);
-static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw);
-static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf);
-static int brcms_ops_get_stats(struct ieee80211_hw *hw,
-                           struct ieee80211_low_level_stats *stats);
-static void brcms_ops_sta_notify(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif,
-                             enum sta_notify_cmd cmd,
-                             struct ieee80211_sta *sta);
-static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
-                         const struct ieee80211_tx_queue_params *params);
-static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw);
-static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                     struct ieee80211_sta *sta);
-static int brcms_ops_sta_remove(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               struct ieee80211_sta *sta);
-static int brcms_ops_ampdu_action(struct ieee80211_hw *hw,
-                              struct ieee80211_vif *vif,
-                              enum ieee80211_ampdu_mlme_action action,
-                              struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                              u8 buf_size);
-static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw);
-static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop);
+static struct ieee80211_channel brcms_2ghz_chantable[] = {
+       CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN2GHZ(5, 2432, 0),
+       CHAN2GHZ(6, 2437, 0),
+       CHAN2GHZ(7, 2442, 0),
+       CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN2GHZ(12, 2467,
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN2GHZ(13, 2472,
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN2GHZ(14, 2484,
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
+};
+
+static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
+       /* UNII-1 */
+       CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
+       /* UNII-2 */
+       CHAN5GHZ(52,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(56,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN5GHZ(60,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(64,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+       /* MID */
+       CHAN5GHZ(100,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(104,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN5GHZ(108,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(112,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN5GHZ(116,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(120,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN5GHZ(124,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(128,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN5GHZ(132,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(136,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN5GHZ(140,
+                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
+                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
+                IEEE80211_CHAN_NO_HT40MINUS),
+       /* UNII-3 */
+       CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS),
+       CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS),
+       CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
+};
+
+/*
+ * The rate table is used for both 2.4G and 5G rates. The
+ * latter being a subset as it does not support CCK rates.
+ */
+static struct ieee80211_rate legacy_ratetable[] = {
+       RATE(10, 0),
+       RATE(20, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(55, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(110, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(60, 0),
+       RATE(90, 0),
+       RATE(120, 0),
+       RATE(180, 0),
+       RATE(240, 0),
+       RATE(360, 0),
+       RATE(480, 0),
+       RATE(540, 0),
+};
+
+static struct ieee80211_supported_band brcms_band_2GHz_nphy = {
+       .band = IEEE80211_BAND_2GHZ,
+       .channels = brcms_2ghz_chantable,
+       .n_channels = ARRAY_SIZE(brcms_2ghz_chantable),
+       .bitrates = legacy_ratetable,
+       .n_bitrates = ARRAY_SIZE(legacy_ratetable),
+       .ht_cap = {
+                  /* from include/linux/ieee80211.h */
+                  .cap = IEEE80211_HT_CAP_GRN_FLD |
+                  IEEE80211_HT_CAP_SGI_20 |
+                  IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
+                  .ht_supported = true,
+                  .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+                  .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
+                  .mcs = {
+                          /* placeholders for now */
+                          .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
+                          .rx_highest = 500,
+                          .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
+                  }
+};
+
+static struct ieee80211_supported_band brcms_band_5GHz_nphy = {
+       .band = IEEE80211_BAND_5GHZ,
+       .channels = brcms_5ghz_nphy_chantable,
+       .n_channels = ARRAY_SIZE(brcms_5ghz_nphy_chantable),
+       .bitrates = legacy_ratetable + BRCMS_LEGACY_5G_RATE_OFFSET,
+       .n_bitrates = ARRAY_SIZE(legacy_ratetable) -
+                       BRCMS_LEGACY_5G_RATE_OFFSET,
+       .ht_cap = {
+                  .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
+                         IEEE80211_HT_CAP_SGI_40 |
+                         IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */
+                  .ht_supported = true,
+                  .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+                  .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
+                  .mcs = {
+                          /* placeholders for now */
+                          .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
+                          .rx_highest = 500,
+                          .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
+                  }
+};
+
+/* flags the given rate in rateset as requested */
+static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br)
+{
+       u32 i;
+
+       for (i = 0; i < rs->count; i++) {
+               if (rate != (rs->rates[i] & 0x7f))
+                       continue;
+
+               if (is_br)
+                       rs->rates[i] |= BRCMS_RATE_FLAG;
+               else
+                       rs->rates[i] &= BRCMS_RATE_MASK;
+               return;
+       }
+}
 
 static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
@@ -175,9 +305,6 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
 {
        struct brcms_info *wl = hw->priv;
        bool blocked;
-       /*
-         struct ieee80211_channel *curchan = hw->conf.channel;
-       */
 
        ieee80211_wake_queues(hw);
        LOCK(wl);
@@ -211,15 +338,15 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
                return -EOPNOTSUPP;
        }
 
-       wl = HW_TO_WL(hw);
+       wl = hw->priv;
        LOCK(wl);
        err = brcms_up(wl);
        UNLOCK(wl);
 
-       if (err != 0) {
+       if (err != 0)
                wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
                          err);
-       }
+
        return err;
 }
 
@@ -228,7 +355,7 @@ brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct brcms_info *wl;
 
-       wl = HW_TO_WL(hw);
+       wl = hw->priv;
 
        /* put driver in down state */
        LOCK(wl);
@@ -236,52 +363,18 @@ brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        UNLOCK(wl);
 }
 
-/*
- * precondition: perimeter lock has been acquired
- */
-static int
-ieee_set_channel(struct ieee80211_hw *hw, struct ieee80211_channel *chan,
-                enum nl80211_channel_type type)
-{
-       struct brcms_info *wl = HW_TO_WL(hw);
-       int err = 0;
-
-       switch (type) {
-       case NL80211_CHAN_HT20:
-       case NL80211_CHAN_NO_HT:
-               err = brcms_c_set(wl->wlc, BRCM_SET_CHANNEL, chan->hw_value);
-               break;
-       case NL80211_CHAN_HT40MINUS:
-       case NL80211_CHAN_HT40PLUS:
-               wiphy_err(hw->wiphy,
-                         "%s: Need to implement 40 Mhz Channels!\n", __func__);
-               err = 1;
-               break;
-       }
-
-       if (err)
-               return -EIO;
-       return err;
-}
-
 static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct ieee80211_conf *conf = &hw->conf;
-       struct brcms_info *wl = HW_TO_WL(hw);
+       struct brcms_info *wl = hw->priv;
        int err = 0;
        int new_int;
        struct wiphy *wiphy = hw->wiphy;
 
        LOCK(wl);
        if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
-               if (brcms_c_set_par(wl->wlc, IOV_BCN_LI_BCN,
-                                   conf->listen_interval) < 0) {
-                       wiphy_err(wiphy, "%s: Error setting listen_interval\n",
-                                 __func__);
-                       err = -EIO;
-                       goto config_out;
-               }
-               brcms_c_get_par(wl->wlc, IOV_BCN_LI_BCN, &new_int);
+               brcms_c_set_beacon_listen_interval(wl->wlc,
+                                                  conf->listen_interval);
        }
        if (changed & IEEE80211_CONF_CHANGE_MONITOR)
                wiphy_err(wiphy, "%s: change monitor mode: %s (implement)\n",
@@ -293,37 +386,30 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
                          "true" : "false");
 
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
-               if (brcms_c_set_par(wl->wlc, IOV_QTXPOWER,
-                                   conf->power_level * 4) < 0) {
+               err = brcms_c_set_tx_power(wl->wlc, conf->power_level);
+               if (err < 0) {
                        wiphy_err(wiphy, "%s: Error setting power_level\n",
                                  __func__);
-                       err = -EIO;
                        goto config_out;
                }
-               brcms_c_get_par(wl->wlc, IOV_QTXPOWER, &new_int);
-               if (new_int != (conf->power_level * 4))
+               new_int = brcms_c_get_tx_power(wl->wlc);
+               if (new_int != conf->power_level)
                        wiphy_err(wiphy, "%s: Power level req != actual, %d %d"
-                                 "\n", __func__, conf->power_level * 4,
+                                 "\n", __func__, conf->power_level,
                                  new_int);
        }
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-               err = ieee_set_channel(hw, conf->channel, conf->channel_type);
-       }
-       if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) {
-               if (brcms_c_set
-                   (wl->wlc, BRCM_SET_SRL,
-                    conf->short_frame_max_tx_count) < 0) {
-                       wiphy_err(wiphy, "%s: Error setting srl\n", __func__);
-                       err = -EIO;
-                       goto config_out;
-               }
-               if (brcms_c_set(wl->wlc, BRCM_SET_LRL,
-                               conf->long_frame_max_tx_count) < 0) {
-                       wiphy_err(wiphy, "%s: Error setting lrl\n", __func__);
-                       err = -EIO;
-                       goto config_out;
-               }
+               if (conf->channel_type == NL80211_CHAN_HT20 ||
+                   conf->channel_type == NL80211_CHAN_NO_HT)
+                       err = brcms_c_set_channel(wl->wlc,
+                                                 conf->channel->hw_value);
+               else
+                       err = -ENOTSUPP;
        }
+       if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS)
+               err = brcms_c_set_rate_limit(wl->wlc,
+                                            conf->short_frame_max_tx_count,
+                                            conf->long_frame_max_tx_count);
 
  config_out:
        UNLOCK(wl);
@@ -335,9 +421,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
                        struct ieee80211_vif *vif,
                        struct ieee80211_bss_conf *info, u32 changed)
 {
-       struct brcms_info *wl = HW_TO_WL(hw);
+       struct brcms_info *wl = hw->priv;
        struct wiphy *wiphy = hw->wiphy;
-       int val;
 
        if (changed & BSS_CHANGED_ASSOC) {
                /* association status changed (associated/disassociated)
@@ -350,13 +435,15 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
                UNLOCK(wl);
        }
        if (changed & BSS_CHANGED_ERP_SLOT) {
+               s8 val;
+
                /* slot timing changed */
                if (info->use_short_slot)
                        val = 1;
                else
                        val = 0;
                LOCK(wl);
-               brcms_c_set(wl->wlc, BRCMS_SET_SHORTSLOT_OVERRIDE, val);
+               brcms_c_set_shortslot_override(wl->wlc, val);
                UNLOCK(wl);
        }
 
@@ -377,19 +464,14 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
                struct ieee80211_supported_band *bi;
                u32 br_mask, i;
                u16 rate;
-               struct wl_rateset rs;
+               struct brcm_rateset rs;
                int error;
 
                /* retrieve the current rates */
                LOCK(wl);
-               error = brcms_c_ioctl(wl->wlc, BRCM_GET_CURR_RATESET,
-                                 &rs, sizeof(rs), NULL);
+               brcms_c_get_current_rateset(wl->wlc, &rs);
                UNLOCK(wl);
-               if (error) {
-                       wiphy_err(wiphy, "%s: retrieve rateset failed: %d\n",
-                                 __func__, error);
-                       return;
-               }
+
                br_mask = info->basic_rates;
                bi = hw->wiphy->bands[brcms_c_get_curband(wl->wlc)];
                for (i = 0; i < bi->n_bitrates; i++) {
@@ -403,48 +485,54 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
 
                /* update the rate set */
                LOCK(wl);
-               brcms_c_ioctl(wl->wlc, BRCM_SET_RATESET, &rs, sizeof(rs), NULL);
+               error = brcms_c_set_rateset(wl->wlc, &rs);
                UNLOCK(wl);
+               if (error)
+                       wiphy_err(wiphy, "changing basic rates failed: %d\n",
+                                 error);
        }
        if (changed & BSS_CHANGED_BEACON_INT) {
                /* Beacon interval changed */
                LOCK(wl);
-               brcms_c_set(wl->wlc, BRCM_SET_BCNPRD, info->beacon_int);
+               brcms_c_set_beacon_period(wl->wlc, info->beacon_int);
                UNLOCK(wl);
        }
        if (changed & BSS_CHANGED_BSSID) {
                /* BSSID changed, for whatever reason (IBSS and managed mode) */
                LOCK(wl);
-               brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET,
-                                 info->bssid);
+               brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);
                UNLOCK(wl);
        }
-       if (changed & BSS_CHANGED_BEACON) {
+       if (changed & BSS_CHANGED_BEACON)
                /* Beacon data changed, retrieve new beacon (beaconing modes) */
                wiphy_err(wiphy, "%s: beacon changed\n", __func__);
-       }
+
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
                /* Beaconing should be enabled/disabled (beaconing modes) */
                wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__,
                          info->enable_beacon ? "true" : "false");
        }
+
        if (changed & BSS_CHANGED_CQM) {
                /* Connection quality monitor config changed */
                wiphy_err(wiphy, "%s: cqm change: threshold %d, hys %d "
                          " (implement)\n", __func__, info->cqm_rssi_thold,
                          info->cqm_rssi_hyst);
        }
+
        if (changed & BSS_CHANGED_IBSS) {
                /* IBSS join status changed */
                wiphy_err(wiphy, "%s: IBSS joined: %s (implement)\n", __func__,
                          info->ibss_joined ? "true" : "false");
        }
+
        if (changed & BSS_CHANGED_ARP_FILTER) {
                /* Hardware ARP filter address list or state changed */
                wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d"
                          " (implement)\n", __func__, info->arp_filter_enabled ?
                          "true" : "false", info->arp_addr_cnt);
        }
+
        if (changed & BSS_CHANGED_QOS) {
                /*
                 * QoS for this association was enabled/disabled.
@@ -602,7 +690,10 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
            IEEE80211_HT_CAP_SGI_20 |
            IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT;
 
-       /* minstrel_ht initiates addBA on our behalf by calling ieee80211_start_tx_ba_session() */
+       /*
+        * minstrel_ht initiates addBA on our behalf by calling
+        * ieee80211_start_tx_ba_session()
+        */
        return 0;
 }
 
@@ -640,7 +731,10 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
                                  tid);
                        return -EINVAL;
                }
-               /* Future improvement: Use the starting sequence number provided ... */
+               /*
+                * Future improvement:
+                *   Use the starting sequence number provided ...
+                */
                *ssn = 0;
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
                break;
@@ -675,7 +769,7 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
 
 static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw)
 {
-       struct brcms_info *wl = HW_TO_WL(hw);
+       struct brcms_info *wl = hw->priv;
        bool blocked;
 
        LOCK(wl);
@@ -687,7 +781,7 @@ static void brcms_ops_rfkill_poll(struct ieee80211_hw *hw)
 
 static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
 {
-       struct brcms_info *wl = HW_TO_WL(hw);
+       struct brcms_info *wl = hw->priv;
 
        no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false");
 
@@ -729,328 +823,236 @@ static int brcms_set_hint(struct brcms_info *wl, char *abbrev)
        return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev);
 }
 
-/**
- * attach to the WL device.
- *
- * Attach to the WL device identified by vendor and device parameters.
- * regs is a host accessible memory address pointing to WL device registers.
- *
- * brcms_attach is not defined as static because in the case where no bus
- * is defined, wl_attach will never be called, and thus, gcc will issue
- * a warning that this function is defined but not used if we declare
- * it as static.
- *
- *
- * is called in brcms_pci_probe() context, therefore no locking required.
- */
-static struct brcms_info *brcms_attach(u16 vendor, u16 device,
-                                      unsigned long regs,
-                           uint bustype, void *btparam, uint irq)
+static void brcms_dpc(unsigned long data)
 {
-       struct brcms_info *wl = NULL;
-       int unit, err;
-       unsigned long base_addr;
-       struct ieee80211_hw *hw;
-       u8 perm[ETH_ALEN];
-
-       unit = n_adapters_found;
-       err = 0;
-
-       if (unit < 0) {
-               return NULL;
-       }
-
-       /* allocate private info */
-       hw = pci_get_drvdata(btparam);  /* btparam == pdev */
-       if (hw != NULL)
-               wl = hw->priv;
-       if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL))
-               return NULL;
-       wl->wiphy = hw->wiphy;
-
-       atomic_set(&wl->callbacks, 0);
+       struct brcms_info *wl;
 
-       /* setup the bottom half handler */
-       tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);
+       wl = (struct brcms_info *) data;
 
+       LOCK(wl);
 
+       /* call the common second level interrupt handler */
+       if (wl->pub->up) {
+               if (wl->resched) {
+                       unsigned long flags;
 
-       base_addr = regs;
+                       INT_LOCK(wl, flags);
+                       brcms_c_intrsupd(wl->wlc);
+                       INT_UNLOCK(wl, flags);
+               }
 
-       if (bustype == PCI_BUS || bustype == RPC_BUS) {
-               /* Do nothing */
-       } else {
-               bustype = PCI_BUS;
-               BCMMSG(wl->wiphy, "force to PCI\n");
+               wl->resched = brcms_c_dpc(wl->wlc, true);
        }
-       wl->bcm_bustype = bustype;
 
-       wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ);
-       if (wl->regsva == NULL) {
-               wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit);
-               goto fail;
-       }
-       spin_lock_init(&wl->lock);
-       spin_lock_init(&wl->isr_lock);
+       /* brcms_c_dpc() may bring the driver down */
+       if (!wl->pub->up)
+               goto done;
 
-       /* prepare ucode */
-       if (brcms_request_fw(wl, (struct pci_dev *)btparam) < 0) {
-               wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
-                         "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
-               brcms_release_fw(wl);
-               brcms_remove((struct pci_dev *)btparam);
-               return NULL;
-       }
+       /* re-schedule dpc */
+       if (wl->resched)
+               tasklet_schedule(&wl->tasklet);
+       else
+               /* re-enable interrupts */
+               brcms_intrson(wl);
 
-       /* common load-time initialization */
-       wl->wlc = brcms_c_attach((void *)wl, vendor, device, unit, false,
-                            wl->regsva, wl->bcm_bustype, btparam, &err);
-       brcms_release_fw(wl);
-       if (!wl->wlc) {
-               wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",
-                         KBUILD_MODNAME, err);
-               goto fail;
-       }
-       wl->pub = brcms_c_pub(wl->wlc);
+ done:
+       UNLOCK(wl);
+}
 
-       wl->pub->ieee_hw = hw;
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev)
+{
+       int status;
+       struct device *device = &pdev->dev;
+       char fw_name[100];
+       int i;
 
-       if (brcms_c_set_par(wl->wlc, IOV_MPC, 0) < 0) {
-               wiphy_err(wl->wiphy, "wl%d: Error setting MPC variable to 0\n",
-                         unit);
+       memset(&wl->fw, 0, sizeof(struct brcms_firmware));
+       for (i = 0; i < MAX_FW_IMAGES; i++) {
+               if (brcms_firmwares[i] == NULL)
+                       break;
+               sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],
+                       UCODE_LOADER_API_VER);
+               status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
+               if (status) {
+                       wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+                                 KBUILD_MODNAME, fw_name);
+                       return status;
+               }
+               sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],
+                       UCODE_LOADER_API_VER);
+               status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
+               if (status) {
+                       wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
+                                 KBUILD_MODNAME, fw_name);
+                       return status;
+               }
+               wl->fw.hdr_num_entries[i] =
+                   wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));
        }
+       wl->fw.fw_cnt = i;
+       return brcms_ucode_data_init(wl);
+}
 
-       /* register our interrupt handler */
-       if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
-               wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
-               goto fail;
+/*
+ * Precondition: Since this function is called in brcms_pci_probe() context,
+ * no locking is required.
+ */
+static void brcms_release_fw(struct brcms_info *wl)
+{
+       int i;
+       for (i = 0; i < MAX_FW_IMAGES; i++) {
+               release_firmware(wl->fw.fw_bin[i]);
+               release_firmware(wl->fw.fw_hdr[i]);
        }
-       wl->irq = irq;
+}
 
-       /* register module */
-       brcms_c_module_register(wl->pub, "linux", wl, wl_linux_watchdog, NULL);
+/**
+ * This function frees the WL per-device resources.
+ *
+ * This function frees resources owned by the WL device pointed to
+ * by the wl parameter.
+ *
+ * precondition: can both be called locked and unlocked
+ *
+ */
+static void brcms_free(struct brcms_info *wl)
+{
+       struct brcms_timer *t, *next;
 
-       if (ieee_hw_init(hw)) {
-               wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit,
-                         __func__);
-               goto fail;
-       }
+       /* free ucode data */
+       if (wl->fw.fw_cnt)
+               brcms_ucode_data_free();
+       if (wl->irq)
+               free_irq(wl->irq, wl);
 
-       memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN);
-       if (WARN_ON(!is_valid_ether_addr(perm)))
-               goto fail;
-       SET_IEEE80211_PERM_ADDR(hw, perm);
+       /* kill dpc */
+       tasklet_kill(&wl->tasklet);
 
-       err = ieee80211_register_hw(hw);
-       if (err) {
-               wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
-                         "%d\n", __func__, err);
-       }
+       if (wl->pub)
+               brcms_c_module_unregister(wl->pub, "linux", wl);
 
-       if (wl->pub->srom_ccode[0])
-               err = brcms_set_hint(wl, wl->pub->srom_ccode);
-       else
-               err = brcms_set_hint(wl, "US");
-       if (err) {
-               wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
-                         __func__, err);
+       /* free common resources */
+       if (wl->wlc) {
+               brcms_c_detach(wl->wlc);
+               wl->wlc = NULL;
+               wl->pub = NULL;
        }
 
-       n_adapters_found++;
-       return wl;
+       /* virtual interface deletion is deferred so we cannot spinwait */
 
-fail:
-       brcms_free(wl);
-       return NULL;
-}
+       /* wait for all pending callbacks to complete */
+       while (atomic_read(&wl->callbacks) > 0)
+               schedule();
 
+       /* free timers */
+       for (t = wl->timers; t; t = next) {
+               next = t->next;
+#ifdef BCMDBG
+               kfree(t->name);
+#endif
+               kfree(t);
+       }
 
+       /*
+        * unregister_netdev() calls get_stats() which may read chip
+        * registers so we cannot unmap the chip registers until
+        * after calling unregister_netdev() .
+        */
+       if (wl->regsva)
+               iounmap(wl->regsva);
 
-#define CHAN2GHZ(channel, freqency, chflags)  { \
-       .band = IEEE80211_BAND_2GHZ, \
-       .center_freq = (freqency), \
-       .hw_value = (channel), \
-       .flags = chflags, \
-       .max_antenna_gain = 0, \
-       .max_power = 19, \
+       wl->regsva = NULL;
 }
 
-static struct ieee80211_channel brcms_2ghz_chantable[] = {
-       CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN2GHZ(2, 2417, IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN2GHZ(3, 2422, IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN2GHZ(4, 2427, IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN2GHZ(5, 2432, 0),
-       CHAN2GHZ(6, 2437, 0),
-       CHAN2GHZ(7, 2442, 0),
-       CHAN2GHZ(8, 2447, IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN2GHZ(9, 2452, IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN2GHZ(10, 2457, IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN2GHZ(11, 2462, IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN2GHZ(12, 2467,
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN2GHZ(13, 2472,
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN2GHZ(14, 2484,
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
-};
+/*
+* called from both kernel as from this kernel module.
+* precondition: perimeter lock is not acquired.
+*/
+static void brcms_remove(struct pci_dev *pdev)
+{
+       struct brcms_info *wl;
+       struct ieee80211_hw *hw;
+       int status;
 
-#define CHAN5GHZ(channel, chflags)  { \
-       .band = IEEE80211_BAND_5GHZ, \
-       .center_freq = 5000 + 5*(channel), \
-       .hw_value = (channel), \
-       .flags = chflags, \
-       .max_antenna_gain = 0, \
-       .max_power = 21, \
-}
+       hw = pci_get_drvdata(pdev);
+       wl = hw->priv;
+       if (!wl) {
+               pr_err("wl: brcms_remove: pci_get_drvdata failed\n");
+               return;
+       }
 
-static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
-       /* UNII-1 */
-       CHAN5GHZ(36, IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(40, IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN5GHZ(44, IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(48, IEEE80211_CHAN_NO_HT40PLUS),
-       /* UNII-2 */
-       CHAN5GHZ(52,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(56,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN5GHZ(60,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(64,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
-       /* MID */
-       CHAN5GHZ(100,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(104,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN5GHZ(108,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(112,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN5GHZ(116,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(120,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN5GHZ(124,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(128,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN5GHZ(132,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(136,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN5GHZ(140,
-                IEEE80211_CHAN_RADAR | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_HT40PLUS |
-                IEEE80211_CHAN_NO_HT40MINUS),
-       /* UNII-3 */
-       CHAN5GHZ(149, IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(153, IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN5GHZ(157, IEEE80211_CHAN_NO_HT40MINUS),
-       CHAN5GHZ(161, IEEE80211_CHAN_NO_HT40PLUS),
-       CHAN5GHZ(165, IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
-};
+       LOCK(wl);
+       status = brcms_c_chipmatch(pdev->vendor, pdev->device);
+       UNLOCK(wl);
+       if (!status) {
+               wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch "
+                                    "failed\n");
+               return;
+       }
+       if (wl->wlc) {
+               wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
+               wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
+               ieee80211_unregister_hw(hw);
+               LOCK(wl);
+               brcms_down(wl);
+               UNLOCK(wl);
+       }
+       pci_disable_device(pdev);
 
-#define RATE(rate100m, _flags) { \
-       .bitrate = (rate100m), \
-       .flags = (_flags), \
-       .hw_value = (rate100m / 5), \
+       brcms_free(wl);
+
+       pci_set_drvdata(pdev, NULL);
+       ieee80211_free_hw(hw);
 }
 
-static struct ieee80211_rate legacy_ratetable[] = {
-       RATE(10, 0),
-       RATE(20, IEEE80211_RATE_SHORT_PREAMBLE),
-       RATE(55, IEEE80211_RATE_SHORT_PREAMBLE),
-       RATE(110, IEEE80211_RATE_SHORT_PREAMBLE),
-       RATE(60, 0),
-       RATE(90, 0),
-       RATE(120, 0),
-       RATE(180, 0),
-       RATE(240, 0),
-       RATE(360, 0),
-       RATE(480, 0),
-       RATE(540, 0),
-};
+static irqreturn_t brcms_isr(int irq, void *dev_id)
+{
+       struct brcms_info *wl;
+       bool ours, wantdpc;
+       unsigned long flags;
 
-static struct ieee80211_supported_band brcms_band_2GHz_nphy = {
-       .band = IEEE80211_BAND_2GHZ,
-       .channels = brcms_2ghz_chantable,
-       .n_channels = ARRAY_SIZE(brcms_2ghz_chantable),
-       .bitrates = legacy_ratetable,
-       .n_bitrates = ARRAY_SIZE(legacy_ratetable),
-       .ht_cap = {
-                  /* from include/linux/ieee80211.h */
-                  .cap = IEEE80211_HT_CAP_GRN_FLD |
-                  IEEE80211_HT_CAP_SGI_20 |
-                  IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
-                  .ht_supported = true,
-                  .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
-                  .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
-                  .mcs = {
-                          /* placeholders for now */
-                          .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
-                          .rx_highest = 500,
-                          .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
-                  }
-};
+       wl = (struct brcms_info *) dev_id;
 
-static struct ieee80211_supported_band brcms_band_5GHz_nphy = {
-       .band = IEEE80211_BAND_5GHZ,
-       .channels = brcms_5ghz_nphy_chantable,
-       .n_channels = ARRAY_SIZE(brcms_5ghz_nphy_chantable),
-       .bitrates = legacy_ratetable + 4,
-       .n_bitrates = ARRAY_SIZE(legacy_ratetable) - 4,
-       .ht_cap = {
-                  /* use IEEE80211_HT_CAP_* from include/linux/ieee80211.h */
-                  .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,     /* No 40 mhz yet */
-                  .ht_supported = true,
-                  .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
-                  .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
-                  .mcs = {
-                          /* placeholders for now */
-                          .rx_mask = {0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0},
-                          .rx_highest = 500,
-                          .tx_params = IEEE80211_HT_MCS_TX_DEFINED}
-                  }
-};
+       ISR_LOCK(wl, flags);
+
+       /* call common first level interrupt handler */
+       ours = brcms_c_isr(wl->wlc, &wantdpc);
+       if (ours) {
+               /* if more to do... */
+               if (wantdpc) {
+
+                       /* ...and call the second level interrupt handler */
+                       /* schedule dpc */
+                       tasklet_schedule(&wl->tasklet);
+               }
+       }
+
+       ISR_UNLOCK(wl, flags);
+
+       return IRQ_RETVAL(ours);
+}
 
 /*
  * is called in brcms_pci_probe() context, therefore no locking required.
  */
 static int ieee_hw_rate_init(struct ieee80211_hw *hw)
 {
-       struct brcms_info *wl = HW_TO_WL(hw);
+       struct brcms_info *wl = hw->priv;
        int has_5g;
-       char phy_list[4];
+       u16 phy_type;
 
        has_5g = 0;
 
        hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL;
        hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
 
-       if (brcms_c_get(wl->wlc, BRCM_GET_PHYLIST, (int *)&phy_list) < 0)
-               wiphy_err(hw->wiphy, "Phy list failed\n");
-
-       if (phy_list[0] == 'n' || phy_list[0] == 'c') {
-               if (phy_list[0] == 'c') {
+       phy_type = brcms_c_get_phy_type(wl->wlc, 0);
+       if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN) {
+               if (phy_type == PHY_TYPE_LCN) {
                        /* Single stream */
                        brcms_band_2GHz_nphy.ht_cap.mcs.rx_mask[1] = 0;
                        brcms_band_2GHz_nphy.ht_cap.mcs.rx_highest = 72;
@@ -1061,14 +1063,13 @@ static int ieee_hw_rate_init(struct ieee80211_hw *hw)
        }
 
        /* Assume all bands use the same phy.  True for 11n devices. */
-       if (NBANDS_PUB(wl->pub) > 1) {
+       if (wl->pub->_nbands > 1) {
                has_5g++;
-               if (phy_list[0] == 'n' || phy_list[0] == 'c') {
+               if (phy_type == PHY_TYPE_N || phy_type == PHY_TYPE_LCN)
                        hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
                            &brcms_band_5GHz_nphy;
-               } else {
+               else
                        return -EPERM;
-               }
        }
        return 0;
 }
@@ -1087,7 +1088,8 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
        hw->queues = N_TX_QUEUES;
        hw->max_rates = 2;      /* Primary rate and 1 fallback rate */
 
-       hw->channel_change_time = 7 * 1000;     /* channel change time is dependent on chip and band  */
+       /* channel change time is dependent on chip and band  */
+       hw->channel_change_time = 7 * 1000;
        hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 
        hw->rate_control_algorithm = "minstrel_ht";
@@ -1096,6 +1098,125 @@ static int ieee_hw_init(struct ieee80211_hw *hw)
        return ieee_hw_rate_init(hw);
 }
 
+/**
+ * attach to the WL device.
+ *
+ * Attach to the WL device identified by vendor and device parameters.
+ * regs is a host accessible memory address pointing to WL device registers.
+ *
+ * brcms_attach is not defined as static because in the case where no bus
+ * is defined, wl_attach will never be called, and thus, gcc will issue
+ * a warning that this function is defined but not used if we declare
+ * it as static.
+ *
+ *
+ * is called in brcms_pci_probe() context, therefore no locking required.
+ */
+static struct brcms_info *brcms_attach(u16 vendor, u16 device,
+                                      resource_size_t regs,
+                                      struct pci_dev *btparam, uint irq)
+{
+       struct brcms_info *wl = NULL;
+       int unit, err;
+       struct ieee80211_hw *hw;
+       u8 perm[ETH_ALEN];
+
+       unit = n_adapters_found;
+       err = 0;
+
+       if (unit < 0)
+               return NULL;
+
+       /* allocate private info */
+       hw = pci_get_drvdata(btparam);  /* btparam == pdev */
+       if (hw != NULL)
+               wl = hw->priv;
+       if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL))
+               return NULL;
+       wl->wiphy = hw->wiphy;
+
+       atomic_set(&wl->callbacks, 0);
+
+       /* setup the bottom half handler */
+       tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);
+
+       wl->regsva = ioremap_nocache(regs, PCI_BAR0_WINSZ);
+       if (wl->regsva == NULL) {
+               wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit);
+               goto fail;
+       }
+       spin_lock_init(&wl->lock);
+       spin_lock_init(&wl->isr_lock);
+
+       /* prepare ucode */
+       if (brcms_request_fw(wl, btparam) < 0) {
+               wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
+                         "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
+               brcms_release_fw(wl);
+               brcms_remove(btparam);
+               return NULL;
+       }
+
+       /* common load-time initialization */
+       wl->wlc = brcms_c_attach(wl, vendor, device, unit, false,
+                                wl->regsva, btparam, &err);
+       brcms_release_fw(wl);
+       if (!wl->wlc) {
+               wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n",
+                         KBUILD_MODNAME, err);
+               goto fail;
+       }
+       wl->pub = brcms_c_pub(wl->wlc);
+
+       wl->pub->ieee_hw = hw;
+
+       /* disable mpc */
+       brcms_c_set_radio_mpc(wl->wlc, false);
+
+       /* register our interrupt handler */
+       if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
+               wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
+               goto fail;
+       }
+       wl->irq = irq;
+
+       /* register module */
+       brcms_c_module_register(wl->pub, "linux", wl, NULL);
+
+       if (ieee_hw_init(hw)) {
+               wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit,
+                         __func__);
+               goto fail;
+       }
+
+       memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN);
+       if (WARN_ON(!is_valid_ether_addr(perm)))
+               goto fail;
+       SET_IEEE80211_PERM_ADDR(hw, perm);
+
+       err = ieee80211_register_hw(hw);
+       if (err)
+               wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
+                         "%d\n", __func__, err);
+
+       if (wl->pub->srom_ccode[0])
+               err = brcms_set_hint(wl, wl->pub->srom_ccode);
+       else
+               err = brcms_set_hint(wl, "US");
+       if (err)
+               wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n",
+                         __func__, err);
+
+       n_adapters_found++;
+       return wl;
+
+fail:
+       brcms_free(wl);
+       return NULL;
+}
+
+
+
 /**
  * determines if a device is a WL device, and if so, attaches it.
  *
@@ -1149,7 +1270,7 @@ brcms_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        memset(hw->priv, 0, sizeof(*wl));
 
        wl = brcms_attach(pdev->vendor, pdev->device,
-                         pci_resource_start(pdev, 0), PCI_BUS, pdev,
+                         pci_resource_start(pdev, 0), pdev,
                          pdev->irq);
 
        if (!wl) {
@@ -1166,7 +1287,7 @@ static int brcms_suspend(struct pci_dev *pdev, pm_message_t state)
        struct ieee80211_hw *hw;
 
        hw = pci_get_drvdata(pdev);
-       wl = HW_TO_WL(hw);
+       wl = hw->priv;
        if (!wl) {
                wiphy_err(wl->wiphy,
                          "brcms_suspend: pci_get_drvdata failed\n");
@@ -1191,75 +1312,34 @@ static int brcms_resume(struct pci_dev *pdev)
        u32 val;
 
        hw = pci_get_drvdata(pdev);
-       wl = HW_TO_WL(hw);
+       wl = hw->priv;
        if (!wl) {
                wiphy_err(wl->wiphy,
                          "wl: brcms_resume: pci_get_drvdata failed\n");
                return -ENODEV;
        }
 
-       err = pci_set_power_state(pdev, PCI_D0);
-       if (err)
-               return err;
-
-       pci_restore_state(pdev);
-
-       err = pci_enable_device(pdev);
-       if (err)
-               return err;
-
-       pci_set_master(pdev);
-
-       pci_read_config_dword(pdev, 0x40, &val);
-       if ((val & 0x0000ff00) != 0)
-               pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
-       /*
-       *  done. driver will be put in up state
-       *  in brcms_ops_add_interface() call.
-       */
-       return err;
-}
-
-/*
-* called from both kernel as from this kernel module.
-* precondition: perimeter lock is not acquired.
-*/
-static void brcms_remove(struct pci_dev *pdev)
-{
-       struct brcms_info *wl;
-       struct ieee80211_hw *hw;
-       int status;
-
-       hw = pci_get_drvdata(pdev);
-       wl = HW_TO_WL(hw);
-       if (!wl) {
-               pr_err("wl: brcms_remove: pci_get_drvdata failed\n");
-               return;
-       }
-
-       LOCK(wl);
-       status = brcms_c_chipmatch(pdev->vendor, pdev->device);
-       UNLOCK(wl);
-       if (!status) {
-               wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch "
-                                    "failed\n");
-               return;
-       }
-       if (wl->wlc) {
-               wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
-               wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
-               ieee80211_unregister_hw(hw);
-               LOCK(wl);
-               brcms_down(wl);
-               UNLOCK(wl);
-       }
-       pci_disable_device(pdev);
+       err = pci_set_power_state(pdev, PCI_D0);
+       if (err)
+               return err;
 
-       brcms_free(wl);
+       pci_restore_state(pdev);
 
-       pci_set_drvdata(pdev, NULL);
-       ieee80211_free_hw(hw);
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       pci_set_master(pdev);
+
+       pci_read_config_dword(pdev, 0x40, &val);
+       if ((val & 0x0000ff00) != 0)
+               pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+       /*
+       *  done. driver will be put in up state
+       *  in brcms_ops_add_interface() call.
+       */
+       return err;
 }
 
 static struct pci_driver brcms_pci_driver = {
@@ -1285,8 +1365,6 @@ static int __init brcms_module_init(void)
 #ifdef BCMDBG
        if (msglevel != 0xdeadbeef)
                brcm_msg_level = msglevel;
-       if (phymsglevel != 0xdeadbeef)
-               phyhal_msg_level = phymsglevel;
 #endif                         /* BCMDBG */
 
        error = pci_register_driver(&brcms_pci_driver);
@@ -1314,82 +1392,6 @@ static void __exit brcms_module_exit(void)
 module_init(brcms_module_init);
 module_exit(brcms_module_exit);
 
-/**
- * This function frees the WL per-device resources.
- *
- * This function frees resources owned by the WL device pointed to
- * by the wl parameter.
- *
- * precondition: can both be called locked and unlocked
- *
- */
-static void brcms_free(struct brcms_info *wl)
-{
-       struct brcms_timer *t, *next;
-
-       /* free ucode data */
-       if (wl->fw.fw_cnt)
-               brcms_ucode_data_free();
-       if (wl->irq)
-               free_irq(wl->irq, wl);
-
-       /* kill dpc */
-       tasklet_kill(&wl->tasklet);
-
-       if (wl->pub) {
-               brcms_c_module_unregister(wl->pub, "linux", wl);
-       }
-
-       /* free common resources */
-       if (wl->wlc) {
-               brcms_c_detach(wl->wlc);
-               wl->wlc = NULL;
-               wl->pub = NULL;
-       }
-
-       /* virtual interface deletion is deferred so we cannot spinwait */
-
-       /* wait for all pending callbacks to complete */
-       while (atomic_read(&wl->callbacks) > 0)
-               schedule();
-
-       /* free timers */
-       for (t = wl->timers; t; t = next) {
-               next = t->next;
-#ifdef BCMDBG
-               kfree(t->name);
-#endif
-               kfree(t);
-       }
-
-       /*
-        * unregister_netdev() calls get_stats() which may read chip registers
-        * so we cannot unmap the chip registers until after calling unregister_netdev() .
-        */
-       if (wl->regsva && wl->bcm_bustype != SDIO_BUS &&
-           wl->bcm_bustype != JTAG_BUS) {
-               iounmap((void *)wl->regsva);
-       }
-       wl->regsva = NULL;
-}
-
-/* flags the given rate in rateset as requested */
-static void brcms_set_basic_rate(struct wl_rateset *rs, u16 rate, bool is_br)
-{
-       u32 i;
-
-       for (i = 0; i < rs->count; i++) {
-               if (rate != (rs->rates[i] & 0x7f))
-                       continue;
-
-               if (is_br)
-                       rs->rates[i] |= BRCMS_RATE_FLAG;
-               else
-                       rs->rates[i] &= BRCMS_RATE_MASK;
-               return;
-       }
-}
-
 /*
  * precondition: perimeter lock has been acquired
  */
@@ -1404,7 +1406,7 @@ void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,
  */
 void brcms_init(struct brcms_info *wl)
 {
-       BCMMSG(WL_TO_HW(wl)->wiphy, "wl%d\n", wl->pub->unit);
+       BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
        brcms_reset(wl);
 
        brcms_c_init(wl->wlc);
@@ -1415,7 +1417,7 @@ void brcms_init(struct brcms_info *wl)
  */
 uint brcms_reset(struct brcms_info *wl)
 {
-       BCMMSG(WL_TO_HW(wl)->wiphy, "wl%d\n", wl->pub->unit);
+       BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
        brcms_c_reset(wl->wlc);
 
        /* dpc will not be rescheduled */
@@ -1437,14 +1439,6 @@ void brcms_intrson(struct brcms_info *wl)
        INT_UNLOCK(wl, flags);
 }
 
-/*
- * precondition: perimeter lock has been acquired
- */
-bool wl_alloc_dma_resources(struct brcms_info *wl, uint addrwidth)
-{
-       return true;
-}
-
 u32 brcms_intrsoff(struct brcms_info *wl)
 {
        unsigned long flags;
@@ -1502,78 +1496,6 @@ void brcms_down(struct brcms_info *wl)
        LOCK(wl);
 }
 
-static irqreturn_t brcms_isr(int irq, void *dev_id)
-{
-       struct brcms_info *wl;
-       bool ours, wantdpc;
-       unsigned long flags;
-
-       wl = (struct brcms_info *) dev_id;
-
-       ISR_LOCK(wl, flags);
-
-       /* call common first level interrupt handler */
-       ours = brcms_c_isr(wl->wlc, &wantdpc);
-       if (ours) {
-               /* if more to do... */
-               if (wantdpc) {
-
-                       /* ...and call the second level interrupt handler */
-                       /* schedule dpc */
-                       tasklet_schedule(&wl->tasklet);
-               }
-       }
-
-       ISR_UNLOCK(wl, flags);
-
-       return IRQ_RETVAL(ours);
-}
-
-static void brcms_dpc(unsigned long data)
-{
-       struct brcms_info *wl;
-
-       wl = (struct brcms_info *) data;
-
-       LOCK(wl);
-
-       /* call the common second level interrupt handler */
-       if (wl->pub->up) {
-               if (wl->resched) {
-                       unsigned long flags;
-
-                       INT_LOCK(wl, flags);
-                       brcms_c_intrsupd(wl->wlc);
-                       INT_UNLOCK(wl, flags);
-               }
-
-               wl->resched = brcms_c_dpc(wl->wlc, true);
-       }
-
-       /* brcms_c_dpc() may bring the driver down */
-       if (!wl->pub->up)
-               goto done;
-
-       /* re-schedule dpc */
-       if (wl->resched)
-               tasklet_schedule(&wl->tasklet);
-       else {
-               /* re-enable interrupts */
-               brcms_intrson(wl);
-       }
-
- done:
-       UNLOCK(wl);
-}
-
-/*
- * is called by the kernel from software irq context
- */
-static void brcms_timer(unsigned long data)
-{
-       _brcms_timer((struct brcms_timer *) data);
-}
-
 /*
 * precondition: perimeter lock is not acquired
  */
@@ -1598,6 +1520,14 @@ static void _brcms_timer(struct brcms_timer *t)
        UNLOCK(t->wl);
 }
 
+/*
+ * is called by the kernel from software irq context
+ */
+static void brcms_timer(unsigned long data)
+{
+       _brcms_timer((struct brcms_timer *) data);
+}
+
 /*
  * Adds a timer to the list. Caller supplies a timer function.
  * Is called from wlc.
@@ -1611,11 +1541,8 @@ struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
        struct brcms_timer *t;
 
        t = kzalloc(sizeof(struct brcms_timer), GFP_ATOMIC);
-       if (!t) {
-               wiphy_err(wl->wiphy, "wl%d: brcms_init_timer: out of memory\n",
-                         wl->pub->unit);
-               return 0;
-       }
+       if (!t)
+               return NULL;
 
        init_timer(&t->timer);
        t->timer.data = (unsigned long) t;
@@ -1635,7 +1562,8 @@ struct brcms_timer *brcms_init_timer(struct brcms_info *wl,
        return t;
 }
 
-/* BMAC_NOTE: Add timer adds only the kernel timer since it's going to be more accurate
+/*
+ * adds only the kernel timer since it's going to be more accurate
  * as well as it's easier to make it periodic
  *
  * precondition: perimeter lock has been acquired
@@ -1644,10 +1572,10 @@ void brcms_add_timer(struct brcms_info *wl, struct brcms_timer *t, uint ms,
                     int periodic)
 {
 #ifdef BCMDBG
-       if (t->set) {
+       if (t->set)
                wiphy_err(wl->wiphy, "%s: Already set. Name: %s, per %d\n",
                          __func__, t->name, periodic);
-       }
+
 #endif
        t->ms = ms;
        t->periodic = (bool) periodic;
@@ -1667,9 +1595,9 @@ bool brcms_del_timer(struct brcms_info *wl, struct brcms_timer *t)
 {
        if (t->set) {
                t->set = false;
-               if (!del_timer(&t->timer)) {
+               if (!del_timer(&t->timer))
                        return false;
-               }
+
                atomic_dec(&wl->callbacks);
        }
 
@@ -1711,27 +1639,6 @@ void brcms_free_timer(struct brcms_info *wl, struct brcms_timer *t)
 
 }
 
-/*
- * runs in software irq context
- *
- * precondition: perimeter lock is not acquired
- */
-static int wl_linux_watchdog(void *ctx)
-{
-       return 0;
-}
-
-struct firmware_hdr {
-       u32 offset;
-       u32 len;
-       u32 idx;
-};
-
-char *brcms_firmwares[MAX_FW_IMAGES] = {
-       "brcm/bcm43xx",
-       NULL
-};
-
 /*
  * precondition: perimeter lock has been acquired
  */
@@ -1744,15 +1651,15 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
                hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data;
                for (entry = 0; entry < wl->fw.hdr_num_entries[i];
                     entry++, hdr++) {
-                       if (hdr->idx == idx) {
-                               pdata = wl->fw.fw_bin[i]->data + hdr->offset;
-                               *pbuf = kmalloc(hdr->len, GFP_ATOMIC);
-                               if (*pbuf == NULL) {
-                                       wiphy_err(wl->wiphy, "fail to alloc %d"
-                                                 " bytes\n", hdr->len);
+                       u32 len = le32_to_cpu(hdr->len);
+                       if (le32_to_cpu(hdr->idx) == idx) {
+                               pdata = wl->fw.fw_bin[i]->data +
+                                       le32_to_cpu(hdr->offset);
+                               *pbuf = kmalloc(len, GFP_ATOMIC);
+                               if (*pbuf == NULL)
                                        goto fail;
-                               }
-                               memcpy(*pbuf, pdata, hdr->len);
+
+                               memcpy(*pbuf, pdata, len);
                                return 0;
                        }
                }
@@ -1777,14 +1684,15 @@ int brcms_ucode_init_uint(struct brcms_info *wl, u32 *data, u32 idx)
                hdr = (struct firmware_hdr *)wl->fw.fw_hdr[i]->data;
                for (entry = 0; entry < wl->fw.hdr_num_entries[i];
                     entry++, hdr++) {
-                       if (hdr->idx == idx) {
-                               pdata = wl->fw.fw_bin[i]->data + hdr->offset;
-                               if (hdr->len != 4) {
+                       if (le32_to_cpu(hdr->idx) == idx) {
+                               pdata = wl->fw.fw_bin[i]->data +
+                                       le32_to_cpu(hdr->offset);
+                               if (le32_to_cpu(hdr->len) != 4) {
                                        wiphy_err(wl->wiphy,
                                                  "ERROR: fw hdr len\n");
                                        return -ENOMSG;
                                }
-                               *data = *((u32 *) pdata);
+                               *data = le32_to_cpu(*((u32 *) pdata));
                                return 0;
                        }
                }
@@ -1793,44 +1701,6 @@ int brcms_ucode_init_uint(struct brcms_info *wl, u32 *data, u32 idx)
        return -ENOMSG;
 }
 
-/*
- * Precondition: Since this function is called in brcms_pci_probe() context,
- * no locking is required.
- */
-static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev)
-{
-       int status;
-       struct device *device = &pdev->dev;
-       char fw_name[100];
-       int i;
-
-       memset((void *)&wl->fw, 0, sizeof(struct brcms_firmware));
-       for (i = 0; i < MAX_FW_IMAGES; i++) {
-               if (brcms_firmwares[i] == NULL)
-                       break;
-               sprintf(fw_name, "%s-%d.fw", brcms_firmwares[i],
-                       UCODE_LOADER_API_VER);
-               status = request_firmware(&wl->fw.fw_bin[i], fw_name, device);
-               if (status) {
-                       wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
-                                 KBUILD_MODNAME, fw_name);
-                       return status;
-               }
-               sprintf(fw_name, "%s_hdr-%d.fw", brcms_firmwares[i],
-                       UCODE_LOADER_API_VER);
-               status = request_firmware(&wl->fw.fw_hdr[i], fw_name, device);
-               if (status) {
-                       wiphy_err(wl->wiphy, "%s: fail to load firmware %s\n",
-                                 KBUILD_MODNAME, fw_name);
-                       return status;
-               }
-               wl->fw.hdr_num_entries[i] =
-                   wl->fw.fw_hdr[i]->size / (sizeof(struct firmware_hdr));
-       }
-       wl->fw.fw_cnt = i;
-       return brcms_ucode_data_init(wl);
-}
-
 /*
  * precondition: can both be called locked and unlocked
  */
@@ -1839,20 +1709,6 @@ void brcms_ucode_free_buf(void *p)
        kfree(p);
 }
 
-/*
- * Precondition: Since this function is called in brcms_pci_probe() context,
- * no locking is required.
- */
-static void brcms_release_fw(struct brcms_info *wl)
-{
-       int i;
-       for (i = 0; i < MAX_FW_IMAGES; i++) {
-               release_firmware(wl->fw.fw_bin[i]);
-               release_firmware(wl->fw.fw_hdr[i]);
-       }
-}
-
-
 /*
  * checks validity of all firmware images loaded from user space
  *
@@ -1890,7 +1746,8 @@ int brcms_check_firmwares(struct brcms_info *wl)
                        ucode_hdr = (struct firmware_hdr *)fw_hdr->data;
                        for (entry = 0; entry < wl->fw.hdr_num_entries[i] &&
                             !rc; entry++, ucode_hdr++) {
-                               if (ucode_hdr->offset + ucode_hdr->len >
+                               if (le32_to_cpu(ucode_hdr->offset) +
+                                   le32_to_cpu(ucode_hdr->len) >
                                    fw->size) {
                                        wiphy_err(wl->wiphy,
                                                  "%s: conflicting bin/hdr\n",