]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/iwlwifi/iwl4965-base.c
iwlwifi: move rate registration to module load
[linux-2.6] / drivers / net / wireless / iwlwifi / iwl4965-base.c
index 44cfd02749761194efdc0eab056d24d872430378..ae4e53f5bedd362675d3de3b3d9eef8e0293d940 100644 (file)
@@ -48,6 +48,7 @@
 #include "iwl-eeprom.h"
 #include "iwl-core.h"
 #include "iwl-4965.h"
+#include "iwl-io.h"
 #include "iwl-helpers.h"
 
 static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
@@ -1792,6 +1793,8 @@ int iwl4965_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *heade
                        return !compare_ether_addr(header->addr2, priv->bssid);
                /* packets to our adapter go through */
                return !compare_ether_addr(header->addr1, priv->mac_addr);
+       default:
+               break;
        }
 
        return 1;
@@ -2053,6 +2056,9 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv)
                priv->staging_rxon.filter_flags = RXON_FILTER_PROMISC_MSK |
                    RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK;
                break;
+       default:
+               IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode);
+               break;
        }
 
 #if 0
@@ -2238,8 +2244,9 @@ static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv,
                        cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
                else
                        cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
-       } else
+       } else {
                cmd->cmd.tx.timeout.pm_frame_timeout = 0;
+       }
 
        cmd->cmd.tx.driver_txop = 0;
        cmd->cmd.tx.tx_flags = tx_flags;
@@ -2600,7 +2607,7 @@ static void iwl4965_set_rate(struct iwl_priv *priv)
                   (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
 }
 
-static void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
+void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
 {
        unsigned long flags;
 
@@ -2615,17 +2622,25 @@ static void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
                /* FIXME: This is a workaround for AP */
                if (priv->iw_mode != IEEE80211_IF_TYPE_AP) {
                        spin_lock_irqsave(&priv->lock, flags);
-                       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET,
+                       iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
                                    CSR_UCODE_SW_BIT_RFKILL);
                        spin_unlock_irqrestore(&priv->lock, flags);
-                       iwl4965_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
+                       /* call the host command only if no hw rf-kill set */
+                       if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
+                               iwl4965_send_card_state(priv,
+                                                       CARD_STATE_CMD_DISABLE,
+                                                       0);
                        set_bit(STATUS_RF_KILL_SW, &priv->status);
+
+                       /* make sure mac80211 stop sending Tx frame */
+                       if (priv->mac80211_registered)
+                               ieee80211_stop_queues(priv->hw);
                }
                return;
        }
 
        spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
        clear_bit(STATUS_RF_KILL_SW, &priv->status);
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -2634,9 +2649,9 @@ static void iwl4965_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
        msleep(10);
 
        spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
-       if (!iwl4965_grab_nic_access(priv))
-               iwl4965_release_nic_access(priv);
+       iwl_read32(priv, CSR_UCODE_DRV_GP1);
+       if (!iwl_grab_nic_access(priv))
+               iwl_release_nic_access(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
@@ -3513,35 +3528,35 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
        if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED |
                     RF_CARD_DISABLED)) {
 
-               iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET,
+               iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
                            CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
-               if (!iwl4965_grab_nic_access(priv)) {
-                       iwl4965_write_direct32(
+               if (!iwl_grab_nic_access(priv)) {
+                       iwl_write_direct32(
                                priv, HBUS_TARG_MBX_C,
                                HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
 
-                       iwl4965_release_nic_access(priv);
+                       iwl_release_nic_access(priv);
                }
 
                if (!(flags & RXON_CARD_DISABLED)) {
-                       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+                       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
                                    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-                       if (!iwl4965_grab_nic_access(priv)) {
-                               iwl4965_write_direct32(
+                       if (!iwl_grab_nic_access(priv)) {
+                               iwl_write_direct32(
                                        priv, HBUS_TARG_MBX_C,
                                        HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED);
 
-                               iwl4965_release_nic_access(priv);
+                               iwl_release_nic_access(priv);
                        }
                }
 
                if (flags & RF_CARD_DISABLED) {
-                       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_SET,
+                       iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
                                    CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT);
-                       iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
-                       if (!iwl4965_grab_nic_access(priv))
-                               iwl4965_release_nic_access(priv);
+                       iwl_read32(priv, CSR_UCODE_DRV_GP1);
+                       if (!iwl_grab_nic_access(priv))
+                               iwl_release_nic_access(priv);
                }
        }
 
@@ -3755,27 +3770,27 @@ int iwl4965_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl4965_rx_q
 
        /* If power-saving is in use, make sure device is awake */
        if (test_bit(STATUS_POWER_PMI, &priv->status)) {
-               reg = iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
+               reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
 
                if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
-                       iwl4965_set_bit(priv, CSR_GP_CNTRL,
+                       iwl_set_bit(priv, CSR_GP_CNTRL,
                                    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
                        goto exit_unlock;
                }
 
-               rc = iwl4965_grab_nic_access(priv);
+               rc = iwl_grab_nic_access(priv);
                if (rc)
                        goto exit_unlock;
 
                /* Device expects a multiple of 8 */
-               iwl4965_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
+               iwl_write_direct32(priv, FH_RSCSR_CHNL0_WPTR,
                                     q->write & ~0x7);
-               iwl4965_release_nic_access(priv);
+               iwl_release_nic_access(priv);
 
        /* Else device is assumed to be awake */
        } else
                /* Device expects a multiple of 8 */
-               iwl4965_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
+               iwl_write32(priv, FH_RSCSR_CHNL0_WPTR, q->write & ~0x7);
 
 
        q->need_update = 0;
@@ -4212,27 +4227,27 @@ static int iwl4965_tx_queue_update_write_ptr(struct iwl_priv *priv,
                /* wake up nic if it's powered down ...
                 * uCode will wake up, and interrupt us again, so next
                 * time we'll skip this part. */
-               reg = iwl4965_read32(priv, CSR_UCODE_DRV_GP1);
+               reg = iwl_read32(priv, CSR_UCODE_DRV_GP1);
 
                if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) {
                        IWL_DEBUG_INFO("Requesting wakeup, GP1 = 0x%x\n", reg);
-                       iwl4965_set_bit(priv, CSR_GP_CNTRL,
+                       iwl_set_bit(priv, CSR_GP_CNTRL,
                                    CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
                        return rc;
                }
 
                /* restore this queue's parameters in nic hardware. */
-               rc = iwl4965_grab_nic_access(priv);
+               rc = iwl_grab_nic_access(priv);
                if (rc)
                        return rc;
-               iwl4965_write_direct32(priv, HBUS_TARG_WRPTR,
+               iwl_write_direct32(priv, HBUS_TARG_WRPTR,
                                     txq->q.write_ptr | (txq_id << 8));
-               iwl4965_release_nic_access(priv);
+               iwl_release_nic_access(priv);
 
        /* else not in power-save mode, uCode will never sleep when we're
         * trying to tx (during RFKILL, we're not trying to tx). */
        } else
-               iwl4965_write32(priv, HBUS_TARG_WRPTR,
+               iwl_write32(priv, HBUS_TARG_WRPTR,
                            txq->q.write_ptr | (txq_id << 8));
 
        txq->need_update = 0;
@@ -4267,7 +4282,15 @@ static void iwl4965_enable_interrupts(struct iwl_priv *priv)
 {
        IWL_DEBUG_ISR("Enabling interrupts\n");
        set_bit(STATUS_INT_ENABLED, &priv->status);
-       iwl4965_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+       iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
+}
+
+/* call this function to flush any scheduled tasklet */
+static inline void iwl_synchronize_irq(struct iwl_priv *priv)
+{
+       /* wait to make sure we flush pedding tasklet*/
+       synchronize_irq(priv->pci_dev->irq);
+       tasklet_kill(&priv->irq_tasklet);
 }
 
 static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
@@ -4275,12 +4298,12 @@ static inline void iwl4965_disable_interrupts(struct iwl_priv *priv)
        clear_bit(STATUS_INT_ENABLED, &priv->status);
 
        /* disable interrupts from uCode/NIC to host */
-       iwl4965_write32(priv, CSR_INT_MASK, 0x00000000);
+       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
 
        /* acknowledge/clear/reset any interrupts still pending
         * from uCode or flow handler (Rx/Tx DMA) */
-       iwl4965_write32(priv, CSR_INT, 0xffffffff);
-       iwl4965_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
+       iwl_write32(priv, CSR_INT, 0xffffffff);
+       iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
        IWL_DEBUG_ISR("Disabled interrupts\n");
 }
 
@@ -4321,28 +4344,28 @@ static void iwl4965_dump_nic_error_log(struct iwl_priv *priv)
                return;
        }
 
-       rc = iwl4965_grab_nic_access(priv);
+       rc = iwl_grab_nic_access(priv);
        if (rc) {
                IWL_WARNING("Can not read from adapter at this time.\n");
                return;
        }
 
-       count = iwl4965_read_targ_mem(priv, base);
+       count = iwl_read_targ_mem(priv, base);
 
        if (ERROR_START_OFFSET <= count * ERROR_ELEM_SIZE) {
                IWL_ERROR("Start IWL Error Log Dump:\n");
                IWL_ERROR("Status: 0x%08lX, count: %d\n", priv->status, count);
        }
 
-       desc = iwl4965_read_targ_mem(priv, base + 1 * sizeof(u32));
-       blink1 = iwl4965_read_targ_mem(priv, base + 3 * sizeof(u32));
-       blink2 = iwl4965_read_targ_mem(priv, base + 4 * sizeof(u32));
-       ilink1 = iwl4965_read_targ_mem(priv, base + 5 * sizeof(u32));
-       ilink2 = iwl4965_read_targ_mem(priv, base + 6 * sizeof(u32));
-       data1 = iwl4965_read_targ_mem(priv, base + 7 * sizeof(u32));
-       data2 = iwl4965_read_targ_mem(priv, base + 8 * sizeof(u32));
-       line = iwl4965_read_targ_mem(priv, base + 9 * sizeof(u32));
-       time = iwl4965_read_targ_mem(priv, base + 11 * sizeof(u32));
+       desc = iwl_read_targ_mem(priv, base + 1 * sizeof(u32));
+       blink1 = iwl_read_targ_mem(priv, base + 3 * sizeof(u32));
+       blink2 = iwl_read_targ_mem(priv, base + 4 * sizeof(u32));
+       ilink1 = iwl_read_targ_mem(priv, base + 5 * sizeof(u32));
+       ilink2 = iwl_read_targ_mem(priv, base + 6 * sizeof(u32));
+       data1 = iwl_read_targ_mem(priv, base + 7 * sizeof(u32));
+       data2 = iwl_read_targ_mem(priv, base + 8 * sizeof(u32));
+       line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32));
+       time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32));
 
        IWL_ERROR("Desc               Time       "
                  "data1      data2      line\n");
@@ -4352,7 +4375,7 @@ static void iwl4965_dump_nic_error_log(struct iwl_priv *priv)
        IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2,
                  ilink1, ilink2);
 
-       iwl4965_release_nic_access(priv);
+       iwl_release_nic_access(priv);
 }
 
 #define EVENT_START_OFFSET  (4 * sizeof(u32))
@@ -4360,7 +4383,7 @@ static void iwl4965_dump_nic_error_log(struct iwl_priv *priv)
 /**
  * iwl4965_print_event_log - Dump error event log to syslog
  *
- * NOTE: Must be called with iwl4965_grab_nic_access() already obtained!
+ * NOTE: Must be called with iwl_grab_nic_access() already obtained!
  */
 static void iwl4965_print_event_log(struct iwl_priv *priv, u32 start_idx,
                                u32 num_events, u32 mode)
@@ -4386,14 +4409,14 @@ static void iwl4965_print_event_log(struct iwl_priv *priv, u32 start_idx,
        /* "time" is actually "data" for mode 0 (no timestamp).
         * place event id # at far right for easier visual parsing. */
        for (i = 0; i < num_events; i++) {
-               ev = iwl4965_read_targ_mem(priv, ptr);
+               ev = iwl_read_targ_mem(priv, ptr);
                ptr += sizeof(u32);
-               time = iwl4965_read_targ_mem(priv, ptr);
+               time = iwl_read_targ_mem(priv, ptr);
                ptr += sizeof(u32);
                if (mode == 0)
                        IWL_ERROR("0x%08x\t%04u\n", time, ev); /* data, ev */
                else {
-                       data = iwl4965_read_targ_mem(priv, ptr);
+                       data = iwl_read_targ_mem(priv, ptr);
                        ptr += sizeof(u32);
                        IWL_ERROR("%010u\t0x%08x\t%04u\n", time, data, ev);
                }
@@ -4416,24 +4439,24 @@ static void iwl4965_dump_nic_event_log(struct iwl_priv *priv)
                return;
        }
 
-       rc = iwl4965_grab_nic_access(priv);
+       rc = iwl_grab_nic_access(priv);
        if (rc) {
                IWL_WARNING("Can not read from adapter at this time.\n");
                return;
        }
 
        /* event log header */
-       capacity = iwl4965_read_targ_mem(priv, base);
-       mode = iwl4965_read_targ_mem(priv, base + (1 * sizeof(u32)));
-       num_wraps = iwl4965_read_targ_mem(priv, base + (2 * sizeof(u32)));
-       next_entry = iwl4965_read_targ_mem(priv, base + (3 * sizeof(u32)));
+       capacity = iwl_read_targ_mem(priv, base);
+       mode = iwl_read_targ_mem(priv, base + (1 * sizeof(u32)));
+       num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
+       next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
 
        size = num_wraps ? capacity : next_entry;
 
        /* bail out if nothing in log */
        if (size == 0) {
                IWL_ERROR("Start IWL Event Log Dump: nothing in log\n");
-               iwl4965_release_nic_access(priv);
+               iwl_release_nic_access(priv);
                return;
        }
 
@@ -4449,7 +4472,7 @@ static void iwl4965_dump_nic_event_log(struct iwl_priv *priv)
        /* (then/else) start at top of log */
        iwl4965_print_event_log(priv, 0, next_entry, mode);
 
-       iwl4965_release_nic_access(priv);
+       iwl_release_nic_access(priv);
 }
 
 /**
@@ -4521,19 +4544,19 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
        /* Ack/clear/reset pending uCode interrupts.
         * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
         *  and will clear only when CSR_FH_INT_STATUS gets cleared. */
-       inta = iwl4965_read32(priv, CSR_INT);
-       iwl4965_write32(priv, CSR_INT, inta);
+       inta = iwl_read32(priv, CSR_INT);
+       iwl_write32(priv, CSR_INT, inta);
 
        /* Ack/clear/reset pending flow-handler (DMA) interrupts.
         * Any new interrupts that happen after this, either while we're
         * in this tasklet, or later, will show up in next ISR/tasklet. */
-       inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS);
-       iwl4965_write32(priv, CSR_FH_INT_STATUS, inta_fh);
+       inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+       iwl_write32(priv, CSR_FH_INT_STATUS, inta_fh);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_debug_level & IWL_DL_ISR) {
                /* just for debug */
-               inta_mask = iwl4965_read32(priv, CSR_INT_MASK);
+               inta_mask = iwl_read32(priv, CSR_INT_MASK);
                IWL_DEBUG_ISR("inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
                              inta, inta_mask, inta_fh);
        }
@@ -4582,7 +4605,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
        /* HW RF KILL switch toggled */
        if (inta & CSR_INT_BIT_RF_KILL) {
                int hw_rf_kill = 0;
-               if (!(iwl4965_read32(priv, CSR_GP_CNTRL) &
+               if (!(iwl_read32(priv, CSR_GP_CNTRL) &
                                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
                        hw_rf_kill = 1;
 
@@ -4653,13 +4676,15 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
        }
 
        /* Re-enable all interrupts */
-       iwl4965_enable_interrupts(priv);
+       /* only Re-enable if diabled by irq */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status))
+               iwl4965_enable_interrupts(priv);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (iwl_debug_level & (IWL_DL_ISR)) {
-               inta = iwl4965_read32(priv, CSR_INT);
-               inta_mask = iwl4965_read32(priv, CSR_INT_MASK);
-               inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS);
+               inta = iwl_read32(priv, CSR_INT);
+               inta_mask = iwl_read32(priv, CSR_INT_MASK);
+               inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
                IWL_DEBUG_ISR("End inta 0x%08x, enabled 0x%08x, fh 0x%08x, "
                        "flags 0x%08lx\n", inta, inta_mask, inta_fh, flags);
        }
@@ -4681,12 +4706,12 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
         *    back-to-back ISRs and sporadic interrupts from our NIC.
         * If we have something to service, the tasklet will re-enable ints.
         * If we *don't* have something, we'll re-enable before leaving here. */
-       inta_mask = iwl4965_read32(priv, CSR_INT_MASK);  /* just for debug */
-       iwl4965_write32(priv, CSR_INT_MASK, 0x00000000);
+       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
 
        /* Discover which interrupts are active/pending */
-       inta = iwl4965_read32(priv, CSR_INT);
-       inta_fh = iwl4965_read32(priv, CSR_FH_INT_STATUS);
+       inta = iwl_read32(priv, CSR_INT);
+       inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
 
        /* Ignore interrupt if there's nothing in NIC to service.
         * This may be due to IRQ shared with another device,
@@ -4718,7 +4743,9 @@ static irqreturn_t iwl4965_isr(int irq, void *data)
 
  none:
        /* re-enable interrupts here since we don't have anything to service. */
-       iwl4965_enable_interrupts(priv);
+       /* only Re-enable if diabled by irq */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status))
+               iwl4965_enable_interrupts(priv);
        spin_unlock(&priv->lock);
        return IRQ_NONE;
 }
@@ -5001,8 +5028,12 @@ int iwl4965_init_geos(struct iwl_priv *priv)
               priv->bands[IEEE80211_BAND_2GHZ].n_channels,
               priv->bands[IEEE80211_BAND_5GHZ].n_channels);
 
-       priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->bands[IEEE80211_BAND_2GHZ];
-       priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ];
+       if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       &priv->bands[IEEE80211_BAND_2GHZ];
+       if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &priv->bands[IEEE80211_BAND_5GHZ];
 
        set_bit(STATUS_GEO_CONFIGURED, &priv->status);
 
@@ -5049,18 +5080,18 @@ static int iwl4965_verify_inst_full(struct iwl_priv *priv, __le32 *image,
 
        IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
 
-       rc = iwl4965_grab_nic_access(priv);
+       rc = iwl_grab_nic_access(priv);
        if (rc)
                return rc;
 
-       iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
+       iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, RTC_INST_LOWER_BOUND);
 
        errcnt = 0;
        for (; len > 0; len -= sizeof(u32), image++) {
                /* read data comes through single port, auto-incr addr */
                /* NOTE: Use the debugless read so we don't flood kernel log
                 * if IWL_DL_IO is set */
-               val = _iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+               val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image)) {
                        IWL_ERROR("uCode INST section is invalid at "
                                  "offset 0x%x, is 0x%x, s/b 0x%x\n",
@@ -5072,7 +5103,7 @@ static int iwl4965_verify_inst_full(struct iwl_priv *priv, __le32 *image,
                }
        }
 
-       iwl4965_release_nic_access(priv);
+       iwl_release_nic_access(priv);
 
        if (!errcnt)
                IWL_DEBUG_INFO
@@ -5096,7 +5127,7 @@ static int iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
 
        IWL_DEBUG_INFO("ucode inst image size is %u\n", len);
 
-       rc = iwl4965_grab_nic_access(priv);
+       rc = iwl_grab_nic_access(priv);
        if (rc)
                return rc;
 
@@ -5104,9 +5135,9 @@ static int iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
                /* read data comes through single port, auto-incr addr */
                /* NOTE: Use the debugless read so we don't flood kernel log
                 * if IWL_DL_IO is set */
-               iwl4965_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+               iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
                        i + RTC_INST_LOWER_BOUND);
-               val = _iwl4965_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+               val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image)) {
 #if 0 /* Enable this if you want to see details */
                        IWL_ERROR("uCode INST section is invalid at "
@@ -5120,7 +5151,7 @@ static int iwl4965_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32
                }
        }
 
-       iwl4965_release_nic_access(priv);
+       iwl_release_nic_access(priv);
 
        return rc;
 }
@@ -5187,11 +5218,11 @@ static int iwl4965_verify_bsm(struct iwl_priv *priv)
        IWL_DEBUG_INFO("Begin verify bsm\n");
 
        /* verify BSM SRAM contents */
-       val = iwl4965_read_prph(priv, BSM_WR_DWCOUNT_REG);
+       val = iwl_read_prph(priv, BSM_WR_DWCOUNT_REG);
        for (reg = BSM_SRAM_LOWER_BOUND;
             reg < BSM_SRAM_LOWER_BOUND + len;
             reg += sizeof(u32), image ++) {
-               val = iwl4965_read_prph(priv, reg);
+               val = iwl_read_prph(priv, reg);
                if (val != le32_to_cpu(*image)) {
                        IWL_ERROR("BSM uCode verification failed at "
                                  "addr 0x%08X+%u (of %u), is 0x%x, s/b 0x%x\n",
@@ -5268,42 +5299,42 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
        inst_len = priv->ucode_init.len;
        data_len = priv->ucode_init_data.len;
 
-       rc = iwl4965_grab_nic_access(priv);
+       rc = iwl_grab_nic_access(priv);
        if (rc)
                return rc;
 
-       iwl4965_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
-       iwl4965_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
-       iwl4965_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
-       iwl4965_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
+       iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+       iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+       iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, inst_len);
+       iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, data_len);
 
        /* Fill BSM memory with bootstrap instructions */
        for (reg_offset = BSM_SRAM_LOWER_BOUND;
             reg_offset < BSM_SRAM_LOWER_BOUND + len;
             reg_offset += sizeof(u32), image++)
-               _iwl4965_write_prph(priv, reg_offset,
+               _iwl_write_prph(priv, reg_offset,
                                          le32_to_cpu(*image));
 
        rc = iwl4965_verify_bsm(priv);
        if (rc) {
-               iwl4965_release_nic_access(priv);
+               iwl_release_nic_access(priv);
                return rc;
        }
 
        /* Tell BSM to copy from BSM SRAM into instruction SRAM, when asked */
-       iwl4965_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
-       iwl4965_write_prph(priv, BSM_WR_MEM_DST_REG,
+       iwl_write_prph(priv, BSM_WR_MEM_SRC_REG, 0x0);
+       iwl_write_prph(priv, BSM_WR_MEM_DST_REG,
                                 RTC_INST_LOWER_BOUND);
-       iwl4965_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
+       iwl_write_prph(priv, BSM_WR_DWCOUNT_REG, len / sizeof(u32));
 
        /* Load bootstrap code into instruction SRAM now,
         *   to prepare to load "initialize" uCode */
-       iwl4965_write_prph(priv, BSM_WR_CTRL_REG,
+       iwl_write_prph(priv, BSM_WR_CTRL_REG,
                BSM_WR_CTRL_REG_BIT_START);
 
        /* Wait for load of bootstrap uCode to finish */
        for (i = 0; i < 100; i++) {
-               done = iwl4965_read_prph(priv, BSM_WR_CTRL_REG);
+               done = iwl_read_prph(priv, BSM_WR_CTRL_REG);
                if (!(done & BSM_WR_CTRL_REG_BIT_START))
                        break;
                udelay(10);
@@ -5317,10 +5348,10 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
 
        /* Enable future boot loads whenever power management unit triggers it
         *   (e.g. when powering back up after power-save shutdown) */
-       iwl4965_write_prph(priv, BSM_WR_CTRL_REG,
+       iwl_write_prph(priv, BSM_WR_CTRL_REG,
                BSM_WR_CTRL_REG_BIT_START_EN);
 
-       iwl4965_release_nic_access(priv);
+       iwl_release_nic_access(priv);
 
        return 0;
 }
@@ -5328,7 +5359,7 @@ static int iwl4965_load_bsm(struct iwl_priv *priv)
 static void iwl4965_nic_start(struct iwl_priv *priv)
 {
        /* Remove all resets to allow NIC to operate */
-       iwl4965_write32(priv, CSR_RESET, 0);
+       iwl_write32(priv, CSR_RESET, 0);
 }
 
 
@@ -5550,24 +5581,24 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv)
        pdata = priv->ucode_data_backup.p_addr >> 4;
 
        spin_lock_irqsave(&priv->lock, flags);
-       rc = iwl4965_grab_nic_access(priv);
+       rc = iwl_grab_nic_access(priv);
        if (rc) {
                spin_unlock_irqrestore(&priv->lock, flags);
                return rc;
        }
 
        /* Tell bootstrap uCode where to find image to load */
-       iwl4965_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
-       iwl4965_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
-       iwl4965_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
+       iwl_write_prph(priv, BSM_DRAM_INST_PTR_REG, pinst);
+       iwl_write_prph(priv, BSM_DRAM_DATA_PTR_REG, pdata);
+       iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG,
                                 priv->ucode_data.len);
 
        /* Inst bytecount must be last to set up, bit 31 signals uCode
         *   that all new ptr/size info is in place */
-       iwl4965_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
+       iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG,
                                 priv->ucode_code.len | BSM_DRAM_INST_LOAD);
 
-       iwl4965_release_nic_access(priv);
+       iwl_release_nic_access(priv);
 
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -5701,16 +5732,19 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
 
        /* At this point, the NIC is initialized and operational */
        priv->notif_missed_beacons = 0;
-       set_bit(STATUS_READY, &priv->status);
 
        iwl4965_rf_kill_ct_config(priv);
 
        IWL_DEBUG_INFO("ALIVE processing complete.\n");
+       set_bit(STATUS_READY, &priv->status);
        wake_up_interruptible(&priv->wait_command_queue);
 
+       iwl_leds_register(priv);
+
        if (priv->error_recovering)
                iwl4965_error_recovery(priv);
 
+       iwlcore_low_level_notify(priv, IWLCORE_START_EVT);
        return;
 
  restart:
@@ -5732,6 +5766,10 @@ static void __iwl4965_down(struct iwl_priv *priv)
        if (!exit_pending)
                set_bit(STATUS_EXIT_PENDING, &priv->status);
 
+       iwl_leds_unregister(priv);
+
+       iwlcore_low_level_notify(priv, IWLCORE_STOP_EVT);
+
        iwlcore_clear_stations_table(priv);
 
        /* Unblock any waiting calls */
@@ -5743,10 +5781,13 @@ static void __iwl4965_down(struct iwl_priv *priv)
                clear_bit(STATUS_EXIT_PENDING, &priv->status);
 
        /* stop and reset the on-board processor */
-       iwl4965_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+       iwl_write32(priv, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
 
        /* tell the device to stop sending interrupts */
+       spin_lock_irqsave(&priv->lock, flags);
        iwl4965_disable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+       iwl_synchronize_irq(priv);
 
        if (priv->mac80211_registered)
                ieee80211_stop_queues(priv->hw);
@@ -5779,7 +5820,7 @@ static void __iwl4965_down(struct iwl_priv *priv)
                                STATUS_FW_ERROR;
 
        spin_lock_irqsave(&priv->lock, flags);
-       iwl4965_clear_bit(priv, CSR_GP_CNTRL,
+       iwl_clear_bit(priv, CSR_GP_CNTRL,
                         CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        spin_unlock_irqrestore(&priv->lock, flags);
 
@@ -5787,17 +5828,17 @@ static void __iwl4965_down(struct iwl_priv *priv)
        iwl4965_hw_rxq_stop(priv);
 
        spin_lock_irqsave(&priv->lock, flags);
-       if (!iwl4965_grab_nic_access(priv)) {
-               iwl4965_write_prph(priv, APMG_CLK_DIS_REG,
+       if (!iwl_grab_nic_access(priv)) {
+               iwl_write_prph(priv, APMG_CLK_DIS_REG,
                                         APMG_CLK_VAL_DMA_CLK_RQT);
-               iwl4965_release_nic_access(priv);
+               iwl_release_nic_access(priv);
        }
        spin_unlock_irqrestore(&priv->lock, flags);
 
        udelay(5);
 
        iwl4965_hw_nic_stop_master(priv);
-       iwl4965_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+       iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
        iwl4965_hw_nic_reset(priv);
 
  exit:
@@ -5834,6 +5875,7 @@ static int __iwl4965_up(struct iwl_priv *priv)
        if (test_bit(STATUS_RF_KILL_SW, &priv->status)) {
                IWL_WARNING("Radio disabled by SW RF kill (module "
                            "parameter)\n");
+               iwl_rfkill_set_hw_state(priv);
                return -ENODEV;
        }
 
@@ -5843,18 +5885,20 @@ static int __iwl4965_up(struct iwl_priv *priv)
        }
 
        /* If platform's RF_KILL switch is NOT set to KILL */
-       if (iwl4965_read32(priv, CSR_GP_CNTRL) &
+       if (iwl_read32(priv, CSR_GP_CNTRL) &
                                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
                clear_bit(STATUS_RF_KILL_HW, &priv->status);
        else {
                set_bit(STATUS_RF_KILL_HW, &priv->status);
                if (!test_bit(STATUS_IN_SUSPEND, &priv->status)) {
+                       iwl_rfkill_set_hw_state(priv);
                        IWL_WARNING("Radio disabled by HW RF Kill switch\n");
                        return -ENODEV;
                }
        }
 
-       iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
+       iwl_rfkill_set_hw_state(priv);
+       iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
 
        rc = iwl4965_hw_nic_init(priv);
        if (rc) {
@@ -5863,17 +5907,17 @@ static int __iwl4965_up(struct iwl_priv *priv)
        }
 
        /* make sure rfkill handshake bits are cleared */
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR,
+       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR,
                    CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
 
        /* clear (again), then enable host interrupts */
-       iwl4965_write32(priv, CSR_INT, 0xFFFFFFFF);
+       iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
        iwl4965_enable_interrupts(priv);
 
        /* really make sure rfkill handshake bits are cleared */
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl4965_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
        /* Copy original ucode data image from disk into backup cache.
         * This will be used to initialize the on-board processor's
@@ -5967,6 +6011,9 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
                if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
                        queue_work(priv->workqueue, &priv->restart);
        } else {
+               /* make sure mac80211 stop sending Tx frame */
+               if (priv->mac80211_registered)
+                       ieee80211_stop_queues(priv->hw);
 
                if (!test_bit(STATUS_RF_KILL_HW, &priv->status))
                        IWL_DEBUG_RF_KILL("Can not turn radio back on - "
@@ -5976,6 +6023,8 @@ static void iwl4965_bg_rf_kill(struct work_struct *work)
                                    "Kill switch must be turned off for "
                                    "wireless networking to work.\n");
        }
+       iwl_rfkill_set_hw_state(priv);
+
        mutex_unlock(&priv->mutex);
 }
 
@@ -6656,7 +6705,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co
        }
 #endif
 
-       iwl4965_radio_kill_sw(priv, !conf->radio_enabled);
+       if (priv->cfg->ops->lib->radio_kill_sw)
+               priv->cfg->ops->lib->radio_kill_sw(priv, !conf->radio_enabled);
 
        if (!conf->radio_enabled) {
                IWL_DEBUG_MAC80211("leave - radio disabled\n");
@@ -7431,36 +7481,6 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,
 
 #endif /* CONFIG_IWLWIFI_DEBUG */
 
-static ssize_t show_rf_kill(struct device *d,
-                           struct device_attribute *attr, char *buf)
-{
-       /*
-        * 0 - RF kill not enabled
-        * 1 - SW based RF kill active (sysfs)
-        * 2 - HW based RF kill active
-        * 3 - Both HW and SW based RF kill active
-        */
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-       int val = (test_bit(STATUS_RF_KILL_SW, &priv->status) ? 0x1 : 0x0) |
-                 (test_bit(STATUS_RF_KILL_HW, &priv->status) ? 0x2 : 0x0);
-
-       return sprintf(buf, "%i\n", val);
-}
-
-static ssize_t store_rf_kill(struct device *d,
-                            struct device_attribute *attr,
-                            const char *buf, size_t count)
-{
-       struct iwl_priv *priv = (struct iwl_priv *)d->driver_data;
-
-       mutex_lock(&priv->mutex);
-       iwl4965_radio_kill_sw(priv, buf[0] == '1');
-       mutex_unlock(&priv->mutex);
-
-       return count;
-}
-
-static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill);
 
 static ssize_t show_temperature(struct device *d,
                                struct device_attribute *attr, char *buf)
@@ -7946,7 +7966,6 @@ static struct attribute *iwl4965_sysfs_entries[] = {
 #endif
        &dev_attr_power_level.attr,
        &dev_attr_retry_rate.attr,
-       &dev_attr_rf_kill.attr,
        &dev_attr_rs_window.attr,
        &dev_attr_statistics.attr,
        &dev_attr_status.attr,
@@ -7992,6 +8011,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        struct iwl_priv *priv;
        struct ieee80211_hw *hw;
        struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
+       unsigned long flags;
        DECLARE_MAC_BUF(mac);
 
        /************************
@@ -8073,11 +8093,11 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
         * 4. Read EEPROM
         *****************/
        /* nic init */
-       iwl4965_set_bit(priv, CSR_GIO_CHICKEN_BITS,
+       iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS,
                CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
 
-       iwl4965_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
-       err = iwl4965_poll_bit(priv, CSR_GP_CNTRL,
+       iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
+       err = iwl_poll_bit(priv, CSR_GP_CNTRL,
                CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
                CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
        if (err < 0) {
@@ -8129,7 +8149,9 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /********************
         * 8. Setup services
         ********************/
+       spin_lock_irqsave(&priv->lock, flags);
        iwl4965_disable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group);
        if (err) {
@@ -8152,6 +8174,8 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        pci_save_state(pdev);
        pci_disable_device(pdev);
 
+       /* notify iwlcore to init */
+       iwlcore_low_level_notify(priv, IWLCORE_INIT_EVT);
        return 0;
 
  out_remove_sysfs:
@@ -8171,11 +8195,12 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        return err;
 }
 
-static void iwl4965_pci_remove(struct pci_dev *pdev)
+static void __devexit iwl4965_pci_remove(struct pci_dev *pdev)
 {
        struct iwl_priv *priv = pci_get_drvdata(pdev);
        struct list_head *p, *q;
        int i;
+       unsigned long flags;
 
        if (!priv)
                return;
@@ -8186,6 +8211,15 @@ static void iwl4965_pci_remove(struct pci_dev *pdev)
 
        iwl4965_down(priv);
 
+       /* make sure we flush any pending irq or
+        * tasklet for the driver
+        */
+       spin_lock_irqsave(&priv->lock, flags);
+       iwl4965_disable_interrupts(priv);
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       iwl_synchronize_irq(priv);
+
        /* Free MAC hash list for ADHOC */
        for (i = 0; i < IWL_IBSS_MAC_HASH_SIZE; i++) {
                list_for_each_safe(p, q, &priv->ibss_mac_hash[i]) {
@@ -8194,6 +8228,7 @@ static void iwl4965_pci_remove(struct pci_dev *pdev)
                }
        }
 
+       iwlcore_low_level_notify(priv, IWLCORE_REMOVE_EVT);
        iwl_dbgfs_unregister(priv);
        sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group);
 
@@ -8208,7 +8243,6 @@ static void iwl4965_pci_remove(struct pci_dev *pdev)
 
        if (priv->mac80211_registered) {
                ieee80211_unregister_hw(priv->hw);
-               iwl4965_rate_control_unregister(priv->hw);
        }
 
        /*netif_stop_queue(dev); */
@@ -8289,21 +8323,35 @@ static int __init iwl4965_init(void)
        int ret;
        printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
        printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
+
+       ret = iwl4965_rate_control_register();
+       if (ret) {
+               IWL_ERROR("Unable to register rate control algorithm: %d\n", ret);
+               return ret;
+       }
+
        ret = pci_register_driver(&iwl4965_driver);
        if (ret) {
                IWL_ERROR("Unable to initialize PCI module\n");
-               return ret;
+               goto error_register;
        }
 #ifdef CONFIG_IWLWIFI_DEBUG
        ret = driver_create_file(&iwl4965_driver.driver, &driver_attr_debug_level);
        if (ret) {
                IWL_ERROR("Unable to create driver sysfs file\n");
-               pci_unregister_driver(&iwl4965_driver);
-               return ret;
+               goto error_debug;
        }
 #endif
 
        return ret;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+error_debug:
+       pci_unregister_driver(&iwl4965_driver);
+#endif
+error_register:
+       iwl4965_rate_control_unregister();
+       return ret;
 }
 
 static void __exit iwl4965_exit(void)
@@ -8312,6 +8360,7 @@ static void __exit iwl4965_exit(void)
        driver_remove_file(&iwl4965_driver.driver, &driver_attr_debug_level);
 #endif
        pci_unregister_driver(&iwl4965_driver);
+       iwl4965_rate_control_unregister();
 }
 
 module_exit(iwl4965_exit);