]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/iwlwifi/iwl4965-base.c
iwlwifi: drop skb silently for Tx request in monitor mode
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / iwlwifi / iwl4965-base.c
index 37ab1c565ce1eb3874c42b2e380be0d9e1add32a..0bd55bb19739b4f506944ef1c1489d88ae820b86 100644 (file)
@@ -398,9 +398,9 @@ static u8 iwl4965_remove_station(struct iwl_priv *priv, const u8 *addr, int is_a
        if (is_ap)
                index = IWL_AP_ID;
        else if (is_broadcast_ether_addr(addr))
-               index = priv->hw_setting.bcast_sta_id;
+               index = priv->hw_params.bcast_sta_id;
        else
-               for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++)
+               for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++)
                        if (priv->stations[i].used &&
                            !compare_ether_addr(priv->stations[i].sta.sta.addr,
                                                addr)) {
@@ -440,9 +440,9 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
        if (is_ap)
                index = IWL_AP_ID;
        else if (is_broadcast_ether_addr(addr))
-               index = priv->hw_setting.bcast_sta_id;
+               index = priv->hw_params.bcast_sta_id;
        else
-               for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) {
+               for (i = IWL_STA_ID; i < priv->hw_params.max_stations; i++) {
                        if (!compare_ether_addr(priv->stations[i].sta.sta.addr,
                                                addr)) {
                                index = i;
@@ -483,7 +483,7 @@ u8 iwl4965_add_station_flags(struct iwl_priv *priv, const u8 *addr,
 
 #ifdef CONFIG_IWL4965_HT
        /* BCAST station and IBSS stations do not work in HT mode */
-       if (index != priv->hw_setting.bcast_sta_id &&
+       if (index != priv->hw_params.bcast_sta_id &&
            priv->iw_mode != IEEE80211_IF_TYPE_IBSS)
                iwl4965_set_ht_add_station(priv, index,
                                 (struct ieee80211_ht_info *) ht_data);
@@ -575,11 +575,11 @@ int iwl4965_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
        txq->need_update = 1;
 
        /* Set up entry in queue's byte count circular buffer */
-       ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);
+       priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
 
        /* Increment and update queue's write index */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       iwl4965_tx_queue_update_write_ptr(priv, txq);
+       ret = iwl4965_tx_queue_update_write_ptr(priv, txq);
 
        spin_unlock_irqrestore(&priv->hcmd_lock, flags);
        return ret ? ret : idx;
@@ -596,13 +596,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
 
 }
 
-int iwl4965_send_statistics_request(struct iwl_priv *priv)
-{
-       u32 flags = 0;
-       return iwl_send_cmd_pdu(priv, REPLY_STATISTICS_CMD,
-                                     sizeof(flags), &flags);
-}
-
 /**
  * iwl4965_rxon_add_station - add station into station table.
  *
@@ -756,60 +749,6 @@ static int iwl4965_full_rxon_required(struct iwl_priv *priv)
        return 0;
 }
 
-static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
-{
-       int rc = 0;
-       struct iwl4965_rx_packet *res = NULL;
-       struct iwl4965_rxon_assoc_cmd rxon_assoc;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_RXON_ASSOC,
-               .len = sizeof(rxon_assoc),
-               .meta.flags = CMD_WANT_SKB,
-               .data = &rxon_assoc,
-       };
-       const struct iwl4965_rxon_cmd *rxon1 = &priv->staging_rxon;
-       const struct iwl4965_rxon_cmd *rxon2 = &priv->active_rxon;
-
-       if ((rxon1->flags == rxon2->flags) &&
-           (rxon1->filter_flags == rxon2->filter_flags) &&
-           (rxon1->cck_basic_rates == rxon2->cck_basic_rates) &&
-           (rxon1->ofdm_ht_single_stream_basic_rates ==
-            rxon2->ofdm_ht_single_stream_basic_rates) &&
-           (rxon1->ofdm_ht_dual_stream_basic_rates ==
-            rxon2->ofdm_ht_dual_stream_basic_rates) &&
-           (rxon1->rx_chain == rxon2->rx_chain) &&
-           (rxon1->ofdm_basic_rates == rxon2->ofdm_basic_rates)) {
-               IWL_DEBUG_INFO("Using current RXON_ASSOC.  Not resending.\n");
-               return 0;
-       }
-
-       rxon_assoc.flags = priv->staging_rxon.flags;
-       rxon_assoc.filter_flags = priv->staging_rxon.filter_flags;
-       rxon_assoc.ofdm_basic_rates = priv->staging_rxon.ofdm_basic_rates;
-       rxon_assoc.cck_basic_rates = priv->staging_rxon.cck_basic_rates;
-       rxon_assoc.reserved = 0;
-       rxon_assoc.ofdm_ht_single_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_single_stream_basic_rates;
-       rxon_assoc.ofdm_ht_dual_stream_basic_rates =
-           priv->staging_rxon.ofdm_ht_dual_stream_basic_rates;
-       rxon_assoc.rx_chain_select_flags = priv->staging_rxon.rx_chain;
-
-       rc = iwl_send_cmd_sync(priv, &cmd);
-       if (rc)
-               return rc;
-
-       res = (struct iwl4965_rx_packet *)cmd.meta.u.skb->data;
-       if (res->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERROR("Bad return from REPLY_RXON_ASSOC command\n");
-               rc = -EIO;
-       }
-
-       priv->alloc_rxb_skb--;
-       dev_kfree_skb_any(cmd.meta.u.skb);
-
-       return rc;
-}
-
 /**
  * iwl4965_commit_rxon - commit staging_rxon to hardware
  *
@@ -841,7 +780,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
         * iwl4965_rxon_assoc_cmd which is used to reconfigure filter
         * and other flags for the current radio configuration. */
        if (!iwl4965_full_rxon_required(priv)) {
-               rc = iwl4965_send_rxon_assoc(priv);
+               rc = iwl_send_rxon_assoc(priv);
                if (rc) {
                        IWL_ERROR("Error setting RXON_ASSOC "
                                  "configuration (%d).\n", rc);
@@ -896,7 +835,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
                       le16_to_cpu(priv->staging_rxon.channel),
                       print_mac(mac, priv->staging_rxon.bssid_addr));
 
-       iwl4965_set_rxon_hwcrypto(priv, priv->cfg->mod_params->hw_crypto);
+       iwl4965_set_rxon_hwcrypto(priv, !priv->cfg->mod_params->sw_crypto);
        /* Apply the new configuration */
        rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
                              sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon);
@@ -1112,118 +1051,6 @@ int iwl4965_send_add_station(struct iwl_priv *priv,
        return rc;
 }
 
-static int iwl4965_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
-                                  struct ieee80211_key_conf *keyconf,
-                                  u8 sta_id)
-{
-       unsigned long flags;
-       __le16 key_flags = 0;
-
-       key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
-       key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-
-       if (sta_id == priv->hw_setting.bcast_sta_id)
-               key_flags |= STA_KEY_MULTICAST_MSK;
-
-       keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-       keyconf->hw_key_idx = keyconf->keyidx;
-
-       key_flags &= ~STA_KEY_FLG_INVALID;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       priv->stations[sta_id].keyinfo.alg = keyconf->alg;
-       priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
-
-       memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
-              keyconf->keylen);
-
-       memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
-              keyconf->keylen);
-
-       priv->stations[sta_id].sta.key.key_offset
-                       = (sta_id % STA_KEY_MAX_NUM);/*FIXME*/
-       priv->stations[sta_id].sta.key.key_flags = key_flags;
-       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
-       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-       IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
-       return iwl4965_send_add_station(priv,
-                               &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
-static int iwl4965_set_tkip_dynamic_key_info(struct iwl_priv *priv,
-                                  struct ieee80211_key_conf *keyconf,
-                                  u8 sta_id)
-{
-       unsigned long flags;
-       int ret = 0;
-
-       keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-       keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
-       keyconf->hw_key_idx = keyconf->keyidx;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-
-       priv->stations[sta_id].keyinfo.alg = keyconf->alg;
-       priv->stations[sta_id].keyinfo.conf = keyconf;
-       priv->stations[sta_id].keyinfo.keylen = 16;
-
-       /* This copy is acutally not needed: we get the key with each TX */
-       memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
-
-       memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
-
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-       return ret;
-}
-
-static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
-{
-       unsigned long flags;
-
-       priv->key_mapping_key = 0;
-
-       spin_lock_irqsave(&priv->sta_lock, flags);
-       memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl4965_hw_key));
-       memset(&priv->stations[sta_id].sta.key, 0, sizeof(struct iwl4965_keyinfo));
-       priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
-       priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
-       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       spin_unlock_irqrestore(&priv->sta_lock, flags);
-
-       IWL_DEBUG_INFO("hwcrypto: clear ucode station key info\n");
-       iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
-       return 0;
-}
-
-static int iwl4965_set_dynamic_key(struct iwl_priv *priv,
-                               struct ieee80211_key_conf *key, u8 sta_id)
-{
-       int ret;
-
-       priv->key_mapping_key = 1;
-
-       switch (key->alg) {
-       case ALG_CCMP:
-               ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id);
-               break;
-       case ALG_TKIP:
-               ret = iwl4965_set_tkip_dynamic_key_info(priv, key, sta_id);
-               break;
-       case ALG_WEP:
-               ret = iwl_set_wep_dynamic_key_info(priv, key, sta_id);
-               break;
-       default:
-               IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
-               ret = -EINVAL;
-       }
-
-       return ret;
-}
-
 static void iwl4965_clear_free_frames(struct iwl_priv *priv)
 {
        struct list_head *element;
@@ -1344,13 +1171,13 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv)
  *
  ******************************************************************************/
 
-static void iwl4965_unset_hw_setting(struct iwl_priv *priv)
+static void iwl4965_unset_hw_params(struct iwl_priv *priv)
 {
-       if (priv->hw_setting.shared_virt)
+       if (priv->shared_virt)
                pci_free_consistent(priv->pci_dev,
                                    sizeof(struct iwl4965_shared),
-                                   priv->hw_setting.shared_virt,
-                                   priv->hw_setting.shared_phys);
+                                   priv->shared_virt,
+                                   priv->shared_phys);
 }
 
 /**
@@ -1947,7 +1774,10 @@ static int iwl4965_scan_initiate(struct iwl_priv *priv)
        }
 
        IWL_DEBUG_INFO("Starting scan...\n");
-       priv->scan_bands = 2;
+       if (priv->cfg->sku & IWL_SKU_G)
+               priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
+       if (priv->cfg->sku & IWL_SKU_A)
+               priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
        set_bit(STATUS_SCANNING, &priv->status);
        priv->scan_start = jiffies;
        priv->scan_pass_start = priv->scan_start;
@@ -1967,7 +1797,7 @@ static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv,
                      | RXON_FLG_CCK_MSK);
                priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
        } else {
-               /* Copied from iwl4965_bg_post_associate() */
+               /* Copied from iwl4965_post_associate() */
                if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
                        priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
                else
@@ -2248,7 +2078,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
        /* If this frame is broadcast or management, use broadcast station id */
        if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) ||
            is_multicast_ether_addr(hdr->addr1))
-               return priv->hw_setting.bcast_sta_id;
+               return priv->hw_params.bcast_sta_id;
 
        switch (priv->iw_mode) {
 
@@ -2262,7 +2092,7 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
                sta_id = iwl4965_hw_find_station(priv, hdr->addr1);
                if (sta_id != IWL_INVALID_STATION)
                        return sta_id;
-               return priv->hw_setting.bcast_sta_id;
+               return priv->hw_params.bcast_sta_id;
 
        /* If this frame is going out to an IBSS network, find the station,
         * or create a new station table entry */
@@ -2282,11 +2112,11 @@ static int iwl4965_get_sta_id(struct iwl_priv *priv,
                               "Defaulting to broadcast...\n",
                               print_mac(mac, hdr->addr1));
                iwl_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr));
-               return priv->hw_setting.bcast_sta_id;
+               return priv->hw_params.bcast_sta_id;
 
        default:
                IWL_WARNING("Unknown mode of operation: %d", priv->iw_mode);
-               return priv->hw_setting.bcast_sta_id;
+               return priv->hw_params.bcast_sta_id;
        }
 }
 
@@ -2433,7 +2263,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv,
         * of the MAC header (device reads on dword boundaries).
         * We'll tell device about this padding later.
         */
-       len = priv->hw_setting.tx_cmd_len +
+       len = priv->hw_params.tx_cmd_len +
                sizeof(struct iwl_cmd_header) + hdr_len;
 
        len_org = len;
@@ -2504,7 +2334,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv,
                           ieee80211_get_hdrlen(fc));
 
        /* Set up entry for this TFD in Tx byte-count array */
-       iwl4965_tx_queue_update_wr_ptr(priv, txq, len);
+       priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, len);
 
        /* Tell device the write index *just past* this latest filled TFD */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
@@ -2600,7 +2430,8 @@ void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
                                    CSR_UCODE_SW_BIT_RFKILL);
                        spin_unlock_irqrestore(&priv->lock, flags);
                        /* call the host command only if no hw rf-kill set */
-                       if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+                       if (!test_bit(STATUS_RF_KILL_HW, &priv->status) &&
+                           iwl_is_ready(priv))
                                iwl4965_send_card_state(priv,
                                                        CARD_STATE_CMD_DISABLE,
                                                        0);
@@ -3195,8 +3026,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
 
        IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index);
        if (index != -1) {
-               int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
 #ifdef CONFIG_IWL4965_HT
+               int freed = iwl4965_tx_queue_reclaim(priv, txq_id, index);
+
                if (tid != MAX_TID_COUNT)
                        priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
                if (iwl4965_queue_space(&txq->q) > txq->q.low_mark &&
@@ -3448,13 +3280,18 @@ static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv,
        cancel_delayed_work(&priv->scan_check);
 
        IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n",
-                      (priv->scan_bands == 2) ? "2.4" : "5.2",
+                      (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
+                                               "2.4" : "5.2",
                       jiffies_to_msecs(elapsed_jiffies
                                        (priv->scan_pass_start, jiffies)));
 
-       /* Remove this scanned band from the list
-        * of pending bands to scan */
-       priv->scan_bands--;
+       /* Remove this scanned band from the list of pending
+        * bands to scan, band G precedes A in order of scanning
+        * as seen in iwl_bg_request_scan */
+       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
+               priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
+       else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
+               priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
 
        /* If a request to abort was given, or the scan did not succeed
         * then we reset the scan state machine and terminate,
@@ -3464,7 +3301,7 @@ static void iwl4965_rx_scan_complete_notif(struct iwl_priv *priv,
                clear_bit(STATUS_SCAN_ABORTING, &priv->status);
        } else {
                /* If there are more bands on this scan pass reschedule */
-               if (priv->scan_bands > 0)
+               if (priv->scan_bands)
                        goto reschedule;
        }
 
@@ -3860,7 +3697,7 @@ static void iwl4965_rx_allocate(struct iwl_priv *priv)
 
                /* Alloc a new receive buffer */
                rxb->skb =
-                   alloc_skb(priv->hw_setting.rx_buf_size,
+                   alloc_skb(priv->hw_params.rx_buf_size,
                                __GFP_NOWARN | GFP_ATOMIC);
                if (!rxb->skb) {
                        if (net_ratelimit())
@@ -3877,7 +3714,7 @@ static void iwl4965_rx_allocate(struct iwl_priv *priv)
                /* Get physical address of RB/SKB */
                rxb->dma_addr =
                    pci_map_single(priv->pci_dev, rxb->skb->data,
-                          priv->hw_setting.rx_buf_size, PCI_DMA_FROMDEVICE);
+                          priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE);
                list_add_tail(&rxb->list, &rxq->rx_free);
                rxq->free_count++;
        }
@@ -3920,7 +3757,7 @@ static void iwl4965_rx_queue_free(struct iwl_priv *priv, struct iwl4965_rx_queue
                if (rxq->pool[i].skb != NULL) {
                        pci_unmap_single(priv->pci_dev,
                                         rxq->pool[i].dma_addr,
-                                        priv->hw_setting.rx_buf_size,
+                                        priv->hw_params.rx_buf_size,
                                         PCI_DMA_FROMDEVICE);
                        dev_kfree_skb(rxq->pool[i].skb);
                }
@@ -3972,7 +3809,7 @@ void iwl4965_rx_queue_reset(struct iwl_priv *priv, struct iwl4965_rx_queue *rxq)
                if (rxq->pool[i].skb != NULL) {
                        pci_unmap_single(priv->pci_dev,
                                         rxq->pool[i].dma_addr,
-                                        priv->hw_setting.rx_buf_size,
+                                        priv->hw_params.rx_buf_size,
                                         PCI_DMA_FROMDEVICE);
                        priv->alloc_rxb_skb--;
                        dev_kfree_skb(rxq->pool[i].skb);
@@ -4107,7 +3944,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
                rxq->queue[i] = NULL;
 
                pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr,
-                                           priv->hw_setting.rx_buf_size,
+                                           priv->hw_params.rx_buf_size,
                                            PCI_DMA_FROMDEVICE);
                pkt = (struct iwl4965_rx_packet *)rxb->skb->data;
 
@@ -4160,7 +3997,7 @@ static void iwl4965_rx_handle(struct iwl_priv *priv)
                }
 
                pci_unmap_single(priv->pci_dev, rxb->dma_addr,
-                                priv->hw_setting.rx_buf_size,
+                                priv->hw_params.rx_buf_size,
                                 PCI_DMA_FROMDEVICE);
                spin_lock_irqsave(&rxq->lock, flags);
                list_add_tail(&rxb->list, &priv->rxq.rx_used);
@@ -4805,23 +4642,11 @@ static int iwl4965_get_channels_for_scan(struct iwl_priv *priv,
                if (channels[i].flags & IEEE80211_CHAN_DISABLED)
                        continue;
 
-               if (ieee80211_frequency_to_channel(channels[i].center_freq) ==
-                   le16_to_cpu(priv->active_rxon.channel)) {
-                       if (iwl_is_associated(priv)) {
-                               IWL_DEBUG_SCAN
-                                   ("Skipping current channel %d\n",
-                                    le16_to_cpu(priv->active_rxon.channel));
-                               continue;
-                       }
-               } else if (priv->only_active_channel)
-                       continue;
-
                scan_ch->channel = ieee80211_frequency_to_channel(channels[i].center_freq);
 
-               ch_info = iwl_get_channel_info(priv, band,
-                                        scan_ch->channel);
+               ch_info = iwl_get_channel_info(priv, band, scan_ch->channel);
                if (!is_channel_valid(ch_info)) {
-                       IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n",
+                       IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n",
                                       scan_ch->channel);
                        continue;
                }
@@ -5996,21 +5821,24 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
                       priv->direct_ssid, priv->direct_ssid_len);
                direct_mask = 1;
        } else if (!iwl_is_associated(priv) && priv->essid_len) {
+               IWL_DEBUG_SCAN
+                 ("Kicking off one direct scan for '%s' when not associated\n",
+                  iwl4965_escape_essid(priv->essid, priv->essid_len));
                scan->direct_scan[0].id = WLAN_EID_SSID;
                scan->direct_scan[0].len = priv->essid_len;
                memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len);
                direct_mask = 1;
        } else {
+               IWL_DEBUG_SCAN("Kicking off one indirect scan.\n");
                direct_mask = 0;
        }
 
        scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = priv->hw_setting.bcast_sta_id;
+       scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id;
        scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
 
 
-       switch (priv->scan_bands) {
-       case 2:
+       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) {
                scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
                scan->tx_cmd.rate_n_flags =
                                iwl4965_hw_set_rate_n_flags(IWL_RATE_1M_PLCP,
@@ -6018,17 +5846,13 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
 
                scan->good_CRC_th = 0;
                band = IEEE80211_BAND_2GHZ;
-               break;
-
-       case 1:
+       } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) {
                scan->tx_cmd.rate_n_flags =
                                iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP,
                                RATE_MCS_ANT_B_MSK);
                scan->good_CRC_th = IWL_GOOD_CRC_TH;
                band = IEEE80211_BAND_5GHZ;
-               break;
-
-       default:
+       } else {
                IWL_WARNING("Invalid scan band count\n");
                goto done;
        }
@@ -6053,23 +5877,18 @@ static void iwl4965_bg_request_scan(struct work_struct *data)
        if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR)
                scan->filter_flags = RXON_FILTER_PROMISC_MSK;
 
-       if (direct_mask) {
-               IWL_DEBUG_SCAN
-                   ("Initiating direct scan for %s.\n",
-                    iwl4965_escape_essid(priv->essid, priv->essid_len));
+       if (direct_mask)
                scan->channel_count =
                        iwl4965_get_channels_for_scan(
                                priv, band, 1, /* active */
                                direct_mask,
                                (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-       } else {
-               IWL_DEBUG_SCAN("Initiating indirect scan.\n");
+       else
                scan->channel_count =
                        iwl4965_get_channels_for_scan(
                                priv, band, 0, /* passive */
                                direct_mask,
                                (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]);
-       }
 
        cmd.len += le16_to_cpu(scan->tx_cmd.len) +
            scan->channel_count * sizeof(struct iwl4965_scan_channel);
@@ -6131,10 +5950,8 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data)
 
 #define IWL_DELAY_NEXT_SCAN (HZ*2)
 
-static void iwl4965_bg_post_associate(struct work_struct *data)
+static void iwl4965_post_associate(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = container_of(data, struct iwl_priv,
-                                            post_associate.work);
        struct ieee80211_conf *conf = NULL;
        int ret = 0;
        DECLARE_MAC_BUF(mac);
@@ -6152,12 +5969,10 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       mutex_lock(&priv->mutex);
 
-       if (!priv->vif || !priv->is_open) {
-               mutex_unlock(&priv->mutex);
+       if (!priv->vif || !priv->is_open)
                return;
-       }
+
        iwl4965_scan_cancel_timeout(priv, 200);
 
        conf = ieee80211_get_hw_conf(priv->hw);
@@ -6241,7 +6056,18 @@ static void iwl4965_bg_post_associate(struct work_struct *data)
 
        /* we have just associated, don't start scan too early */
        priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
+}
+
+
+static void iwl4965_bg_post_associate(struct work_struct *data)
+{
+       struct iwl_priv *priv = container_of(data, struct iwl_priv,
+                                            post_associate.work);
+
+       mutex_lock(&priv->mutex);
+       iwl4965_post_associate(priv);
        mutex_unlock(&priv->mutex);
+
 }
 
 static void iwl4965_bg_abort_scan(struct work_struct *work)
@@ -6411,7 +6237,8 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) {
                IWL_DEBUG_MAC80211("leave - monitor\n");
-               return -1;
+               dev_kfree_skb_any(skb);
+               return 0;
        }
 
        IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
@@ -6638,7 +6465,6 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw,
 
        if (priv->vif != vif) {
                IWL_DEBUG_MAC80211("leave - priv->vif != vif\n");
-               mutex_unlock(&priv->mutex);
                return 0;
        }
 
@@ -6863,6 +6689,10 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changes & BSS_CHANGED_ASSOC) {
                IWL_DEBUG_MAC80211("ASSOC %d\n", bss_conf->assoc);
+               /* This should never happen as this function should
+                * never be called from interrupt context. */
+               if (WARN_ON_ONCE(in_interrupt()))
+                       return;
                if (bss_conf->assoc) {
                        priv->assoc_id = bss_conf->aid;
                        priv->beacon_int = bss_conf->beacon_int;
@@ -6870,14 +6700,16 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw,
                        priv->assoc_capability = bss_conf->assoc_capability;
                        priv->next_scan_jiffies = jiffies +
                                        IWL_DELAY_NEXT_SCAN_AFTER_ASSOC;
-                       queue_work(priv->workqueue, &priv->post_associate.work);
+                       mutex_lock(&priv->mutex);
+                       iwl4965_post_associate(priv);
+                       mutex_unlock(&priv->mutex);
                } else {
                        priv->assoc_id = 0;
                        IWL_DEBUG_MAC80211("DISASSOC %d\n", bss_conf->assoc);
                }
        } else if (changes && iwl_is_associated(priv) && priv->assoc_id) {
                        IWL_DEBUG_MAC80211("Associated Changes %d\n", changes);
-                       iwl4965_send_rxon_assoc(priv);
+                       iwl_send_rxon_assoc(priv);
        }
 
 }
@@ -6965,13 +6797,11 @@ static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
        key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
        key_flags &= ~STA_KEY_FLG_INVALID;
 
-       if (sta_id == priv->hw_setting.bcast_sta_id)
+       if (sta_id == priv->hw_params.bcast_sta_id)
                key_flags |= STA_KEY_MULTICAST_MSK;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
 
-       priv->stations[sta_id].sta.key.key_offset =
-                                       (sta_id % STA_KEY_MAX_NUM);/* FIXME */
        priv->stations[sta_id].sta.key.key_flags = key_flags;
        priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
 
@@ -7001,7 +6831,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        IWL_DEBUG_MAC80211("enter\n");
 
-       if (!priv->cfg->mod_params->hw_crypto) {
+       if (priv->cfg->mod_params->sw_crypto) {
                IWL_DEBUG_MAC80211("leave - hwcrypto disabled\n");
                return -EOPNOTSUPP;
        }
@@ -7026,7 +6856,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
         * so far, we are in legacy wep mode (group key only), otherwise we are
         * in 1X mode.
         * In legacy wep mode, we use another host command to the uCode */
-       if (key->alg == ALG_WEP && sta_id == priv->hw_setting.bcast_sta_id &&
+       if (key->alg == ALG_WEP && sta_id == priv->hw_params.bcast_sta_id &&
                priv->iw_mode != IEEE80211_IF_TYPE_AP) {
                if (cmd == SET_KEY)
                        is_default_wep_key = !priv->key_mapping_key;
@@ -7039,7 +6869,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                if (is_default_wep_key)
                        ret = iwl_set_default_wep_key(priv, key);
                else
-                       ret = iwl4965_set_dynamic_key(priv, key, sta_id);
+                       ret = iwl_set_dynamic_key(priv, key, sta_id);
 
                IWL_DEBUG_MAC80211("enable hwcrypto key\n");
                break;
@@ -7047,7 +6877,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                if (is_default_wep_key)
                        ret = iwl_remove_default_wep_key(priv, key);
                else
-                       ret = iwl4965_clear_sta_key_info(priv, sta_id);
+                       ret = iwl_remove_dynamic_key(priv, sta_id);
 
                IWL_DEBUG_MAC80211("disable hwcrypto key\n");
                break;
@@ -7223,8 +7053,6 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw)
                return;
        }
 
-       priv->only_active_channel = 0;
-
        iwl4965_set_rate(priv);
 
        mutex_unlock(&priv->mutex);
@@ -7644,7 +7472,7 @@ static ssize_t show_statistics(struct device *d,
                return -EAGAIN;
 
        mutex_lock(&priv->mutex);
-       rc = iwl4965_send_statistics_request(priv);
+       rc = iwl_send_statistics_request(priv, 0);
        mutex_unlock(&priv->mutex);
 
        if (rc) {
@@ -7952,8 +7780,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
         * 5. Setup HW constants
         ************************/
        /* Device-specific setup */
-       if (iwl4965_hw_set_hw_setting(priv)) {
-               IWL_ERROR("failed to set hw settings\n");
+       if (priv->cfg->ops->lib->set_hw_params(priv)) {
+               IWL_ERROR("failed to set hw parameters\n");
                goto out_iounmap;
        }
 
@@ -7963,7 +7791,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        err = iwl_setup(priv);
        if (err)
-               goto out_unset_hw_settings;
+               goto out_unset_hw_params;
        /* At this point both hw and priv are initialized. */
 
        /**********************************
@@ -7989,7 +7817,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
        if (err) {
                IWL_ERROR("failed to create sysfs device attributes\n");
-               goto out_unset_hw_settings;
+               goto out_unset_hw_params;
        }
 
        err = iwl_dbgfs_register(priv, DRV_NAME);
@@ -8013,8 +7841,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
  out_remove_sysfs:
        sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
- out_unset_hw_settings:
-       iwl4965_unset_hw_setting(priv);
+ out_unset_hw_params:
+       iwl4965_unset_hw_params(priv);
  out_iounmap:
        pci_iounmap(pdev, priv->hw_base);
  out_pci_release_regions:
@@ -8076,7 +7904,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
                iwl4965_rx_queue_free(priv, &priv->rxq);
        iwl4965_hw_txq_ctx_free(priv);
 
-       iwl4965_unset_hw_setting(priv);
+       iwl4965_unset_hw_params(priv);
        iwlcore_clear_stations_table(priv);
 
 
@@ -8141,9 +7969,17 @@ static int iwl4965_pci_resume(struct pci_dev *pdev)
  *
  *****************************************************************************/
 
-static struct pci_driver iwl4965_driver = {
+/* Hardware specific file defines the PCI IDs table for that hardware module */
+static struct pci_device_id iwl_hw_card_ids[] = {
+       {IWL_PCI_DEVICE(0x4229, PCI_ANY_ID, iwl4965_agn_cfg)},
+       {IWL_PCI_DEVICE(0x4230, PCI_ANY_ID, iwl4965_agn_cfg)},
+       {0}
+};
+MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids);
+
+static struct pci_driver iwl_driver = {
        .name = DRV_NAME,
-       .id_table = iwl4965_hw_card_ids,
+       .id_table = iwl_hw_card_ids,
        .probe = iwl4965_pci_probe,
        .remove = __devexit_p(iwl4965_pci_remove),
 #ifdef CONFIG_PM
@@ -8165,13 +8001,13 @@ static int __init iwl4965_init(void)
                return ret;
        }
 
-       ret = pci_register_driver(&iwl4965_driver);
+       ret = pci_register_driver(&iwl_driver);
        if (ret) {
                IWL_ERROR("Unable to initialize PCI module\n");
                goto error_register;
        }
 #ifdef CONFIG_IWLWIFI_DEBUG
-       ret = driver_create_file(&iwl4965_driver.driver, &driver_attr_debug_level);
+       ret = driver_create_file(&iwl_driver.driver, &driver_attr_debug_level);
        if (ret) {
                IWL_ERROR("Unable to create driver sysfs file\n");
                goto error_debug;
@@ -8182,7 +8018,7 @@ static int __init iwl4965_init(void)
 
 #ifdef CONFIG_IWLWIFI_DEBUG
 error_debug:
-       pci_unregister_driver(&iwl4965_driver);
+       pci_unregister_driver(&iwl_driver);
 #endif
 error_register:
        iwl4965_rate_control_unregister();
@@ -8192,9 +8028,9 @@ error_register:
 static void __exit iwl4965_exit(void)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
-       driver_remove_file(&iwl4965_driver.driver, &driver_attr_debug_level);
+       driver_remove_file(&iwl_driver.driver, &driver_attr_debug_level);
 #endif
-       pci_unregister_driver(&iwl4965_driver);
+       pci_unregister_driver(&iwl_driver);
        iwl4965_rate_control_unregister();
 }